#include "HomingEnemy.h"
#include "LD.h"
#include "Level.h"
#include "Player.h"

#include <list>



HomingEnemy::HomingEnemy() :
  GameObject( LD::GO_HOMING_ENEMY )
{
  m_Texture = LD::TEX_HOMING_ENEMY_1;
  Width = 32;
  Height = 32;
  AnimDelay = 0.0f;
  SizeFactor = 0.25f;
  pTarget = NULL;
}


void HomingEnemy::Display()
{
  //GameObject::Display();
  int     trueWidth = (int)( Width * SizeFactor );
  int     trueHeight = (int)( Height * SizeFactor );
  theApp.RenderTextureSection2d( X - trueWidth / 2, Y - trueHeight / 2, 
                                 theApp.m_TexSec[m_Texture], 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
                                 trueWidth, trueHeight );
}



void HomingEnemy::DetermineNewTarget( Level& Level )
{
  GameObject*   pBestTarget = NULL;
  float         closestDistance = 50000.0f;

  std::list<GameObject*>::iterator    itO( Level.Objects.begin() );
  while ( itO != Level.Objects.end() )
  {
    GameObject*   pObj( *itO );

    if ( ( pObj->m_Type == LD::GO_PLAYER )
    ||   ( pObj->m_Type == LD::GO_PLANKTON ) )
    {
      int     dx = pObj->X - X;
      int     dy = pObj->Y - Y;

      D3DXVECTOR2     delta( (float)dx, (float)dy );

      float           distance = D3DXVec2Length( &delta );

      /*
      if ( ( pObj->m_Type == LD::GO_PLAYER )
      &&   ( ( (Player*)pObj )->SizeFactor > SizeFactor ) )
      {
        // player is bigger, stop chasing
        ++itO;
        continue;
      }*/

      if ( ( pBestTarget == NULL )
      ||   ( distance < closestDistance ) )
      {
        pBestTarget = pObj;
        closestDistance = distance;
      }
    }

    ++itO;
  }
  pTarget = pBestTarget;
}



void HomingEnemy::Update( Level& Level, float ElapsedTime )
{
  AnimDelay += ElapsedTime;
  if ( fmodf( AnimDelay, 0.5f ) >= 0.25f )
  {
    m_Texture = LD::TEX_HOMING_ENEMY_1;
  }
  else
  {
    m_Texture = LD::TEX_HOMING_ENEMY_2;
  }

  if ( pTarget == NULL )
  {
    DetermineNewTarget( Level );
  }

  if ( pTarget != NULL )
  {
    int     dx = pTarget->X - X;
    int     dy = pTarget->Y - Y;

    D3DXVECTOR2     delta( (float)dx, (float)dy );

    float           distance = D3DXVec2Length( &delta );

    D3DXVec2Normalize( &delta, &delta );

    //if ( distance < 200.0f )
    {
      Level.MoveObject( this, 25.0f * delta.x * ElapsedTime, 25.0f * delta.y * ElapsedTime );
    }
  }

  std::list<GameObject*>::iterator    itO( Level.Objects.begin() );
  while ( itO != Level.Objects.end() )
  {
    GameObject*   pObj( *itO );

    if ( pObj->m_Type == LD::GO_PLANKTON )
    {
      RECT    rcDummy;
      if ( IntersectRect( &rcDummy, &Bounds(), &pObj->Bounds() ) )
      {
        pObj->RemoveMe = true;
        if ( pObj == pTarget )
        {
          pTarget = NULL;
        }
        Grow( Level, 0.05f );
        theApp.PlaySoundA( LD::SOUND_EAT );
      }
    }
    ++itO;
  }
}



RECT HomingEnemy::Bounds()
{
  RECT    rc;

  int     trueWidth = (int)( Width * SizeFactor );
  int     trueHeight = (int)( Height * SizeFactor );

  SetRect( &rc, X - trueWidth / 2, Y - trueHeight / 2, X + trueWidth / 2, Y + trueHeight / 2 );

  return rc;
}



void HomingEnemy::OnObjectRemoved( Level& Level, GameObject* pKilledObject )
{
  if ( pKilledObject == pTarget )
  {
    pTarget = NULL;
  }
  if ( pKilledObject == this )
  {
    theApp.PlaySoundA( LD::SOUND_DIE );
  }
}



void HomingEnemy::Grow( Level& Level, float GrowFactor )
{
  int     oldWidth = (int)( Width * SizeFactor );
  int     oldHeight = (int)( Height * SizeFactor );

  float     newFactor = SizeFactor + GrowFactor;
  int     trueWidth = (int)( Width * newFactor );
  int     trueHeight = (int)( Height * newFactor );

  if ( ( trueWidth == oldWidth )
    && ( trueHeight == oldHeight ) )
  {
    SizeFactor += GrowFactor;
    return;
  }
  // grow carefully to all sides to avoid getting stuck in a wall
  int       dx = trueWidth - oldWidth;
  int       dy = trueHeight - oldHeight;

  RECT      rc( Bounds() );

  while ( ( dx > 0 )
    || ( dy > 0 ) )
  {
    bool    wantedToGrowX = ( dx > 0 );
    bool    couldGrowX = false;
    bool    wantedToGrowY = ( dy > 0 );
    bool    couldGrowY = false;
    if ( dx > 0 )
    {
      ++rc.right;

      if ( Level.IsAreaBlocked( this, rc ) )
      {
        --rc.right;
      }
      else
      {
        --dx;
        couldGrowX = true;
      }
    }
    if ( dx > 0 )
    {
      --rc.left;

      if ( Level.IsAreaBlocked( this, rc ) )
      {
        ++rc.left;
      }
      else
      {
        --dx;
        couldGrowX = true;
        --X;
      }
    }
    if ( dy > 0 )
    {
      ++rc.bottom;

      if ( Level.IsAreaBlocked( this, rc ) )
      {
        --rc.bottom;
      }
      else
      {
        --dy;
        couldGrowY = true;
      }
    }
    if ( dy > 0 )
    {
      --rc.top;

      if ( Level.IsAreaBlocked( this, rc ) )
      {
        ++rc.top;
      }
      else
      {
        --dy;
        couldGrowY = true;
        --Y;
      }
    }

    if ( ( ( wantedToGrowX )
      && ( !couldGrowX ) )
      || ( ( wantedToGrowY )
      && ( !couldGrowY ) ) )
    {
      // could not grow, stuck!
      RemoveMe = true;
      Level.SpawnParticles( 50, X, Y, 0xffff0000 );
      theApp.PlaySoundA( LD::SOUND_DIE );
      return;
    }
  }
  SizeFactor += GrowFactor;

  RECT    bounds = Bounds();

  if ( ( bounds.right != rc.right )
    || ( bounds.left != rc.left )
    || ( bounds.top != rc.top )
    || ( bounds.bottom != rc.bottom ) )
  {
    if ( ( bounds.right - bounds.left == rc.right - rc.left )
      && ( bounds.bottom - bounds.top == rc.bottom - rc.top ) )
    {
      X += rc.left - bounds.left;
      Y += rc.top - bounds.top;
    }
    else
    {
      int a = 0;
    }
  }
}



