#include <Xtreme/XRenderer.h>

#include <cmath>

#include ".\BirdiesRevenge.h"
#include ".\Bubble.h"
#include ".\Level.h"



Bubble::Bubble()
{
  m_Type = Birdie2::UT_BUBBLE;

  m_bArrivedOnTop = false;

  m_fTimeToPop = 0.0f;

  m_pCaughtUnit = NULL;

  m_fAnimTime = 0.0f;
  m_fMovedDistance = 0.0f;

  m_MovementBounds.set( 12, 12, 40, 40 );
  m_CollisionBounds.set( 12, 12, 40, 40 );

  m_Floating = true;

  SetAnimation( "Bubble" );
}



Bubble::~Bubble()
{
  if ( m_pCaughtUnit )
  {
    if ( m_pCaughtUnit->m_pOnUnit )
    {
      m_pCaughtUnit->m_pOnUnit->m_CarriedUnits.remove( m_pCaughtUnit );
      m_pCaughtUnit->m_pOnUnit = NULL;
    }
  }
  delete m_pCaughtUnit;
}



void Bubble::Display( const GR::tPoint& ptOffset, XRenderer& Renderer )
{
  int     size = 64;
  if ( m_pCaughtUnit )
  {
    m_pCaughtUnit->m_Position = m_Position;

    /*
    GR::tPoint    myCenter = MovementBounds().center();

    GR::tPoint    offset = myCenter - m_pCaughtUnit->MovementBounds().size() / 2;

    m_pCaughtUnit->m_Position = offset;
    m_pCaughtUnit->SetImage( m_CaughtImage );
    m_pCaughtUnit->Display( ptOffset, Renderer );
    */

    GR::tPoint    myCenter = MovementBounds().center();
    GR::tPoint    caughtUnitPos = myCenter - m_pCaughtUnit->MovementBounds().size() / 2;

    auto tsImage = theApp.Section( m_CaughtImage );

    GR::tFPoint     tuv[4];

    tsImage.GetTrueUV( tuv[0], tuv[1], tuv[2], tuv[3] );

    int       width = tsImage.m_Width;
    int       height = tsImage.m_Height;

    int       x = caughtUnitPos.x - ptOffset.x + width / 2;
    int       y = caughtUnitPos.y - ptOffset.y + height / 2;

    GR::f32   zoomX = 0.9f + 0.1f * std::sin( m_fAnimTime );
    GR::f32   zoomY = 0.9f + 0.1f * std::cos( m_fAnimTime );
    GR::f32   angle = 0.0f;

    GR::tVector   vDelta( -width * 0.5f * zoomX, -height * 0.5f * zoomY, 0.0f );
    GR::tVector   vDelta2( width * 0.5f * zoomX, -height * 0.5f * zoomY, 0.0f );
    GR::tVector   vDelta3( -width * 0.5f * zoomX, height * 0.5f * zoomY, 0.0f );
    GR::tVector   vDelta4( width * 0.5f * zoomX, height * 0.5f * zoomY, 0.0f );

    vDelta.RotateZ( -angle );
    vDelta2.RotateZ( -angle );
    vDelta3.RotateZ( -angle );
    vDelta4.RotateZ( -angle );

    GR::tVector   ptPos1 = GR::tVector( (float)x, (float)y, 0 ) + vDelta;
    GR::tVector   ptPos2 = GR::tVector( (float)x, (float)y, 0 ) + vDelta2;
    GR::tVector   ptPos3 = GR::tVector( (float)x, (float)y, 0 ) + vDelta3;
    GR::tVector   ptPos4 = GR::tVector( (float)x, (float)y, 0 ) + vDelta4;

    Renderer.SetTexture( 0, tsImage.m_pTexture );
    Renderer.RenderQuadDetail2d( ptPos1.x, ptPos1.y,
      ptPos2.x, ptPos2.y,
      ptPos3.x, ptPos3.y,
      ptPos4.x, ptPos4.y,
      tuv[0].x, tuv[0].y,
      tuv[1].x, tuv[1].y,
      tuv[2].x, tuv[2].y,
      tuv[3].x, tuv[3].y,
      0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff );

    size = math::maxValue( tsImage.m_Width, size );
    size = math::maxValue( tsImage.m_Height, size );
  }
  
  bool    displayBubble = true;

  if ( m_fTimeToPop >= 8.0f )
  {
    if ( fmodf( m_fTimeToPop, 0.25f ) >= 0.125f )
    {
      displayBubble = false;
    }
  }
  if ( displayBubble )
  {
    XTextureSection     tsImage( theApp.AnimationFrame( m_AnimPos ) );
    //Renderer.RenderTextureSectionAlphaBlendedColorKeyed( m_Position.x, m_Position.y, tsImage, 128, 0xffff00ff );
    /*
    Renderer.RenderTextureSectionRotatedZoomedColorKeyedColorized( m_Position.x + 32 - ptOffset.x, m_Position.y + 32 - ptOffset.y, tsImage, 0.0f,
    0.9f + 0.1f * std::sin( m_fAnimTime ),
    0.9f + 0.1f * std::cos( m_fAnimTime ),
    0xffff00ff, 0x80ffffff );
    */

    Renderer.RenderTextureSection2d( m_Position.x - ptOffset.x, m_Position.y - ptOffset.y, tsImage, 0xffffffff, size, size );
  }
}



void Bubble::Update( Level& Level, const GR::f32 fElapsedTime )
{
  GR::tFPoint   ptCurPos( 400.0f, 52.0f );

  m_fTimeToPop += fElapsedTime;
  if ( m_fTimeToPop >= 10.0f )
  {
    m_RemoveMe = true;

    Level.m_Units.push_back( m_pCaughtUnit );
    m_pCaughtUnit->m_Jumping = false;
    m_pCaughtUnit = NULL;
  }

  m_fAnimTime += 5.0f * fElapsedTime;

  m_Position = m_TruePosition;
  m_Position.x += (int)( 20.0f * std::sin( m_fAnimTime * 0.4f ) );
}



void Bubble::UpdateFixed( Level& Level )
{
  if ( !m_bArrivedOnTop )
  {
    GR::tPoint    ptTarget( Level.m_BubbleTargetPos );

    GR::tPoint    ptPos( m_TruePosition );

    GR::tPoint    delta( ptTarget - m_TruePosition );

    // go y first
    if ( delta.y != 0 )
    {
      delta.y = math::clamp( delta.y, -1, 1 );

      m_Position = m_TruePosition;
      MoveUnblocked( Level, 0, delta.y );
      m_TruePosition = m_Position;
      m_Position = m_TruePosition;
      m_Position.x += (int)( 20.0f * std::sin( m_fAnimTime * 0.4f ) );
    }
    else if ( delta.x != 0 )
    {
      delta.x = math::clamp( delta.x, -1, 1 );

      m_Position = m_TruePosition;
      MoveUnblocked( Level, delta.x, 0 );
      m_TruePosition = m_Position;
      m_Position = m_TruePosition;
      m_Position.x += (int)( 20.0f * std::sin( m_fAnimTime * 0.4f ) );
    }
    else
    {
      m_bArrivedOnTop = true;
    }
  }
  Unit::UpdateFixed( Level );
}



void Bubble::ProcessEvent( Level& Level, const eUnitEvent& Event )
{
  Unit::ProcessEvent( Level, Event );

  switch ( Event )
  {
    case ET_BLOCKED_LEFT:
      break;
    case ET_BLOCKED_RIGHT:
      break;
    case ET_FALL_START:
      break;
    case ET_FALL_END:
      break;
  }
}