#include "EntPlayer.h"
#include "MyEntityManager.h"
#include "GameLogic.h"

#define C_BOAT_MAX_HEALTH 10

EntPlayer::EntPlayer()
{
   m_sprite = NULL;
   m_spriteMoving = NULL;
   m_spriteIdle = NULL;
   m_spriteLastUsed = NULL;
   ResetKeys();
   m_SlotKeyUp = CL_Keyboard::sig_key_up().connect( this, &EntPlayer::OnKeyUp);
   m_SlotKeyDown = CL_Keyboard::sig_key_down().connect( this, &EntPlayer::OnKeyDown);
 
   m_boatMaxSpeed = 2;
   m_boatPower = 0.04f;
   m_turnSpeed = 0.07f;
   SetSort(2500); //draw after the beam draws
   m_vPosition = CL_Vector2(GetScreenX/2, 100);
   m_health = C_BOAT_MAX_HEALTH;
   SetType(C_TYPE_BOAT);
    m_bHandledDeath = false;
   if (!Init()) throw ("Error initting player");
   m_shieldTimer = 0;

}
 
int EntPlayer::GetHealthPercent()
{
    return (float(m_health)/float(C_BOAT_MAX_HEALTH))*100;

}


void EntPlayer::RepairHull()
{
    m_health += 5;
    if (m_health > C_BOAT_MAX_HEALTH) m_health = C_BOAT_MAX_HEALTH;
}

EntPlayer::~EntPlayer()
{
    SAFE_DELETE(m_sprite);
    SAFE_DELETE(m_spriteMoving);
    SAFE_DELETE(m_spriteIdle);
    
}

void EntPlayer::ResetKeys()
{
    m_Keys = 0; 

}

bool EntPlayer::Init()
{
    //setup stuff
 
    m_spriteMoving = new CL_Sprite("boat_move", GetApp()->GetResourceManager());
    m_spriteIdle = new CL_Sprite("boat_idle", GetApp()->GetResourceManager());

    m_sprite = new CL_Sprite();


    if (!m_sprite) CL_Error("Unable to load crayon sprite");
   
    SetSpriteData(m_spriteMoving);
    m_sprite->set_alignment(origin_center);
    m_sprite->set_rotation_hotspot(origin_center);
    
    return true; //success
}



void EntPlayer::OnKeyDown(const CL_InputEvent &key)
{
    switch(key.id)
    {
    case CL_KEY_LEFT:
       m_Keys |= C_KEY_LEFT;
       break;

    case CL_KEY_RIGHT:
        m_Keys |= C_KEY_RIGHT;
        break;

    case CL_KEY_UP:
        m_Keys |= C_KEY_UP;
        break;

    case CL_KEY_DOWN:
        m_Keys |= C_KEY_DOWN;
        break;

    }

}

void EntPlayer::OnKeyUp(const CL_InputEvent &key)
{
    switch(key.id)
    {
    case CL_KEY_LEFT:
        m_Keys &= ~C_KEY_LEFT;
        break;
        
    case CL_KEY_RIGHT:
        m_Keys &= ~C_KEY_RIGHT;
        break;
        
    case CL_KEY_UP:
        m_Keys &= ~C_KEY_UP;
        break;
        
    case CL_KEY_DOWN:
        m_Keys &= ~C_KEY_DOWN;
        break;
        
    }
    
}


void EntPlayer::Render()
{
    m_sprite->set_alpha(m_alpha);
    m_sprite->set_scale(m_vScale.x, m_vScale.y);
    m_sprite->draw(m_vPosition.x, m_vPosition.y);
      
}

void EntPlayer::SetSpriteData(CL_Sprite *pSprite)
{
    if (m_spriteLastUsed != pSprite)
    {
    
     m_sprite->set_image_data(*pSprite);
     m_spriteLastUsed = pSprite;
    }

}
void EntPlayer::UpdateMovement(float step)
{
 
    float power = 0;
    CL_Vector2 vBoatEngine(0,0);

    if (m_Keys & C_KEY_UP)
    {
       power = m_boatPower;    
    }

    if (m_Keys & C_KEY_DOWN)
    {
        power = -m_boatPower;    
    }

    if (m_Keys & C_KEY_LEFT)
    {
        m_vHeading += -(Vector2Perp(m_vHeading)*(m_turnSpeed*step));
    }

    if (m_Keys & C_KEY_RIGHT)
    {
        m_vHeading += Vector2Perp(m_vHeading)*(m_turnSpeed*step);
    }

    if (m_health == 0)
    {
        power = 0; //boat damaged
    }

    vBoatEngine = m_vHeading * power;
    m_vVelocity += vBoatEngine;

    if (power == 0)
    {
        //apply some brakes
        m_vVelocity *= 0.90f;
    }

    Vector2Truncate(m_vVelocity, m_boatMaxSpeed);


    CL_Vector2 vAttemptedPos = m_vPosition + m_vVelocity*step;
    

   Entity *pEnt = GetMyEntityMgr->TouchedEntity(C_TYPE_OBSTACLE, vAttemptedPos, 10);

   if (pEnt)
   {
       m_vVelocity *= -1;
       OnCrash(1);
 
   }

   if ( (vAttemptedPos- CL_Vector2(GetScreenX/2, GetScreenY/2)).length() < 80)
   {
       //hit the island
       m_vVelocity *= -1;
       OnCrash(1);

   }



    CL_Rect rect(0,0, GetScreenX, GetScreenY);
    if (!rect.is_inside(CL_Point(vAttemptedPos.x, vAttemptedPos.y)))
    {
        //we stepped out of bounds
        m_vVelocity *= -1;
    }

    
    //last minute emgerency check
    vAttemptedPos = m_vPosition + m_vVelocity*step;

    if (!rect.is_inside(CL_Point(vAttemptedPos.x, vAttemptedPos.y)))
     {
       m_vVelocity = CL_Vector2(0,0);
    }

    
    //actually move it
    m_vPosition += m_vVelocity*step;

    if (m_vVelocity.length() > 0.3)
    {
        //moving!
        SetSpriteData(m_spriteMoving);
    } else
    {
        SetSpriteData(m_spriteIdle);
    }

}

void EntPlayer::OnCrash(int damage)
{
    if (m_shieldTimer > CL_System::get_time()) return; //we just hit something else, give the guy
    //a break
    
    m_shieldTimer = CL_System::get_time() + 3000;
    m_health -= damage;
    GetGameLogic->GetMessageDispatcher()->SendMsg(C_MESSAGE_SOUND, 0, NULL, C_SOUND_CRASH);

}

void EntPlayer::Update(float step)
{
    Entity::Update(step);

    if (m_health > 0)
    {
         if (m_shieldTimer> CL_System::get_time())
        {
            //can't be hurt right now
            m_alpha = 0.5f;
        }   else
        {
            m_alpha = 1;
        }
    }


    if (GetGameLogic->m_bSuspended) return;

    if (m_health <= 0 && !m_bHandledDeath)
    {
        m_health = 0;
        m_bHandledDeath = true;
        GetGameLogic->GetMessageDispatcher()->SendText("Patrol boat sunk!", 1000);
        GetGameLogic->GetMessageDispatcher()->SendMsg(C_MESSAGE_GAME_OVER, 3000);
        m_bScaleToNothing = true;
        m_bFadeAlphaTo = true;
    }

    if (step == 0) return; //paused

    //Calculate the steering force and update the bot's velocity and position
     UpdateMovement(step);
     



     Entity *pEnt = GetMyEntityMgr->TouchedEntity(C_TYPE_SWIMMER, m_vPosition, GetRadius());

     if (pEnt)
     {
         GetGameLogic->GetMessageDispatcher()->SendMsg(C_MESSAGE_GOT_RESCUED, 10, pEnt);
     }


     float angle = PI - atan2(m_vHeading.x, m_vHeading.y);
     m_sprite->set_angle(RADTODEG*angle);
     m_sprite->update();
}