#include "blobcollective.h"
#include "lp_profiler.h"

BlobCollective::BlobCollective(const float xPos, const float yPos, const float aRadius)
{
  Blob* blob = new Blob(xPos, yPos, aRadius);
  blobs.Add(blob);
}

BlobCollective::~BlobCollective()
{
}

void
BlobCollective::Split()
{
  float biggestRadius = -1.0f;
  int biggestIndex = -1;

  for(int i = 0; i < blobs.Count(); i++)
  {
    Blob* t = blobs[i];
    if(t->GetRadius() > biggestRadius)
    {
      biggestRadius = t->GetRadius();
      biggestIndex = i;
    }
  }

  //biggestIndex = random() % blobs.Count();
  //biggestRadius = blobs[biggestIndex]->GetRadius();

  float aRadius = 5000.0f + 1000.0f - (float)(random() % 2000);
  aRadius /= 10000.0f;
  float bRadius = 1.0f - aRadius;

  aRadius = sqrt(biggestRadius * biggestRadius * aRadius);
  bRadius = sqrt(biggestRadius * biggestRadius * bRadius);

  Blob* biggest = blobs[biggestIndex];

  Blob* newBlob = new Blob(biggest->GetPosition().x + biggestRadius * 0.15f, biggest->GetPosition().y, aRadius);
  blobs.Add(newBlob);
  newBlob = new Blob(biggest->GetPosition().x - biggestRadius * 0.15f, biggest->GetPosition().y, bRadius);
  blobs.Add(newBlob);

  blobs.RemoveAt(biggestIndex);
  delete biggest;
}

void
BlobCollective::Join()
{
  if(blobs.Count() == 1)
    return;

  Blob* smallest = NULL;
  float smallestRadius = 100000.0f;
  int smallestIndex = -1;

  for(int i = 0; i < blobs.Count(); i++)
  {
    if(blobs[i]->GetRadius() < smallestRadius)
    {
      smallestIndex = i;
      smallestRadius = blobs[i]->GetRadius();
      smallest = blobs[i];
    }
  }

  LP_ASSERT(smallest);

  Blob* closest = NULL;
  float closestDist = 100000.0f;
  int closestIndex = -1;
  for(int i = 0; i < blobs.Count(); i++)
  {
    if(i == smallestIndex)
      continue;
    float dist = LP_Vector2::Dist(smallest->GetPosition(), blobs[i]->GetPosition());
    if(dist < closestDist)
    {
      closestIndex = i;
      closestDist = dist;
      closest = blobs[i];
    }
  }

  LP_ASSERT(closest);

  float newRadius = smallestRadius * smallestRadius;
  newRadius += closest->GetRadius() * closest->GetRadius();
  newRadius = sqrt(newRadius);

  blobs.Remove(smallest);
  blobs.Remove(closest);

  Blob* newBlob = new Blob(smallest->GetPosition().x, smallest->GetPosition().y, newRadius);
  blobs.Add(newBlob);

  delete smallest;
  delete closest;
}

void
BlobCollective::Move(const float dt)
{
  LP_PROFILE(BLOB_COLLECTIVE_MOVE);
  for(int i = 0; i < blobs.Count(); i++)
    blobs[i]->Move(dt);
}

void
BlobCollective::Satisfy(Env& env)
{
  LP_PROFILE(BLOB_COLLECTIVE_SATISFY);
  for(int i = 0; i < blobs.Count(); i++)
    blobs[i]->Satisfy(env);

  CollisionTestBlobs();
}

void
BlobCollective::CollisionTestBlobs()
{
  for(int i = 0; i < blobs.Count(); i++)
  {
    for(int j = 0; j < blobs.Count(); j++)
    {
      if(i == j)
        continue;

      blobs[i]->CollisionTest(*(blobs[j]));
    }
  }
}

void
BlobCollective::SetForce(LP_Vector2& aForce)
{
  for(int i = 0; i < blobs.Count(); i++)
    blobs[i]->SetForce(aForce);
}

void
BlobCollective::AddForce(LP_Vector2& aForce)
{
  for(int i = 0; i < blobs.Count(); i++)
    blobs[i]->AddForce(aForce);
}

void
BlobCollective::Draw()
{
  LP_PROFILE(BLOB_COLLECTIVE_DRAW);
  for(int i = 0; i < blobs.Count(); i++)
    blobs[i]->Draw();
}

