#include <IO/FileStream.h>

#include "GSGame.h"
#include "BirdiesRevenge.h"
#include "Birdie.h"

#include <String/StringUtil.h>



IMPLEMENT_CLONEABLE( CGSGame, "GSGame" )



void CGSGame::Init()
{
  m_dwScore = 0;
  m_Level.m_GameEventHandler = fastdelegate::MakeDelegate( this, &CGSGame::ProcessGameEvent );
  m_dwLevel = 1;
  m_NumLives = 3;

  for ( int i = 0; i < 7; ++i )
  {
    m_DiamondsCollected[i] = false;
  }

  m_Level.Load( GR::IO::FileStream( theApp.AppPath( Misc::Format( "data/level%1%.dat" ) << m_dwLevel ).c_str() ) );

  StartLevel();
}



void CGSGame::Exit()
{
}



void CGSGame::StartLevel()
{
  m_pBossUnit = NULL;
  m_BossMaxHealth = 0;
  m_Level.PrepareForStart();

  Level::tListUnits::iterator   it( m_Level.m_Units.begin() );
  while ( it != m_Level.m_Units.end() )
  {
    Unit*   pUnit( *it );

    if ( pUnit->m_Type == Birdie2::UT_PUMPKIN )
    {
      m_pBossUnit = pUnit;
      m_BossMaxHealth = pUnit->m_HP;

      theApp.SoundClass()->Play( theApp.Sound( "Boss.Laugh" ) );
      theApp.PlaySong( "boss" );
      break;
    }
    ++it;
  }
}



void CGSGame::Display( XRenderer& Renderer )
{
  theApp.RenderBackground( Renderer, "BG.1" );

  m_Level.Display( Renderer );

  for ( int i = 0; i < 7; ++i )
  {
    if ( m_DiamondsCollected[i] )
    {
      Renderer.RenderTextureSection2d( 800 - 2 - 6 * 2 - 7 * 20 + i * 22, 2, theApp.Section( Misc::Format( "Diamond.%1%" ) << i + 1 ), 0xffffffff, 20, 20 );
    }
  }

  if ( m_pBossUnit != NULL )
  {
    Renderer.SetShader( XRenderer::ST_FLAT_NO_TEXTURE );
    Renderer.RenderQuad2d( 5, 5, ( 790 * m_pBossUnit->m_HP ) / m_BossMaxHealth, 10, 0xffff0000 );
    Renderer.SetShader( XRenderer::ST_ALPHA_TEST );
  }

  Renderer.RenderText2d( theApp.Font( "Font" ), 2, 0, ( Misc::Format( "Score: %01:9%" ) << m_dwScore ).Result().c_str() );
  Renderer.RenderText2d( theApp.Font( "Font" ), 2, 575, ( Misc::Format( "Lives: %1%" ) << m_NumLives ).Result().c_str() );
}



void CGSGame::UpdatePerDisplayFrame( const float ElapsedTime )
{
  if ( !IsActivelyUpdating() )
  {
    return;
  }

  m_Level.Update( ElapsedTime );

  /*
  if ( m_Level.m_pCenterOnUnit )
  {
    GR::tPoint    ptPos( m_Level.m_pCenterOnUnit->Bounds().center() );

    m_Level.m_ptOffset.x = ptPos.x - 400.0f;
    m_Level.m_ptOffset.y = ptPos.y - 300.0f;

    if ( m_Level.m_ptOffset.x < 0.0f )
    {
      m_Level.m_ptOffset.x = 0.0f;
    }
    if ( m_Level.m_ptOffset.x > m_Level.m_Feld.Width() * 20.0f - 800.0f )
    {
      m_Level.m_ptOffset.x = m_Level.m_Feld.Width() * 20.0f - 800.0f;
    }
    if ( m_Level.m_ptOffset.y < 0.0f )
    {
      m_Level.m_ptOffset.y = 0.0f;
    }
    if ( m_Level.m_ptOffset.y > m_Level.m_Feld.Height() * 20.0f - 600.0f )
    {
      m_Level.m_ptOffset.y = m_Level.m_Feld.Height() * 20.0f - 600.0f;
    }
  }*/

  if ( theApp.InputClass()->ReleasedKeyPressed( Xtreme::KEY_ESCAPE ) )
  {
    GR::Strings::ParameterList    params;

    params.SetParam( "InGame", 1 );
    PushState( "GSOptions", params );
  }
  if ( theApp.InputClass()->ReleasedKeyPressed( Xtreme::KEY_D ) )
  {
    ProcessGameEvent( Birdie2::CGameEvent( Birdie2::CGameEvent::GE_LEVEL_COMPLETED ) );
  }
}



void CGSGame::Update()
{
  if ( !IsActivelyUpdating() )
  {
    return;
  }
}



bool CGSGame::ProcessEvent( const GUI::OutputEvent& Event )
{
  switch ( Event.Type )
  {
    case OET_BUTTON_PUSHED:
      break;
  }
  return false;
}



void CGSGame::ProcessGameEvent( const Birdie2::CGameEvent& GameEvent )
{
  switch ( GameEvent.m_Type )
  {
    case Birdie2::CGameEvent::GE_ITEM_COLLECTED:
      if ( GR::Strings::StartsWith( GameEvent.m_strParam, "Diamond" ) )
      {
        int     diamondIndex = GR::Convert::ToI32( GameEvent.m_strParam.substr( 8 ) );
        if ( ( diamondIndex >= 1 )
        &&   ( diamondIndex <= 7 ) )
        {
          m_DiamondsCollected[diamondIndex - 1] = true;
        }
      }
      break;
    case Birdie2::CGameEvent::GE_CHANGE_SCORE:
      m_dwScore += GameEvent.m_iParam[0];
      break;
    case Birdie2::CGameEvent::GE_LEVEL_COMPLETED:
      m_dwLevel++;

      if ( !m_Level.Load( GR::IO::FileStream( theApp.AppPath( Misc::Format( "data/level%1%.dat" ) << m_dwLevel ).c_str() ) ) )
      {
        ChangeState( "GSDone" );
      }
      else
      {
        StartLevel();
      }
      break;
    case Birdie2::CGameEvent::GE_PLAYER_DIED:
      --m_NumLives;
      if ( m_NumLives == 0 )
      {
        // TODO - game over?
        ChangeState( "GSMenu" );
        return;
      }
      if ( !m_Level.Load( GR::IO::FileStream( theApp.AppPath( Misc::Format( "data/level%1%.dat" ) << m_dwLevel ).c_str() ) ) )
      {
        ChangeState( "GSMenu" );
      }
      else
      {
        StartLevel();
      }
      break;
    case Birdie2::CGameEvent::GE_UNIT_DELETED:
      if ( m_pBossUnit == GameEvent.pUnit )
      {
        m_pBossUnit = NULL;
      }
      break;
  }
}