//---------------------------
// Includes
//---------------------------
#include "StdAfx.h"
#include "resource.h"
#include "Archer.h"

#include "Painter.h"
#include "ResourceLoader.h"
#include "InputState.h"
#include "CollisionMesh.h"
#include "Image.h"
#include "TextFormat.h"
#include "Audio.h"

//---------------------------
// Defines
//---------------------------
//

//---------------------------
// Constructor & Destructor
//---------------------------
Archer::Archer(ResourceLoader* resourceLoaderPtr,const String& imagename,const String& arrowImage,int hitPoints)
:Enemy(resourceLoaderPtr,imagename,hitPoints)
{
	m_VCollisionMeshPtr->CreateRect((m_ImagePtr->GetWidth()/10)-22,8,4,m_ImagePtr->GetHeight()/8-8);
	m_HCollisionMeshPtr->CreateRect(0,9,50,m_ImagePtr->GetHeight()/8*2.0/3.0);
	m_Range = 500;
	m_ArrowPtr = new Arrow(resourceLoaderPtr,arrowImage,-5);
	m_DamageAmount = -1;
}

Archer::~Archer()
{
	delete m_VCollisionMeshPtr;
	delete m_HCollisionMeshPtr;
	SafeDelete(&m_ImagePtr);
	delete m_ArrowPtr;
}

void Archer::Paint(Painter *painterPtr, Matrix2D matView)
{
	//Draw the image
	int width = m_ImagePtr->GetWidth()/5;
	int height = m_ImagePtr->GetHeight()/8;

	switch(m_CurrentState)
	{
	case STATE_WAITING:
		switch(m_CurrentAnimationStep)
		{
		case 0:
			m_SpriteBox.Set(0,0,width,height);
			break;
		case 15:
			m_SpriteBox.Set(width,0,width*2,height);
			break;
		}
		break;
	case STATE_FALLING:
		m_SpriteBox.Set(width,height*2,width*2,height*3);
		break;
	case STATE_HEAVY_ATTACK:
		switch(m_CurrentAnimationStep)
		{
		case 0:
			m_SpriteBox.Set(width*2,height,width*3,height*2);
			break;
		case 35:
			m_SpriteBox.Set(width*2,height*0,width*3,height*1);
			break;
		case 48:
			m_SpriteBox.Set(width*3,height*0,width*4,height*1);
			break;
		case 51:
			m_SpriteBox.Set(width*4,height*0,width*5,height*1);
			break;
		case 54:
			m_SpriteBox.Set(width*0,height*1,width*1,height*2);
			break;
		case 57:
			m_SpriteBox.Set(width*1,height*1,width*2,height*2);
			break;
		}
		break;
	case STATE_HIT:
		switch(m_CurrentAnimationStep)
		{
		case 0:
			m_SpriteBox.Set(width*3,height*1,width*4,height*2);
			break;

		case 4: 
			m_SpriteBox.Set(width*4,height*1,width*5,height*2);
			break;

		case 8: 
			m_SpriteBox.Set(width*0,height*2,width*1,height*3);
			break;
		}
		break;

	case STATE_DYING:
		switch(m_CurrentAnimationStep)
		{
		case 0:
			m_SpriteBox.Set(width*4,height*4,width*5,height*5);
			break;

		case 10: 
			m_SpriteBox.Set(width*0,height*5,width*1,height*6);
			break;
		case 20: 
			m_SpriteBox.Set(width*1,height*5,width*2,height*6);
			break;

		case 30: 
			m_SpriteBox.Set(width*2,height*5,width*1,height*6);
			break;

		case 53: 
			m_SpriteBox.Set(width*3,height*5,width*4,height*6);
			break;

		case 76: 
			m_SpriteBox.Set(width*4,height*5,width*5,height*6);
			break;

		case 99: 
			m_SpriteBox.Set(width*0,height*6,width*1,height*7);
			break;

		case 122: 
			m_SpriteBox.Set(width*1,height*6,width*2,height*7);
			break;

		case 145: 
			m_SpriteBox.Set(width*2,height*6,width*3,height*7);
			break;
		}
		break;
	}
	painterPtr->SetTransformMatrix(m_MatWorld * matView);
	painterPtr->DrawImage(m_ImagePtr,0,0,m_SpriteBox);

	//Paint the arrow
	m_ArrowPtr->Paint(painterPtr, matView);

	//Draw the collisionMesh
	/*painterPtr->SetColor(0,0,255,127);
	painterPtr->SetTransformMatrix(matView);
	painterPtr->FillCollisionMesh(GetHCollisionMesh());
	painterPtr->FillCollisionMesh(GetVCollisionMesh());*/
	
}

void Archer::Tick(InputState *inputStatePtr)
{

}

void Archer::Tick(InputState *inputStatePtr, Hero *hero)
{
	DetermineReactionToHero(hero);
	m_Velocity.x = 0;

	//State logic
	switch(m_CurrentState)
	{
	case STATE_WAITING:
		if(m_CurrentAnimationStep == 30)
		{
			m_CurrentAnimationStep = 0;
		} else {
			++m_CurrentAnimationStep;
		}

		if(m_Attack)
		{
			++m_AttackTimer;
			// Wait a random time before attacking again
			if(m_AttackTimer > randomBetween(30,60))
			{
				if(m_ArrowPtr->ReadyToFire())
				{
					SetCurrentState(STATE_HEAVY_ATTACK);
					m_AttackTimer = -1;
				}
			}
		}

		if(!m_HitGround)
		{
			SetCurrentState(STATE_FALLING);
			m_AttackTimer = -1;
		}
		break;

	case STATE_FALLING:
		if(m_HitGround)
		{
			SetCurrentState(STATE_WAITING);
			CheckDead();
		}
		break;

	case STATE_HEAVY_ATTACK:
		if(m_CurrentAnimationStep == 35)
		{
			Fire();
		}
		if(m_CurrentAnimationStep == 60)
		{
			SetCurrentState(STATE_WAITING);
		} else {
			++m_CurrentAnimationStep;
		}
		break;

	case STATE_HIT:
		if(m_CurrentAnimationStep > 12)
		{
			SetCurrentState(STATE_WAITING);
			CheckDead();
		} else {
			if(m_HeadingRight)
			{
				m_Velocity.x = -m_Speed;
			} else {
				m_Velocity.x = m_Speed;
			}
			++m_CurrentAnimationStep;
		}
		break;

	case STATE_DYING:
		m_Velocity.x = 0;
		if(m_CurrentAnimationStep <= 240)
		{
			++m_CurrentAnimationStep;
		}
		break;
	}

	m_ArrowPtr->Tick(inputStatePtr,hero);
	//gebruik de GetDeltaTime methode van het InputState object om de tijd die verstreken is sinds laatste 
	//call van Tick te weten te komen. Die tijd wordt bijgehouden in de variabele dTime.
	double dTime = inputStatePtr->GetDeltaTime();

	//Bereken de nieuwe positie in functie van de snelheid en de valversnelling.
	SetPosition(m_Position + m_Velocity * dTime + m_Gravity*dTime*dTime/2);

	//Bereken de nieuwe velocity vector die door de versnelling is gewijzigd.
	m_Velocity += m_Gravity*dTime;

	//mirrors the image
	Matrix2D matTransform, matPosition;
	matPosition.SetAsTranslate(m_Position.x-30,m_Position.y);
	if(!m_HeadingRight)
	{
		Matrix2D matTranslate, matMirror;
		matMirror.SetAsScale(-1,1);
		Rect2D collisionbounds = m_HCollisionMeshPtr->GetBounds();
		matTranslate.SetAsTranslate(collisionbounds.MaxX - collisionbounds.MinX+30*2,0);
		matTransform = matMirror * matTranslate;
	}
	m_MatWorld = matTransform * matPosition;
}

void Archer::DetermineReactionToHero(Hero *hero)
{
	if(!m_dead)
	{
		Scalar diff = GetPosition().x - hero->GetPosition().x;

		//When the hero is within range of the archer, the enemy will start attacking him
		if(abs(diff) < m_Range)
		{
			if(diff > 0)
			{
				m_HeadingRight = false;
			} else {
				m_HeadingRight = true;
			}
			m_ArrowPtr->SetHeadingDirection(m_HeadingRight);

			if(m_CurrentState != STATE_FALLING && m_CurrentState != STATE_HIT && m_CurrentState != STATE_DYING)
			{
				m_Attack = true;
			} else {
				m_Attack = false;
			}
		} else {
			m_Attack = false;
		}

		Enemy::DetermineReactionToHero(hero);
		if(m_ArrowPtr->IsVisible())
		{
			hero->detectHealthChange(m_ArrowPtr->GetCollisionMesh(),m_DamageAmount);
		}
	}
}

void Archer::Fire()
{
	if(m_HeadingRight)
	{
		m_ArrowPtr->SetPosition(Point2D(m_Position.x + 67,m_Position.y+10));
	} else {
		m_ArrowPtr->SetPosition(Point2D(m_Position.x + 20,m_Position.y+10));
	}

	m_ArrowPtr->SetVisible(true);
	m_ArrowPtr->Fire();
}

Arrow *Archer::getArrow() const
{
	return m_ArrowPtr;
}
