#include "ExampleAIModule.h"

using namespace BWAPI;

struct vect2d {
  int x;
  int y;
};

struct twopointlink {
  vect2d point1;
  vect2d point2;
};

bool analyzed,bnarrow,bfluidfilldone,bhighreslinksfound,bjustfinished,bletsgoagain,bgotitagain,bchecked;
int  mapwidth,mapheight;
bool nodebool[1024][1024],fluidedgechecked[1050000], nonwalk2[1024][1024], checked[1024][1024];

vect2d fluidzonepoints[1050000],fluidzoneedge[1050000];

int fluidzoneedgeindexes[1050000],fluidzoneindexes[1050000],zonelinkindexindex[1050000],zonelinkindex[1050000],fluidzoneareas[1050000];
vect2d links[30000000],linksinner[30000000],lastpoint,lastdir,firstdir,firstpoint,currdir,innerdir;

int nnumb,zonen,lastn,lastn2,zliid,firstlink,zliiid,currlink,lastarea,lastedge,lastx,scanx,scany,npointcheck,lasty,zoneid,longestcheckedbegin,longestcheckedend,currcheckedbegin,currcheckedend;
bool walk[1024][1024];
bool build[256][256],banalizis_finished,blinkunification_finished,bfirstpointselected;

BWAPI::Player *self;

/////////////////////////////////////////////

bool doCheck(int x, int y);
void setNodeBool(int x, int y);

// isWalkPtValid: returns true if the point is a valid walk coordinate
bool isWalkPtValid(int x, int y);

// walk: returns the value of walk[x][y] with bounds checking
bool walk(int x, int y);

// nonwalk2: returns the value of nonwalk2[x][y] with bounds checking
bool nonwalk2(int x, int y);

// nodebool: returns the value of nodebool[x][y] with bounds checking
bool nodebool(int x, int y);

// isNarrow: checks if space is narrow
bool isNarrow(int x, int y);

/////////////////////////////////////////////

void ExampleAIModule::onStart()
{
  self = Broodwar->self();

  mapwidth  = Broodwar->mapWidth();
  mapheight = Broodwar->mapHeight();

  nnumb       = -1;
  lastn       = -1;
  zliid       = 0;
  zliiid      = 0;
  currlink    = 0;
  scanx       = 0;
  lastpoint.x = 9000;
  lastpoint.y = 9000;
  scany       = 0;
  npointcheck = 0;
  lastarea    = 0;
  lastx       = 0;
  lasty       = 0;
  
  Broodwar->sendText("Hello world!");
  Broodwar->printf("The map is %s, a %d player map", Broodwar->mapName().c_str(), Broodwar->getStartLocations().size());
  // Enable some cheat flags
  Broodwar->enableFlag(Flag::UserInput);
  // Uncomment to enable complete map information
  //Broodwar->enableFlag(Flag::CompleteMapInformation);

  // make buildability local
  for (int c1 = 0; c1 < mapwidth; ++c1)
    for (int c2 = 0; c2 < mapheight; ++c2)
      build[c1][c2] = Broodwar->isBuildable(c1, c2);
  
  mapwidth  *=  4;
  mapheight *=  4;

  // make walkability local
  for (int c1 = 0; c1 < mapwidth; ++c1)
    for (int c2 = 0; c2 < mapheight; ++c2)
      walk[c1][c2] = Broodwar->isWalkable(c1,c2);
  
  if ( !Broodwar->isReplay() )
  {
    //send each worker to the mineral field that is closest to it
    for ( std::set<Unit*>::const_iterator i = self->getUnits().begin(), iend = self->getUnits().end(); i != iend; ++i )
    {
      if ( (*i)->getType().isWorker() )
      {
        Unit *closestMineral  = NULL;
        int bestDist          = 999999;
        for ( std::set<Unit*>::iterator m = Broodwar->getMinerals().begin(), mend = Broodwar->getMinerals().end(); m != mend; ++m )
        {
          int newDist = (*i)->getDistance(*m);
          if ( !closestMineral || newDist < bestDist )
          {
            bestDist = newDist
            closestMineral = *m;
          }
        }
        if ( closestMineral )
          (*i)->rightClick(closestMineral);
      }
      else if ( (*i)->getType().isResourceDepot() )
      {
        //if this is a center, tell it to build the appropiate type of worker
        (*i)->train( self->getRace().getWorker() );
      }
    } // for each self units
  } // if not a replay
}

void ExampleAIModule::onEnd(bool isWinner) {}


bool doNarrowDirectionCheck(int x, int y)
{
  if ( walk(x, y) && 
       !nodebool[x][y] )
  {
    nodebool[x][y] = true;
    return true;
  }
  return false;
}

void setNodeBool(int x, int y)
{
  if ( !isWalkPtValid(x,y) )
    return;
  if ( !nodebool[x][y] )
  {
    nodebool[x][y] = true;
    if ( bnarrow )
      nonwalk2[x][y] = true;
    nnumb++;
    lastarea++;
    fluidzonepoints[nnumb].x = x;
    fluidzonepoints[nnumb].y = y;
  }
}

bool isWalkPtValid(int x, int y)
{
  return x >= 0 && x < mapwidth &&
         y >= 0 && y < mapheight;
}

bool nonwalk2(int x, int y)
{
  if ( !isWalkPtValid(x,y) )
    return false;
  return nonwalk2[x][y];
}

bool walk(int x, int y)
{
  if ( !isWalkPtValid(x,y) )
    return false;
  return walk[x][y];
}

bool isNarrow(int x, int y)
{
  return ( !walk(x+1, y) && !walk(x-1, y) ) ||
         ( !walk(x, y+1) && !walk(x, y-1) );
}

bool doCheck(int x, int y)
{
  bool check = false;
  if ( !walk(x, y) )
    return true;

  if ( !checked[x][y] )
  {
    check = bnarrow ^ isNarrow(x, y);

    if ( !check )
      setNodeBool(x,y);
  }
  return check;
}

bool nodebool(int x, int y)
{
  if ( !isWalkPtValid(x,y) )
    return false;
  return nodebool[x][y];
}

void ExampleAIModule::onFrame()
{
  int nsteps,c1,c2,c3,nlinkfound,sumcoord;
  vect2d innercoords[4],prevdir,rootnodes[2],currdir,innerside,tempcoord[4],tempcoord2[4];
  bool currenttilewalkable,edgefound,linkfound,blinkfound;

  if ( Broodwar->isReplay() )
    return;
  
  //do some operations from terrain analyzation
  if ( !analyzed )
  {
    //fluidfill to find the edges
    for ( nsteps = 0; scany < mapheight && nsteps < 10000; nsteps++ )
    {
      edgefound = false;
      //do we have things to continue?
      if (nnumb == lastn)
      {
        lastx = scanx;
        lasty = scany;
        if ( scanx == mapwidth - 1 )
        {
          scanx = 0;
          scany++;
        }
        else
        {
          scanx++;
        }
        lastarea = 0;
        bfirstpointselected = true;
      }
      else
      {
        //yes, so lets continuew it
        lastn++;
        lastx = fluidzonepoints[lastn].x;
        lasty = fluidzonepoints[lastn].y;
      }
      
      //if we hadn't then we check if scanned tile is walkable, and not checked [otherwise irrelevant..]
      if ( walk(lastx, lasty) && !checked[lastx][lasty] )
      {
        if ( bfirstpointselected )
        {
          bnarrow = isNarrow(lastx, lasty);
          if ( bnarrow )
            nonwalk2[lastx][lasty] = true;

          bfirstpointselected = false;
        }
        if ( lastn == nnumb )
        {
          nnumb++;
          lastn++;
          fluidzonepoints[lastn].x = lastx;
          fluidzonepoints[lastn].y = lasty;
          lastarea++;
        }
      
        //check it
        //right
        if (  doCheck(lastx+1, lasty) ||  // right
              doCheck(lastx-1, lasty) ||  // left
              doCheck(lastx, lasty+1) ||  // down
              doCheck(lastx, lasty-1)  )  // up
          edgefound = true;

        //addedge;
        if (edgefound)
        {
          fluidzoneedge[lastedge].x = lastx;
          fluidzoneedge[lastedge].y = lasty;
          
          lastedge++;
        }
        //area done?
        if ( lastn == nnumb )
        {
          fluidzoneareas[zonen] = lastarea;
          lastarea = 0;
          zonen++;
          fluidzoneedgeindexes[zonen] = lastedge;
          fluidzoneindexes[zonen] = nnumb+1;
        }
      
      }
      checked[lastx][lasty] = true;
    }
    if ( scany >= mapheight && !bfluidfilldone )
    {
      bfluidfilldone  = true;
      bjustfinished   = true;
    }
    
    if ( bjustfinished )
    {
      bjustfinished = false;
      memset(nodebool, 0, sizeof(nodebool));
      lastn = 0;
    }
    
////////////////////////////////////////////////////////////
    //draw stuff
    if ( bfluidfilldone )
    {
      //Broodwar->printf("numberofzones: %d" , zonen);
      for ( c1 = 0; c1 < mapwidth; c1++)
        for ( c2 = 0; c2 < mapheight; c2++)
          Broodwar->drawBoxMap(c1*8, c2*8, c1*8+8, c2*8+8, walk(c1, c2) ? Colors::Purple : Colors::Blue);
      
      for ( c1 = 0; c1 < fluidzoneedgeindexes[zonen]; c1++)
          Broodwar->drawBoxMap(fluidzoneedge[c1].x*8, fluidzoneedge[c1].y*8, fluidzoneedge[c1].x*8+8, fluidzoneedge[c1].y*8+8, Colors::Red);
    }
    
    //FIND HIGHRES POLYGONS
    nsteps = 0;
    while ( bfluidfilldone && !bhighreslinksfound && nsteps < 3000 && zliid < zonen )
    {
      //check edge points
      //Broodwar->printf("zliid, zonen %d %d" , zliid, zonen);
      while ( nsteps < 3000 && npointcheck < fluidzoneedgeindexes[zliid+1] - fluidzoneedgeindexes[zliid] )
      { //ONLYINCREMENT NPOINTCHECK, IF THE THING IS NOT ALREADY CHECKED
        //if we have no initial point, pick one
        nsteps++;
        if ( lastpoint.x == 9000 )
        {
          //see if we are a narrow, or a normal zone
          c1        = fluidzoneedgeindexes[zliid];
          lastpoint = fluidzoneedge[c1];
          bnarrow   = nonwalk2[lastpoint.x][lastpoint.y];

          //pick first nonchecked
          for ( c1++; c1 < fluidzoneedgeindexes[zliid+1]-1; c1++ )
          {
            //if narrow zone, we might have a non ciruclar zone, so it will only stop, when all the number
            //of edges are checked, so only stop picking if we run out of points or find one of the end points if linear zone
            if ( bnarrow )
            {
              sumcoord = 0;
              lastx = fluidzoneedge[c1].x;
              lasty = fluidzoneedge[c1].y;
              
              if ( !walk(lastx+1, lasty) )
                sumcoord++;
              if ( !walk(lastx-1, lasty) )
                sumcoord++;
              if ( !walk(lastx, lasty-1) )
                sumcoord++;
              if ( !walk(lastx, lasty+1) )
                sumcoord++;

              //if we have more then three points then one is an endpoint
              if ( sumcoord >= 3 && !nodebool[lastx][lasty] )
              {
                lastpoint = fluidzoneedge[c1];
                break;
              }
              else if ( !nodebool[lastx][lasty] )
              {
                lastpoint = fluidzoneedge[c1];
              }
              
            } // if bnarrow
            else
            {
              if ( !nodebool[fluidzoneedge[c1].x][fluidzoneedge[c1].y] )
              {
                lastpoint = fluidzoneedge[c1];
                break;
              }
            } // if !bnarrow
          } // for loop

          
          if (  !walk(lastpoint.x+1, lastpoint.y) && 
                 walk(lastpoint.x-1, lastpoint.y)  )
          {
            linksinner[currlink].x = lastpoint.x-1;
            linksinner[currlink].y = lastpoint.y;
          }
          else if (  !walk(lastpoint.x-1, lastpoint.y) && 
                      walk(lastpoint.x+1, lastpoint.y)  )
          {
            linksinner[currlink].x = lastpoint.x+1;
            linksinner[currlink].y = lastpoint.y;
          }
          else if (  !walk(lastpoint.x, lastpoint.y-1) && 
                      walk(lastpoint.x, lastpoint.y+1)  )
          {
            linksinner[currlink].x = lastpoint.x;
            linksinner[currlink].y = lastpoint.y+1;
          }
          else if (  !walk(lastpoint.x, lastpoint.y+1) && 
                      walk(lastpoint.x, lastpoint.y-1)  )
          {
            linksinner[currlink].x = lastpoint.x;
            linksinner[currlink].y = lastpoint.y-1;
          }
          firstpoint  = lastpoint;
          firstlink   = currlink;
          zonelinkindexindex[zliiid] = firstlink;
          lastdir.x = 0;
          lastdir.y = 0;
          zliiid++;

          links[currlink] = lastpoint;

          currlink++;
          npointcheck++;

          nodebool[lastpoint.x][lastpoint.y] = true;

          //pick a nearby point for link: THEY ARE GOING TO PICK THE ONE CLOSEST BENDING TOWARDS INNER POINT
          
          //right
          
        }
        //start comparing stuff to inital/last point
        
        while ( nsteps < 3000 && npointcheck < fluidzoneedgeindexes[zliid+1] - fluidzoneedgeindexes[zliid] )
        {
          blinkfound = false;
          //pick a suitable point for next link
          
          nsteps++;
          sumcoord = 0;
          
          //FIXMEEEE : we need an array, it will hold candidates for adding as links, then if we have more then 1 candidate, we will check those
          //which are part of the zone and the closest will remain.
          
          if ( bnarrow )
          {
            blinkfound = true;
            //left
            if ( doNarrowDirectionCheck(lastpoint.x-1, lastpoint.y) )
            {
              currdir.x = -1;
              currdir.y = 0;
            }
            //right
            else if ( doNarrowDirectionCheck(lastpoint.x+1, lastpoint.y) )
            {
              currdir.x = 1;
              currdir.y = 0;
            }
            //down
            else if ( doNarrowDirectionCheck(lastpoint.x, lastpoint.y+1) )
            {
              currdir.x = 0;
              currdir.y = 1;
            }
            //up
            else if ( doNarrowDirectionCheck(lastpoint.x, lastpoint.y-1) )
            {
              currdir.x = 0;
              currdir.y = -1;
            }
            //upleft
            else if ( doNarrowDirectionCheck(lastpoint.x-1, lastpoint.y-1) )
            {
              currdir.x = -1;
              currdir.y = -1;
            }
            //upright
            else if ( doNarrowDirectionCheck(lastpoint.x+1, lastpoint.y-1) )
            {
              currdir.x = 1;
              currdir.y = -1;
            }
            //downright
            else if ( doNarrowDirectionCheck(lastpoint.x+1, lastpoint.y+1) )
            {
              currdir.x = 1;
              currdir.y = 1;
            }
            //downleft
            else if ( doNarrowDirectionCheck(lastpoint.x-1, lastpoint.y+1) )
            {
              currdir.x = -1;
              currdir.y = 1;
            }
            else
            {
              blinkfound = false;
            }
          }
          else // if !bnarrow
          {
            //left
            if ( walk(lastpoint.x-1, lastpoint.y) && !nonwalk2[lastpoint.x-1][lastpoint.y] && lastdir.x != 1 && lastpoint.x != 0 && !nodebool[lastpoint.x-1][lastpoint.y] && (lastpoint.x-1 != firstpoint.x || lastpoint.y != firstpoint.y) && 
              (((!walk(lastpoint.x-1, lastpoint.y-1) || nonwalk2[lastpoint.x-1][lastpoint.y-1] || lastpoint.y == 0) && (lastdir.y != 0 || !walk(lastpoint.x+1, lastpoint.y-1) || nonwalk2[lastpoint.x+1][lastpoint.y-1] || lastpoint.y == 0)) ||
               ((!walk(lastpoint.x-1, lastpoint.y+1) || nonwalk2[lastpoint.x-1][lastpoint.y+1] || lastpoint.y == mapheight-1) && (lastdir.y != 0 || !walk(lastpoint.x+1, lastpoint.y+1) || nonwalk2[lastpoint.x+1][lastpoint.y+1] || lastpoint.y == mapheight-1)) ))
            {
              blinkfound = true;
              tempcoord[sumcoord].x = lastpoint.x-1;
              tempcoord[sumcoord].y = lastpoint.y;
              
              //which side was inner?
              if ( !walk(lastpoint.x-1, lastpoint.y-1) || nonwalk2[lastpoint.x-1][lastpoint.y-1] || lastpoint.y == 0 )
              {
                tempcoord2[sumcoord].x = lastpoint.x-1;
                tempcoord2[sumcoord].y = lastpoint.y+1;
              }
              else 
              {
                tempcoord2[sumcoord].x = lastpoint.x-1;
                tempcoord2[sumcoord].y = lastpoint.y-1;
              }
              sumcoord++;
            }
          //right
            if ( walk(lastpoint.x+1, lastpoint.y) && !nonwalk2[lastpoint.x+1][lastpoint.y] && lastdir.x != -1 && lastpoint.x != mapwidth-1 && !nodebool[lastpoint.x+1][lastpoint.y] && (lastpoint.x+1 != firstpoint.x || lastpoint.y != firstpoint.y) && 
              (((lastdir.y != 0 || !walk(lastpoint.x-1, lastpoint.y-1)|| nonwalk2[lastpoint.x-1][lastpoint.y-1] || lastpoint.y == 0) && (!walk(lastpoint.x+1, lastpoint.y-1) || nonwalk2[lastpoint.x+1][lastpoint.y-1] || lastpoint.y == 0)) ||
               ((lastdir.y != 0 || !walk(lastpoint.x-1, lastpoint.y+1) || nonwalk2[lastpoint.x-1][lastpoint.y+1] || lastpoint.y == mapheight-1) && (!walk(lastpoint.x+1, lastpoint.y+1) || nonwalk2[lastpoint.x+1][lastpoint.y+1] || lastpoint.y == mapheight-1))) )
            {
              blinkfound = true;
              tempcoord[sumcoord].x = lastpoint.x+1;
              tempcoord[sumcoord].y = lastpoint.y;
              //which side was inner?
              if ( !walk(lastpoint.x+1, lastpoint.y-1) || nonwalk2[lastpoint.x+1][lastpoint.y-1] || lastpoint.y == 0 )
              {
                tempcoord2[sumcoord].x = lastpoint.x+1;
                tempcoord2[sumcoord].y = lastpoint.y+1;
              }
              else {
                tempcoord2[sumcoord].x = lastpoint.x+1;
                tempcoord2[sumcoord].y = lastpoint.y-1;
              }
              sumcoord++;
            }
            //down
            if (walk(lastpoint.x, lastpoint.y+1) && !nonwalk2[lastpoint.x][lastpoint.y+1] && lastdir.y !=-1 && lastpoint.y != mapheight-1 && !nodebool[lastpoint.x][lastpoint.y+1] && (lastpoint.x!= firstpoint.x || lastpoint.y+1 != firstpoint.y) && 
              (((!walk(lastpoint.x-1, lastpoint.y+1) || nonwalk2[lastpoint.x-1][lastpoint.y+1] || lastpoint.x == 0) && (lastdir.x != 0 || !walk(lastpoint.x-1, lastpoint.y-1) || nonwalk2[lastpoint.x-1][lastpoint.y-1] || lastpoint.x == 0)) ||
               ((!walk(lastpoint.x+1, lastpoint.y+1) || nonwalk2[lastpoint.x+1][lastpoint.y+1] || lastpoint.x == mapwidth-1) && (lastdir.x != 0 || !walk(lastpoint.x+1, lastpoint.y-1) || nonwalk2[lastpoint.x+1][lastpoint.y-1] || lastpoint.x == mapwidth-1)) ))
            {
              blinkfound = true;
              tempcoord[sumcoord].x = lastpoint.x;
              tempcoord[sumcoord].y = lastpoint.y+1;
              //which side was inner?
              if ( !walk(lastpoint.x-1, lastpoint.y+1) || nonwalk2[lastpoint.x-1][lastpoint.y+1] || lastpoint.x == 0 ) 
              {
                tempcoord2[sumcoord].x = lastpoint.x+1;
                tempcoord2[sumcoord].y = lastpoint.y+1;
              }
              else {
                tempcoord2[sumcoord].x = lastpoint.x-1;
                tempcoord2[sumcoord].y = lastpoint.y+1;
              }
              sumcoord++;
            }
            //up
            if (walk(lastpoint.x, lastpoint.y-1) && !nonwalk2[lastpoint.x][lastpoint.y-1] && lastdir.y != 1 && lastpoint.y != 0 && !nodebool[lastpoint.x][lastpoint.y-1] && (lastpoint.x!= firstpoint.x || lastpoint.y-1 != firstpoint.y) && 
              (((lastdir.x != 0 || !walk(lastpoint.x-1, lastpoint.y+1) || nonwalk2[lastpoint.x-1][lastpoint.y+1] || lastpoint.x == 0) && (!walk(lastpoint.x-1, lastpoint.y-1) || nonwalk2[lastpoint.x-1][lastpoint.y-1] || lastpoint.x == 0)) ||
               ((lastdir.x != 0 || !walk(lastpoint.x+1, lastpoint.y+1) || nonwalk2[lastpoint.x+1][lastpoint.y+1] || lastpoint.x == mapwidth-1) && (!walk(lastpoint.x+1, lastpoint.y-1) || nonwalk2[lastpoint.x+1][lastpoint.y-1] || lastpoint.x == mapwidth-1)) ))
            {
              blinkfound = true;
              tempcoord[sumcoord].x = lastpoint.x;
              tempcoord[sumcoord].y = lastpoint.y-1;
              currdir.y = -1;
              //which side was inner?
              if ((!walk(lastpoint.x-1, lastpoint.y-1) || nonwalk2[lastpoint.x-1][lastpoint.y-1] || lastpoint.x == 0))
              {
                tempcoord2[sumcoord].x = lastpoint.x+1;
                tempcoord2[sumcoord].y = lastpoint.y-1;
              }
              else
              {
                tempcoord2[sumcoord].x = lastpoint.x-1;
                tempcoord2[sumcoord].y = lastpoint.y-1;
              }
              sumcoord++;
            }
            
            //upleft
            if (walk(lastpoint.x-1, lastpoint.y-1) && !nonwalk2[lastpoint.x-1][lastpoint.y-1] && ((lastdir.x!=1 && lastdir.y!=1) || (lastdir.x != 0 && lastdir.y != 0)) && lastpoint.x != 0 && lastpoint.y != 0 && !nodebool[lastpoint.x-1][lastpoint.y-1] && (lastpoint.x-1 != firstpoint.x || lastpoint.y-1 != firstpoint.y) && 
              ((!walk(lastpoint.x, lastpoint.y-1) || nonwalk2[lastpoint.x][lastpoint.y-1]) || (!walk(lastpoint.x-1, lastpoint.y) || nonwalk2[lastpoint.x-1][lastpoint.y])) )
            {
              blinkfound = true;
              tempcoord[sumcoord].x = lastpoint.x-1;
              tempcoord[sumcoord].y = lastpoint.y-1;
              //which side was inner?
              if ( !walk(lastpoint.x, lastpoint.y-1) || nonwalk2[lastpoint.x][lastpoint.y-1] )
              {
                tempcoord2[sumcoord].x = lastpoint.x-1;
                tempcoord2[sumcoord].y = lastpoint.y;
              }
              else 
              {
                tempcoord2[sumcoord].x = lastpoint.x;
                tempcoord2[sumcoord].y = lastpoint.y-1;
              }
              sumcoord++;
            }
            //upright
            if (walk(lastpoint.x+1, lastpoint.y-1) && !nonwalk2[lastpoint.x+1][lastpoint.y-1] && ((lastdir.x != -1 && lastdir.y!=1) || (lastdir.x != 0 && lastdir.y != 0)) && lastpoint.x != mapwidth-1 && lastpoint.y != 0 && !nodebool[lastpoint.x+1][lastpoint.y-1] && (lastpoint.x+1 != firstpoint.x || lastpoint.y-1 != firstpoint.y) && 
              ((!walk(lastpoint.x, lastpoint.y-1) || nonwalk2[lastpoint.x][lastpoint.y-1]) || (!walk(lastpoint.x+1, lastpoint.y) || nonwalk2[lastpoint.x+1][lastpoint.y])) )
            {
              blinkfound = true;
              tempcoord[sumcoord].x = lastpoint.x+1;
              tempcoord[sumcoord].y = lastpoint.y-1;
              //which side was inner?
              if ( !walk(lastpoint.x, lastpoint.y-1) || nonwalk2[lastpoint.x][lastpoint.y-1] )
              {
                tempcoord2[sumcoord].x = lastpoint.x+1;
                tempcoord2[sumcoord].y = lastpoint.y;
              }
              else
              {
                tempcoord2[sumcoord].x = lastpoint.x;
                tempcoord2[sumcoord].y = lastpoint.y-1;
              }
              sumcoord++;
            }
            //downright
            if (walk(lastpoint.x+1, lastpoint.y+1) && !nonwalk2[lastpoint.x+1][lastpoint.y+1] && ((lastdir.x != -1 && lastdir.y!=-1) || (lastdir.x != 0 && lastdir.y != 0)) && lastpoint.x != mapwidth-1 && lastpoint.y != mapheight-1 && !nodebool[lastpoint.x+1][lastpoint.y+1] && (lastpoint.x+1 != firstpoint.x || lastpoint.y+1 != firstpoint.y) && 
              ((!walk(lastpoint.x, lastpoint.y+1) || nonwalk2[lastpoint.x][lastpoint.y+1]) || (!walk(lastpoint.x+1, lastpoint.y) || nonwalk2[lastpoint.x+1][lastpoint.y])) )
            {
              blinkfound = true;
              tempcoord[sumcoord].x = lastpoint.x+1;
              tempcoord[sumcoord].y = lastpoint.y+1;
              //which side was inner?
              if ( !walk(lastpoint.x, lastpoint.y+1) || nonwalk2[lastpoint.x][lastpoint.y+1] )
              {
                tempcoord2[sumcoord].x = lastpoint.x+1;
                tempcoord2[sumcoord].y = lastpoint.y;
              }
              else 
              {
                tempcoord2[sumcoord].x = lastpoint.x;
                tempcoord2[sumcoord].y = lastpoint.y+1;
              }
              sumcoord++;
            }
            //downleft
            if (  walk(lastpoint.x-1, lastpoint.y+1) && 
                  !nonwalk2[lastpoint.x-1][lastpoint.y+1] && 
                  ((lastdir.x!=1 && lastdir.y!=-1) || (lastdir.x != 0 && lastdir.y != 0)) && 
                  lastpoint.x != 0 && 
                  lastpoint.y != mapheight-1 && 
                  !nodebool[lastpoint.x-1][lastpoint.y+1] && 
                  (lastpoint.x-1 != firstpoint.x || lastpoint.y+1 != firstpoint.y) && 
                  ((!walk(lastpoint.x, lastpoint.y+1) || nonwalk2[lastpoint.x][lastpoint.y+1]) || (!walk(lastpoint.x-1, lastpoint.y) || nonwalk2[lastpoint.x-1][lastpoint.y])) )
            {
              blinkfound = true;
              tempcoord[sumcoord].x = lastpoint.x-1;
              tempcoord[sumcoord].y = lastpoint.y+1;
              //which side was inner?
              if ( !walk(lastpoint.x, lastpoint.y+1) || nonwalk2[lastpoint.x][lastpoint.y+1] )
              {
                tempcoord2[sumcoord].x = lastpoint.x-1;
                tempcoord2[sumcoord].y = lastpoint.y;
              }
              else 
              {
                tempcoord2[sumcoord].x = lastpoint.x;
                tempcoord2[sumcoord].y = lastpoint.y+1;
              }
              sumcoord++;
            }
            
            
            //IF THERE ARE MORE CANDIDATES FIND THE ONE WICH IS PRESENT IN THE LIST OF THE CURRENT ZONE EDGES.
            if ( sumcoord == 1 ) 
            {
              nodebool[tempcoord[0].x][tempcoord[0].y] = true;
              currdir.x = tempcoord[0].x - lastpoint.x;
              currdir.y = tempcoord[0].y - lastpoint.y;
              linksinner[currlink].x = tempcoord2[0].x;
              linksinner[currlink].y = tempcoord2[0].y;
            }
            else if ( sumcoord > 1 )
            {
              for ( c1 = 0; c1 < sumcoord; c1++)
              {
                blinkfound = false;
                for ( c2 = fluidzoneedgeindexes[zliid]; c2 < fluidzoneedgeindexes[zliid+1]; c2++)
                {
                  if (  fluidzoneedge[c2].x == tempcoord[c1].x && 
                        fluidzoneedge[c2].y == tempcoord[c1].y )
                  {
                    blinkfound = true;
                    break;
                  }
                }
                if ( !blinkfound )
                  tempcoord[c1].x = 9000;
              }

              blinkfound = false;
              
              currdir.x = 0;
              currdir.y = 0;
              lastn = 0;
              for ( c1 = 0; c1 < sumcoord; c1++)
              {
                if ( tempcoord[c1].x != 9000)
                {
                  blinkfound = true;
                  if ( abs(tempcoord[c1].x - lastpoint.x + lastdir.x) + abs(tempcoord[c1].y - lastpoint.y + lastdir.y) > abs(currdir.x) + abs(currdir.y) )
                  {
                    lastn = c1;
                    currdir.x = tempcoord[c1].x - lastpoint.x + lastdir.x;
                    currdir.y = tempcoord[c1].y - lastpoint.y + lastdir.y;
                  }
                }
              }
              if ( blinkfound )
              {
                nodebool[tempcoord[lastn].x][tempcoord[lastn].y] = true;
                currdir.x = tempcoord[lastn].x - lastpoint.x;
                currdir.y = tempcoord[lastn].y - lastpoint.y;
                linksinner[currlink] = tempcoord2[lastn];
              }
            } // elseif sumcoord > 1
          
          } // !bnarrow
          
          
          //FIXMEEEE end
          
          
          //add point.
          if ( blinkfound )
          {
            lastpoint.x += currdir.x;
            lastpoint.y += currdir.y;
            if ( currdir.x == lastdir.x && currdir.y == lastdir.y )
            {
              links[currlink-1] = lastpoint;
            }
            else 
            {
              links[currlink]       = lastpoint;
              linksinner[currlink]  = innerside;
              lastdir               = currdir;
              currlink++;
            }
            npointcheck++;
            
          }
          else 
          {
            lastpoint.x = 9000;
            lastpoint.y = 9000;
            //Broodwar->printf("nothing f9und " );
            break;
          }
        } // while
       
        //register where we were last time, will continue from there
          
      } // little while
      
      /////////
      //all points of fluidzone checked, no more links to find?
      if ( npointcheck >= fluidzoneedgeindexes[zliid+1] - fluidzoneedgeindexes[zliid] )
      {
        lastpoint.x = 9000;
        lastpoint.y = 9000;
        zliid++;
        npointcheck = 0;
        zonelinkindex[zliid] = zliiid;
        bchecked = false;
      }
    } // big while

    if ( !bhighreslinksfound && bfluidfilldone && zliid >= zonen )
    {
      bjustfinished       = true;
      bhighreslinksfound  = true;
    }


    if ( bhighreslinksfound )
    {
      for ( c1 = 0; c1 < zonen; c1++ )
      {
        for ( c2 = zonelinkindex[c1]; c2 < zonelinkindex[c1+1]; c2++ )
        {
          for ( c3 = zonelinkindexindex[c2]; c3 < zonelinkindexindex[c2+1]; c3++ )
          {
            if ( c3 == zonelinkindexindex[c2+1]-1 )
            {
              if ( abs(links[zonelinkindexindex[c2]].x - links[c3].x) < 2 && abs(links[zonelinkindexindex[c2]].y - links[c3].y) < 2 )
                Broodwar->drawLineMap(links[zonelinkindexindex[c2]].x*8, links[zonelinkindexindex[c2]].y*8, links[c3].x*8, links[c3].y*8, Colors::Green);
            }
            else 
            {
              Broodwar->drawLineMap(links[c3+1].x*8, links[c3+1].y*8, links[c3].x*8, links[c3].y*8, Colors::Green);
            }
          }
        }
        
      }
    }

    //have we checked all tiles? IF YES, START TO REDUCE NODE TABLES but for now, just stop
    if ( banalizis_finished )
      analyzed = true;

  } // if !analyzed

}

void ExampleAIModule::onSendText(std::string text)
{
  Broodwar->sendText("%s",text.c_str());
}

void ExampleAIModule::onReceiveText(BWAPI::Player* player, std::string text){}
void ExampleAIModule::onPlayerLeft(BWAPI::Player* player){}
void ExampleAIModule::onNukeDetect(BWAPI::Position target){}
void ExampleAIModule::onUnitDiscover(BWAPI::Unit* unit){}
void ExampleAIModule::onUnitEvade(BWAPI::Unit* unit){}
void ExampleAIModule::onUnitShow(BWAPI::Unit* unit){}
void ExampleAIModule::onUnitHide(BWAPI::Unit* unit){}
void ExampleAIModule::onUnitCreate(BWAPI::Unit* unit){}
void ExampleAIModule::onUnitDestroy(BWAPI::Unit* unit){}
void ExampleAIModule::onUnitMorph(BWAPI::Unit* unit){}
void ExampleAIModule::onUnitRenegade(BWAPI::Unit* unit){}
void ExampleAIModule::onSaveGame(std::string gameName){}

