//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "dMandelbrotC.h"
#include "ServerPool.h"
#include "ServerThread.h"
#include "ServerWindow.h"
#include "Unit1.h"
#include <stdio.h>
#include <dos.h> // for testing.

__fastcall ServerPool::ServerPool()
{
  // Do nothing

   // For testing, use just two threads.
 //Pool[0] = new ServerThread(true);
// Pool[0]->Socket->Address = "127.0.0.1";

 //Pool[1] = new ServerThread(true);
 //Pool[1]->Socket->Address ="127.0.0.1";

 NumServers = 0;


}

int __fastcall  ServerPool::ScanCblock(AnsiString CblockExample)
{
 if (NumServers + 256 > MAX_SERVERS)
   return(false);

  // Create the buffer to hold this test:
  Data = new char* [51];
  for(int j = 0; j < 51; j++)
     Data[j] = new char[51];

   char base[100];

   // Add the First Server.
   ImageWin->SPool->AddServer( CblockExample);


   // Use the address of the first server to find others...
   AnsiString baseAddr = ImageWin->SPool->Pool[0]->IP;

   strcpy(base,baseAddr.c_str());
   int i = strlen(base);
   while(i > 0 && base[i] !='.')
     i--;

   base[i]='\0';  // Chop off the end stuff.

  for(int i = 1; i< 255; i++)
  {
   char newIP[100];
   sprintf(newIP,"%s.%d",base,i);

  Pool[NumServers] = new ServerThread(true);
  Pool[NumServers]->Socket->Host = newIP; // For Testing.

  // Run this new server with a test case to determine speed.
  Pool[NumServers]->SendBuf.sy = 0;
  Pool[NumServers]->SendBuf.ey = 50;
  Pool[NumServers]->SendBuf.sx = 0;
  Pool[NumServers]->SendBuf.ex = 50;
  Pool[NumServers]->SendBuf.maxIter = 240;
  Pool[NumServers]->SendBuf.rMin = -2.75;
  Pool[NumServers]->SendBuf.iMin = -1.25;
  Pool[NumServers]->SendBuf.rInc = (0.75 + 2.75) / 50;
  Pool[NumServers]->SendBuf.iInc = (1.25 + 1.25) / 50;;

  Pool[NumServers]->Resume();
  NumServers++;
  }

  bool Flag = true;
  while (Flag )
  {
   Flag = false;
   for(int i = NumServers-254; i < NumServers; i++)
   {
     if ( Pool[i]->Suspended != true)
       Flag = true;
   }
   _sleep(1);
  } // end while.



  //Dealocate the memory we allocated at the begining:
  //for(int j = 0; j < 51; j++)
  //   delete  Data[j];
  //delete Data;

  // Find bad servers.
  RemoveDeadServers();

  // Sort the remaining Servers
  SortServers();

} // End ScanCblock


int __fastcall  ServerPool::AddServer(AnsiString Server)
{
 if (NumServers == MAX_SERVERS)
   return(false);

  Pool[NumServers] = new ServerThread(true);
  Pool[NumServers]->Socket->Host = Server; // For Testing.

  // Run this new server with a test case to determine speed.
  Pool[NumServers]->SendBuf.sy = 0;
  Pool[NumServers]->SendBuf.ey = 50;
  Pool[NumServers]->SendBuf.sx = 0;
  Pool[NumServers]->SendBuf.ex = 50;
  Pool[NumServers]->SendBuf.maxIter = 240;
  Pool[NumServers]->SendBuf.rMin = -2.75;
  Pool[NumServers]->SendBuf.iMin = -1.25;
  Pool[NumServers]->SendBuf.rInc = (0.75 + 2.75) / 50;
  Pool[NumServers]->SendBuf.iInc = (1.25 + 1.25) / 50;;

  // Create the buffer to hold this test:
  Data = new char* [51];
  for(int j = 0; j < 51; j++)
     Data[j] = new char[51];

  Pool[NumServers]->Resume();

  // for testing add semaphore here...
  while( Pool[NumServers]->Suspended != true)
  {
    _sleep(1);
  }

  if(Pool[NumServers]->ServerBad == false) // got done!
  {
    NumServers++;
  }
  else
  {
    delete Pool[NumServers]; return(false);
  }



  //Dealocate the memory we allocated at the begining:
  for(int j = 0; j < 51; j++)
     delete  Data[j];
  delete Data;

  // Sort the Servers
  SortServers();


} // End addServer

void __fastcall ServerPool::RemoveServer(int Server)
{
 if (Server >= 0 && Server < NumServers )
 {
  delete Pool[Server];
  for(int j = Server; j < NumServers - 1; j++)
  {
   Pool[j] = Pool[j+1];
  }

  NumServers--;
 } // end if.
}

void __fastcall ServerPool::SortServers(void)
{
 // Simple Insertion sort based on the speed of each server.
 int i,j;
 ServerThread *X;

 for(i = 1; i < NumServers; i++)
 {
   X = Pool[i];
   j = i-1;
   while(j >= 0 && Pool[j]->Ips < X->Ips)
   {
    Pool[j+1] = Pool[j];
    j--;
   }
  Pool[j+1] = X;
 }

}

void __fastcall ServerPool::RemoveDeadServers(void)
{

 for(int i = 0; i < NumServers; i++)
 {
   if (Pool[i]->ServerBad == true || Pool[i]->Ips == 0)
   {
    RemoveServer(i);
   }
 }
} // End RemoveDeadServers

void __fastcall ServerPool::RunMandelbrot(int Height, int Width, long double Rmin,
                long double Rmax, long double Imin, long double Imax)
{


 int ServerPoolPower = 0;  // Incase it's the first time, give a default.
 double iInc,rInc;
 rInc = (Rmax - Rmin) / Width;
 iInc = (Imax - Imin) / Height;


 // Create our image buffer.
  Data = new char* [Width];
  for(int j = 0; j < Width; j++)
     Data[j] = new char[Height];




 // Calculate the total processing power of our server pool.
 for(int i = 0; i < NumServers; i++)
 {
  ServerPoolPower += Pool[i]->Ips;
 }


 // Check which allocation algorithm to run..
 if ( ServerWin->EqualAllocationCB->Checked)
 {
  int Position = 0;
  for(int i = 0; i < NumServers; i++)
  {
    // All servers the same:
    Pool[i]->SendBuf.sy = 0;
    Pool[i]->SendBuf.ey = Height - 1;
    Pool[i]->SendBuf.maxIter = 240;
    Pool[i]->SendBuf.rMin = Rmin;
    Pool[i]->SendBuf.iMin = Imin;
    Pool[i]->SendBuf.rInc = rInc;
    Pool[i]->SendBuf.iInc = iInc;

    // Diffrent for diffrent servers.

    Pool[i]->SendBuf.sx = Position;

    // Calculate the end of this Server's part.
    // This algorithm is completely even and fair, not taking into
    // account the relative speeds of each server.
    Position += (Width - 1) / NumServers;

    // Make sure we get the last one right!
    if (i == NumServers - 1)
     Pool[i]->SendBuf.ex = Width - 1;
    else
     Pool[i]->SendBuf.ex = Position - 1;

  }
   // Gentelmen, start your engines!
 for(int i = 0; i < NumServers; i++)
   Pool[i]->Resume();

 ControlWin->ProgressBar->Max = NumServers;

 // We wait for the servers to get done:


 boolean done = false;
 while ( ! done)
 {
 done = true;
 int NumberDone = 0;
  for(int i = 0; i < NumServers; i++)
  {
    if (Pool[i]->Suspended == false)
    {
      done = false;
    }
    else
    {
      NumberDone++;
    }
  }

  // Check for servers that got clobered, and re-assign their
  // work to the next guy to get done.
  for(int i = 0; i < NumServers; i++)
  {
    // Check if somebody unpluged something... (ie, server went down)
    if ( Pool[i]->ServerBad == true && Pool[i]->Recovered == false)
    {
      // Make best effort to try and find somebody to cover for it.
      for(int j = 0; j < NumServers; j++)
      {
        if (Pool[j]->Suspended == true && Pool[j]->ServerBad == false)
        {
          // We found our volenteer, turn him loose.
          Pool[j]->SendBuf = Pool[i]->SendBuf;
          Pool[j]->Resume();
          Pool[i]->Recovered = true; //no need to do this again ;>
          done = false; // duh....

        }
      } // end for looking for server to take over.

    } // end if server died half-way through.
  } // end error recovery for loop.

  ControlWin->ProgressBar->Position = NumberDone;
  ControlWin->ProgressBar->Update();
  // for testing Possibly take out later, in here now to prevent busy wait.
  _sleep(1);// do nothing
 }




 }    // End Equal Allocation
 else
 {


  int SliceSize = (int) ServerWin->SliceSizeEB->Text.ToDouble();
  int Position = 0;
  // Slice Competition!
   ControlWin->ProgressBar->Max = Width;
  // Step 1.
  // Allocate each server a  slice, if enough exist.
  for(int i = 0; i < NumServers; i++)
  {
     // All servers the same:
    Pool[i]->SendBuf.sy = 0;
    Pool[i]->SendBuf.ey = Height - 1;
    Pool[i]->SendBuf.maxIter = 240;
    Pool[i]->SendBuf.rMin = Rmin;
    Pool[i]->SendBuf.iMin = Imin;
    Pool[i]->SendBuf.rInc = rInc;
    Pool[i]->SendBuf.iInc = iInc;

    // Diffrent for diffrent servers.

    Pool[i]->SendBuf.sx = Position;

    // Calculate the end of this Server's part.

    Position += SliceSize + 1;

    // Make sure we get the last one right!
    if (Position > Width - 1)
    {
     Pool[i]->SendBuf.ex = Width - 1;
     break;  // Exit this loop, we are done (SMALL IMAGE!)
    }
    else
    {
     Pool[i]->SendBuf.ex = Position - 1;
    }

  ControlWin->ProgressBar->Position = Position;
  ControlWin->ProgressBar->Update();

  }
  // End Step 1

  // Step 2.
  // Start the servers, and as they finish, give them another slice
  // Until there are no more slices.
  for(int i = 0; i < NumServers; i++)
    Pool[i]->Resume();

  // Cycle through servers, looking for new ones to give slices to.
  while( Position <= Width -1 )
  {
    // First of all,
    // Check for servers that got clobered, and re-assign their
  // work to the next guy to get done.

  for(int i = 0; i < NumServers; i++)
  {
    // Check if somebody unpluged something... (ie, server went down)
    if ( Pool[i]->ServerBad == true && Pool[i]->Recovered == false)
    {
      // Wait for somebody to get done.
      bool waitdone = false;
      while( !waitdone )
      {
      for(int j = 0; j < NumServers; j++)
      {
        if (Pool[j]->Suspended == true && Pool[j]->ServerBad == false)
        {
          // We found our volenteer, turn him loose.
          Pool[j]->SendBuf = Pool[i]->SendBuf;
          Pool[j]->Resume();
          Pool[i]->Recovered = true; //no need to do this again ;>
          waitdone = true;
        } // end if
      } // end for - looking for server to take over.
      } // end while -(wait for somebody to get done).
    } // end if -server died half-way through.
  } // end for error recovery for loop.


  // Sort the Servers, giving any with more speed preference.
  SortServers();


  // Now that we recovered from clobbered servers, look for
  // servers that got done, and give them more work.

  for(int i = 0; i < NumServers; i++)
  {
    if (Pool[i]->Suspended == true && Pool[i]->ServerBad == false)
    {
     // Found an empty server (first in line via KI/s because of sort)
     // Lets give it some work and turn it loose!

     Pool[i]->SendBuf.sy = 0;
     Pool[i]->SendBuf.ey = Height - 1;
     Pool[i]->SendBuf.maxIter = 240;
     Pool[i]->SendBuf.rMin = Rmin;
     Pool[i]->SendBuf.iMin = Imin;
     Pool[i]->SendBuf.rInc = rInc;
     Pool[i]->SendBuf.iInc = iInc;

     // Starting position
     Pool[i]->SendBuf.sx = Position;

     // ending position
      Position += SliceSize + 1;

    // Make sure we get the last one right!
    if (Position > Width - 1)
    {
     Pool[i]->SendBuf.ex = Width - 1;
     break;  // Exit this FOR loop, we are done!
    }
    else
    {
     Pool[i]->SendBuf.ex = Position - 1;
    }

    }
    // Start this server.
    Pool[i]->Resume();
  } // end for - servers who are done.

  
  ControlWin->ProgressBar->Position = Position;
  ControlWin->ProgressBar->Update();

  } // End while - Still work left to do.

  // End Step 2

  // Step 3 Wait for the last few slices to get done.


  // Simple, we just wait.
  // For testing: ( add anti-clobber code here as well)
  // not too important, shouldn't happen often, and will only cause
  // a small prob at end of image.
   bool done2 = false;
  while(!done2)
  {
  done2=true;
  for(int i = 0; i < NumServers; i++)
  {
    if (Pool[i]->Suspended == false)
    {
      done2 = false;
    }
   } // end for.
  }// end while.



  //End Step3.

 // Old One!
 //Allocate portion of the image to be drawn between the
 // diffrent servers, so that they should all get done at
 // the same time (if they operate at the same speed as they
 // did last time).
 /* int Position = 0;
  for(int i = 0; i < NumServers; i++)
  {
    // All servers the same:
    Pool[i]->SendBuf.sy = 0;
    Pool[i]->SendBuf.ey = Height - 1;
    Pool[i]->SendBuf.maxIter = 240;
    Pool[i]->SendBuf.rMin = Rmin;
    Pool[i]->SendBuf.iMin = Imin;
    Pool[i]->SendBuf.rInc = rInc;
    Pool[i]->SendBuf.iInc = iInc;

    // Diffrent for diffrent servers.

    Pool[i]->SendBuf.sx = Position;

    // Calculate the end of this Server's part.

    Position += (int) ((double)(Width - 1) /
            ( (double)ServerPoolPower / (double)Pool[i]->Ips ) );

    // Make sure we get the last one right!
    if (i == NumServers - 1)
     Pool[i]->SendBuf.ex = Width - 1;
    else
     Pool[i]->SendBuf.ex = Position - 1;

  }

  ----- END Old way */
 }


 // Copy the image to the viewport.
 Graphics::TBitmap *Bitmap = new Graphics::TBitmap();
   Bitmap->Width  = Width;
   Bitmap->Height = Height;
   Bitmap->PixelFormat = 3;


 Byte *ptr;
 for(int y = 0; y < Height; y++)
 {
   ptr = (unsigned char*) Bitmap->ScanLine[y];
   for(int x = 0; x < Width; x++)
   {
    ptr[x] = Data[x][y];
   } // end X loop.
 } // end Y loop.

 //Dealocate the memory we allocated at the begining:
  for(int j = 0; j < Width; j++)
     delete  Data[j];
  delete Data;

 // Display Image.
 ImageWin->Display->Picture->Graphic = Bitmap;

 // If any servers died, remove them.
 RemoveDeadServers();

 // Now, sort the servers based on their speed.
 SortServers();

 // Now, update the servers List
 ServerWin->UpdateServerList();


}




//---------------------------------------------------------------------------
#pragma package(smart_init)
