#include ".\gamelogic.h"
#include ".\BirdiesRevenge.h"
#include ".\Birdie.h"
#include ".\Collectible.h"
#include ".\Unit.h"
#include ".\Level.h"
#include ".\Bubble.h"
#include ".\Bonus.h"
#include ".\Note.h"
#include ".\Points.h"



std::map<Birdie2::eUnitTypes, Birdie2::EnemyInfo>      GameLogic::EnemyInfos;



Unit* GameLogic::SpawnBonus( const GR::tPoint& Pos, const std::string& CaughtImage )
{
  Bonus*    pBonus = (Bonus*)Unit::FromType( Birdie2::UT_BONUS );

  pBonus->m_Position = Pos;
  pBonus->SetImage( CaughtImage );

  switch ( rand() % 4 )
  {
    case 0:
      pBonus->m_BonusImage = "Fruit.Melon";
      pBonus->m_Value = 100;
      break;
    case 1:
      pBonus->m_BonusImage = "Pudding";
      pBonus->m_Value = 200;
      break;
    case 2:
      pBonus->m_BonusImage = "Cake.1";
      pBonus->m_Value = 300;
      break;
    case 3:
      pBonus->m_MakeDiamond = true;
      pBonus->m_Value = 7000;
      break;
  }
  return pBonus;
}



Unit* GameLogic::SpawnExtra( Level& Level, const GR::tPoint& Pos )
{
  Collectible*   pExtra = (Collectible*)Level.SpawnUnit( Pos.x, Pos.y, Birdie2::UT_COLLECTIBLE );

  // TODO - Level settings!

  auto  item = ( Birdie2::eItems )( rand() % 5 );

  pExtra->m_Item = item;
  switch ( item )
  {
    case Birdie2::IT_GUN:
      pExtra->SetImage( "Item.Gun" );
      break;
    case Birdie2::IT_UZI:
      pExtra->SetImage( "Item.Uzi" );
      break;
    case Birdie2::IT_LAMP_1:
      pExtra->SetImage( "Item.Lamp.1" );
      break;
    case Birdie2::IT_LAMP_2:
      pExtra->SetImage( "Item.Lamp.2" );
      break;
    case Birdie2::IT_LAMP_3:
      pExtra->SetImage( "Item.Lamp.3" );
      break;
  }
  return pExtra;
}



Points* GameLogic::SpawnPoints( Level& Level, int X, int Y, int Value )
{
  auto pUnit = Level.SpawnUnit( X, Y, Birdie2::UT_POINTS );
  ( (Points*)pUnit )->m_Points = Misc::Format() << Value;

  Level.m_GameEventHandler( Birdie2::CGameEvent( Birdie2::CGameEvent::GE_CHANGE_SCORE, Value ) );

  return (Points*)pUnit;
}



GR::u32 GameLogic::UnitsCollide( Unit* pUnit1, Unit* pUnit2, Level& Level )
{
  switch ( pUnit1->m_Type )
  {
    case Birdie2::UT_NOTE:
      if ( ( !( (Note*)pUnit1 )->m_Rising )
      &&   ( pUnit2->m_IsNasty ) )
      {
        /*
        if ( pUnit2->m_DisplayHit )
        {
          Unit*    pPop = Unit::FromType( Birdie2::UT_POP );
          pPop->m_Position = pUnit1->m_Position;
          pPop->m_Position.offset( 12, 12 );

          Level.m_Units.push_back( pPop );

          pUnit1->m_RemoveMe = true;
          return 0;
        }*/

        if ( pUnit2->m_Type == Birdie2::UT_PUMPKIN )
        {
          theApp.SoundClass()->Play( theApp.Sound( "Boss.Hit" ) );
        }

        --pUnit2->m_HP;
        if ( pUnit2->m_HP <= 0 )
        {
          if ( pUnit2->m_Type == Birdie2::UT_PUMPKIN )
          {
            // explodes!
            Unit*   pPiece = Level.SpawnUnit( pUnit2->m_Position.x, pUnit2->m_Position.y, Birdie2::UT_PUMPKIN_PIECE );
            pPiece->m_Speed.set( -5, -5 );
            pPiece->SetImage( "Pumpkin.Mash.1" );
            pPiece = Level.SpawnUnit( pUnit2->m_Position.x, pUnit2->m_Position.y, Birdie2::UT_PUMPKIN_PIECE );
            pPiece->m_Speed.set( 5, -5 );
            pPiece->SetImage( "Pumpkin.Mash.3" );
            pPiece = Level.SpawnUnit( pUnit2->m_Position.x, pUnit2->m_Position.y, Birdie2::UT_PUMPKIN_PIECE );
            pPiece->m_Speed.set( -5, 5 );
            pPiece->SetImage( "Pumpkin.Mash.6" );
            pPiece = Level.SpawnUnit( pUnit2->m_Position.x, pUnit2->m_Position.y, Birdie2::UT_PUMPKIN_PIECE );
            pPiece->m_Speed.set( 5, 5 );
            pPiece->SetImage( "Pumpkin.Mash.8" );

            pPiece = Level.SpawnUnit( pUnit2->m_Position.x, pUnit2->m_Position.y, Birdie2::UT_PUMPKIN_PIECE );
            pPiece->m_Speed.set( -5, 0 );
            pPiece->SetImage( "Pumpkin.Mash.4" );
            pPiece = Level.SpawnUnit( pUnit2->m_Position.x, pUnit2->m_Position.y, Birdie2::UT_PUMPKIN_PIECE );
            pPiece->m_Speed.set( 5, 0 );
            pPiece->SetImage( "Pumpkin.Mash.5" );
            pPiece = Level.SpawnUnit( pUnit2->m_Position.x, pUnit2->m_Position.y, Birdie2::UT_PUMPKIN_PIECE );
            pPiece->m_Speed.set( 0, -5 );
            pPiece->SetImage( "Pumpkin.Mash.2" );
            pPiece = Level.SpawnUnit( pUnit2->m_Position.x, pUnit2->m_Position.y, Birdie2::UT_PUMPKIN_PIECE );
            pPiece->m_Speed.set( 0, 5 );
            pPiece->SetImage( "Pumpkin.Mash.7" );

            return 2;
          }
          else
          {
            Bubble*  pBubble = (Bubble*)Unit::FromType( Birdie2::UT_BUBBLE );

            pBubble->m_pCaughtUnit = pUnit2;
            pBubble->m_CaughtImage = EnemyInfos[pUnit2->m_Type].DeadImage;
            pBubble->m_Position = pUnit2->m_Position;

            int   size = 64;
            XTextureSection tsImage( theApp.Section( pBubble->m_CaughtImage ) );

            size = math::maxValue( tsImage.m_Width, size );
            size = math::maxValue( tsImage.m_Height, size );

            pBubble->m_MovementBounds.set( 12, 12, size - 24, size - 24 );
            pBubble->m_CollisionBounds.set( 12, 12, size - 24, size - 24 );

            pBubble->m_Position.offset( -( pBubble->MovementBounds().width() - pUnit2->MovementBounds().width() ) / 2,
              -( pBubble->MovementBounds().height() - pUnit2->MovementBounds().height() ) / 2 );
            //pBubble->m_Position.offset( -12, -12 );
            pBubble->m_TruePosition = pBubble->m_Position;
            pBubble->m_ptFracPos.set( ( GR::f32 )pBubble->m_Position.x, ( GR::f32 )pBubble->m_Position.y );


            pUnit2->ProcessEvent( Level, Unit::ET_GET_CAUGHT );

            pUnit1->m_RemoveMe = true;

            Level.m_Units.push_back( pBubble );
            return 2;
          }
        }
        else
        {
          Unit*    pPop = Unit::FromType( Birdie2::UT_POP );
          pPop->m_Position = pUnit1->m_Position;
          pPop->m_Position.offset( 12, 12 );

          Level.m_Units.push_back( pPop );

          pUnit1->m_RemoveMe = true;

          pUnit2->m_HitDisplayTime = 0.125f;
          pUnit2->m_DisplayHit = true;
        }
      }
      break;
    case Birdie2::UT_FLASH:
      if ( pUnit2->m_IsNasty )
      {
        pUnit2->m_RemoveMe = true;

        Unit* pBonus = GameLogic::SpawnBonus( pUnit2->m_Position + GR::tPoint( 12, 12 ), EnemyInfos[pUnit2->m_Type].DeadImage );
        Level.m_Units.push_back( pBonus );

        theApp.SoundClass()->Play( theApp.Sound( "Pop" ) );

        Level.m_GameEventHandler( Birdie2::CGameEvent( Birdie2::CGameEvent::GE_CHANGE_SCORE, 150 ) );
        return 2;
      }
      break;
    case Birdie2::UT_BIRDIE:
      if ( pUnit2->m_Type == Birdie2::UT_BUBBLE )
      {
        pUnit2->m_RemoveMe = true;

        Unit*    pPop = Unit::FromType( Birdie2::UT_POP );
        pPop->m_Position = pUnit2->m_Position;
        pPop->m_Position.offset( 12, 12 );

        Level.m_Units.push_back( pPop );

        Unit* pBonus = GameLogic::SpawnBonus( pUnit2->m_Position + GR::tPoint( 12, 12 ), ( (Bubble*)pUnit2 )->m_CaughtImage );

        Level.m_Units.push_back( pBonus );

        theApp.SoundClass()->Play( theApp.Sound( "Pop" ) );

        Level.m_GameEventHandler( Birdie2::CGameEvent( Birdie2::CGameEvent::GE_CHANGE_SCORE, 50 ) );
      }
      else if ( pUnit2->m_Type == Birdie2::UT_FLASH_BUBBLE )
      {
        pUnit2->m_RemoveMe = true;

        Unit*    pPop = Unit::FromType( Birdie2::UT_POP );
        pPop->m_Position = pUnit2->m_Position;
        pPop->m_Position.offset( 12, 12 );

        Level.m_Units.push_back( pPop );

        Unit* pFlash = Unit::FromType( Birdie2::UT_FLASH );

        pFlash->m_Position = pUnit2->m_Position;
        if ( pUnit1->m_Position.x > pUnit2->m_Position.x )
        {
          pFlash->m_FaceLeft = true;
        }
        Level.m_Units.push_back( pFlash );

        theApp.SoundClass()->Play( theApp.Sound( "Flash.Pop" ) );

        Level.m_GameEventHandler( Birdie2::CGameEvent( Birdie2::CGameEvent::GE_CHANGE_SCORE, 75 ) );
      }
      else if ( pUnit2->m_Type == Birdie2::UT_COLLECTIBLE )
      {
        theApp.SoundClass()->Play( theApp.Sound( "Collect" ) );
        GameLogic::ItemCollected( (Birdie*)pUnit1, (Collectible*)pUnit2, Level );
      }
      else if ( pUnit2->m_Type == Birdie2::UT_NOTE )
      {
        pUnit2->m_RemoveMe = true;

        Unit*    pPop = Unit::FromType( Birdie2::UT_POP );
        pPop->m_Position = pUnit2->m_Position;
        pPop->m_Position.offset( 12, 12 );

        Level.m_Units.push_back( pPop );

        theApp.SoundClass()->Play( theApp.Sound( "Pop" ) );

        Level.m_GameEventHandler( Birdie2::CGameEvent( Birdie2::CGameEvent::GE_CHANGE_SCORE, 10 ) );
      }
      else if ( ( pUnit2->m_IsNasty )
      ||        ( pUnit2->m_Type == Birdie2::UT_BOSS_SHOT ) )
      {
        // TOT
        Birdie*    pBirdie = (Birdie*)pUnit1;

        pBirdie->m_Dying = true;
        pBirdie->m_Floating = true;
        pBirdie->m_Jumping = false;

        pBirdie->SetAnimation( "Player.Dead" );

        if ( pBirdie->m_pOnUnit )
        {
          pBirdie->m_pOnUnit->m_CarriedUnits.remove( pBirdie );
          pBirdie->m_pOnUnit = NULL;
        }
        Level.m_DeathPause = 2.5f;
      }
      else if ( pUnit2->m_Type == Birdie2::UT_BONUS )
      {
        Bonus*   pBonus = (Bonus*)pUnit2;

        if ( pBonus->m_Done )
        {
          pUnit2->m_RemoveMe = true;

          // Punkte-Anzeige
          Level.m_GameEventHandler( Birdie2::CGameEvent( Birdie2::CGameEvent::GE_ITEM_COLLECTED, pBonus->m_BonusImage ) );

          SpawnPoints( Level, pBonus->MovementBounds().center().x, pBonus->MovementBounds().center().y, pBonus->m_Value );
          
          theApp.SoundClass()->Play( theApp.Sound( "Collect" ) );
        }
      }
      break;
  }
  return 0;

}



void GameLogic::ItemCollected( Birdie* pPlayer, Collectible* pItem, Level& Level )
{
  switch ( pItem->m_Item )
  {
    case Birdie2::IT_GUN:
      pPlayer->m_Gun = true;
      pPlayer->m_Uzi = false;
      pPlayer->SetAnimation( "Player.WalkGun" );
      SpawnPoints( Level, pItem->m_Position.x, pItem->m_Position.y, 100 );
      break;
    case Birdie2::IT_UZI:
      pPlayer->m_Gun = false;
      pPlayer->m_Uzi = true;
      pPlayer->SetAnimation( "Player.WalkUzi" );
      SpawnPoints( Level, pItem->m_Position.x, pItem->m_Position.y, 100 );
      break;
    case Birdie2::IT_LAMP_1:
      pPlayer->m_FastNotes = true;
      SpawnPoints( Level, pItem->m_Position.x, pItem->m_Position.y, 1000 );
      break;
    case Birdie2::IT_LAMP_2:
      pPlayer->m_FartherNotes = true;
      SpawnPoints( Level, pItem->m_Position.x, pItem->m_Position.y, 1000 );
      break;
    case Birdie2::IT_LAMP_3:
      pPlayer->m_SmallerFireDelay = true;
      SpawnPoints( Level, pItem->m_Position.x, pItem->m_Position.y, 1000 );
      break;
  }
  pItem->m_RemoveMe = true;
}



bool GameLogic::CanUnitStandOnPlatform( Unit& Unit )
{
  if ( Unit.m_Type == Birdie2::UT_BIRDIE )
  {
    return true;
  }
  return false;
}