#include "Player.h"
#include "Level.h"
#include "GetEmGood.h"
#include "PlayState.h"
#include "GameLogic.h"



Player::Player() :
  m_Moving( false ),
  m_FireDelay( 0 ),
  m_FireDelayMax( 15 ),
  m_BulletPower( 1 ),
  m_SlowDown( 0 )
{
  m_PlayerIndex = 0;
  m_Type = Pac::UT_PLAYER;
  SetAnim();
  m_MoveDir = Pac::DIR_NONE;
  m_ShootDir = Pac::DIR_S;
  m_MoveSpeed = 8;

  m_Invincibility   = 300;
  m_DisplayBlinkingFast = true;

  m_DisplayOffset.set( -( 48 - 16 ) / 2, -( 21 - 16 ) / 2 - 18 );
}



void Player::SetAnim()
{
  if ( !m_Moving )
  {
    SetAnimation( Misc::Format( "Player.%1%.Stand" ) << m_PlayerIndex + 1 );
  }
  else
  {
    SetAnimation( Misc::Format( "Player.%1%.Move" ) << m_PlayerIndex + 1 );
  }
}



void Player::UpdateFixed( PlayState& State )
{
  int     origMoveSpeed = m_MoveSpeed;

  if ( m_SlowDown > 0 )
  {
    if ( m_MoveSpeed < 4 )
    {
      m_MoveSpeed = 1;
    }
    else
    {
      m_MoveSpeed -= 4;
    }
  }

  TiledMover::UpdateFixed( State );

  if ( m_SlowDown > 0 )
  {
    m_MoveSpeed = origMoveSpeed;
    --m_SlowDown;
  }

  if ( m_FireDelay > 0 )
  {
    --m_FireDelay;
  }
  if ( theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::ACTION] ) )
  {
    if ( m_FireDelay == 0 )
    {
      m_FireDelay = m_FireDelayMax;
      FireShot( State );
    }
  }
}



void Player::OnArrivedAtTile( PlayState& State )
{
  if ( ( State.Level.m_Field.Field( m_TilePos.x, m_TilePos.y ) == Pac::FT_LOCK )
  &&   ( m_HasKey ) )
  {
    GameLogic::LevelCompleted( State );
  }

  if ( State.Level.m_Field.Field( m_TilePos.x, m_TilePos.y ) == Pac::FT_DOT )
  {
    State.TicksSinceLastDot = 0;
    State.Level.m_Field.SetField( m_TilePos.x, m_TilePos.y, Pac::FT_EMPTY );
    GameLogic::DecreaseNumberOfDots( State );
    ++State.Score;

    theApp.SoundClass()->Play( theApp.Sound( "Eat.Dot" ) );
  }
  else if ( ( State.Level.m_Field.Field( m_TilePos.x, m_TilePos.y ) >= Pac::FT_EXTRA_BULLET_POWER )
  &&        ( State.Level.m_Field.Field( m_TilePos.x, m_TilePos.y ) <= Pac::FT_EXTRA_TIME ) )
  {
    GameLogic::ExtraPickedUp( State, m_TilePos, m_PlayerIndex );
    State.Level.m_Field.SetField( m_TilePos.x, m_TilePos.y, Pac::FT_EMPTY );
  }
  TiledMover::OnArrivedAtTile( State );
}



void Player::FireShot( PlayState& State )
{
  if ( m_ShootDir == Pac::DIR_NONE )
  {
    dh::Log( "Can't shoot without dir!" );
    return;
  }
  GR::tPoint      pos( m_Position );

  Unit*   pShot = State.Level.SpawnUnit( pos.x, pos.y, Pac::UT_PLAYER_SHOT, m_PlayerIndex );

  switch ( m_ShootDir )
  {
    case Pac::DIR_E:
      pShot->SetImage( "PlayerShot.R" );
      break;
    case Pac::DIR_W:
      pShot->SetImage( "PlayerShot.L" );
      break;
    case Pac::DIR_N:
      pShot->SetImage( "PlayerShot.U" );
      break;
    case Pac::DIR_S:
      pShot->SetImage( "PlayerShot.D" );
      break;
  }

  pShot->m_MoveDir      = m_ShootDir;
  pShot->m_HP           = m_BulletPower;
  theApp.SoundClass()->Play( theApp.Sound( "Player.Shoot" ) );
}



void Player::Update( PlayState& State, const GR::f32 ElapsedTime )
{
  Unit::Update( State, ElapsedTime );

  if ( !theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::ACTION] ) )
  {
    if ( m_MoveDir != Pac::DIR_NONE )
    {
      m_ShootDir = m_MoveDir;
    }
  }

  CheckControls( State );
}



void Player::ProcessEvent( PlayState& State, const eUnitEvent& Event )
{
  TiledMover::ProcessEvent( State, Event );

  switch ( Event )
  {
    case ET_BLOCKED_UP:
      break;
    case ET_FALL_START:
      break;
    case ET_FALL_END:
      break;
    case ET_ENTER_PLATFORM:
      break;
    case ET_LEAVE_PLATFORM:
      break;
    case ET_DIE:
      break;
    case ET_MOVED_DOWN:
    case ET_MOVED_LEFT:
    case ET_MOVED_RIGHT:
    case ET_MOVED_UP:
      CheckControls( State );
      break;
  }
}



void Player::OnLoad( PlayState& State )
{
  m_StartPosition = m_Position;
}



void Player::CheckControls( PlayState& State )
{
  {
    bool    overriddenMove = false;
    if ( theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::LEFT] ) )
    {
      if ( m_Position.y % 16 == 0 )
      {
        if ( State.Level.CanMove( this, m_TilePos, Pac::DIR_W ) )
        {
          m_MoveDir = Pac::DIR_W;
          m_Moving = true;
          SetAnim();
          overriddenMove = true;
        }
        if ( !theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::ACTION] ) )
        {
          m_ShootDir = Pac::DIR_W;
        }
      }
    }
    if ( theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::RIGHT] ) )
    {
      if ( m_Position.y % 16 == 0 )
      {
        if ( State.Level.CanMove( this, m_TilePos, Pac::DIR_E ) )
        {
          m_MoveDir = Pac::DIR_E;
          m_Moving = true;
          SetAnim();
          overriddenMove = true;
        }
        if ( !theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::ACTION] ) )
        {
          m_ShootDir = Pac::DIR_E;
        }
      }
    }
    if ( theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::UP] ) )
    {
      if ( m_Position.x % 16 == 0 )
      {
        if ( State.Level.CanMove( this, m_TilePos, Pac::DIR_N ) )
        {
          m_MoveDir = Pac::DIR_N;
          m_Moving = true;
          SetAnim();
          overriddenMove = true;
        }
        if ( !theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::ACTION] ) )
        {
          m_ShootDir = Pac::DIR_N;
        }
      }
    }
    if ( theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::DOWN] ) )
    {
      if ( m_Position.x % 16 == 0 )
      {
        if ( State.Level.CanMove( this, m_TilePos, Pac::DIR_S ) )
        {
          m_MoveDir = Pac::DIR_S;
          m_Moving = true;
          SetAnim();
          overriddenMove = true;
        }
        if ( !theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::ACTION] ) )
        {
          m_ShootDir = Pac::DIR_S;
        }
      }
    }
    if ( !overriddenMove )
    {
      AutoDetectDirection( State );
    }
  }
  //else
  {
    // while in movement only allow turning back
    if ( ( ( m_MoveDir == Pac::DIR_E )
           || ( m_NotMoving ) )
         && ( theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::LEFT] ) ) )
    {
      TurnAround();
      if ( !theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::ACTION] ) )
      {
        m_ShootDir = m_MoveDir;
      }
    }
    if ( ( ( m_MoveDir == Pac::DIR_W )
           || ( m_NotMoving ) )
         && ( theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::RIGHT] ) ) )
    {
      TurnAround();
      if ( !theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::ACTION] ) )
      {
        m_ShootDir = m_MoveDir;
      }
    }
    if ( ( m_MoveDir == Pac::DIR_N )
         && ( theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::DOWN] ) ) )
    {
      TurnAround();
      if ( !theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::ACTION] ) )
      {
        m_ShootDir = m_MoveDir;
      }
    }
    if ( ( m_MoveDir == Pac::DIR_S )
         && ( theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::UP] ) ) )
    {
      TurnAround();
      if ( !theApp.InputClass()->VKeyPressed( theApp.m_BoundKeys[m_PlayerIndex][Pac::ControlKey::ACTION] ) )
      {
        m_ShootDir = m_MoveDir;
      }
    }
    SetAnim();
  }
}