//---------------------------
// Includes
//---------------------------
#include "StdAfx.h"
#include "resource.h"
#include "MovingEnemy.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
//---------------------------
MovingEnemy::MovingEnemy(ResourceLoader* resourceLoaderPtr,const String& imagename,int hitPoints)
:Enemy(resourceLoaderPtr,imagename,hitPoints)
,m_MovementDirection(STAND_STILL)
{
	m_WeaponCollisionMeshPtr = resourceLoaderPtr->GetCollisionMesh();
	m_WeaponCollisionMeshPtr->CreateRect(0,0,0,0);
}

MovingEnemy::~MovingEnemy()
{
}

void MovingEnemy::Tick(InputState *inputStatePtr)
{
}

void MovingEnemy::Tick(InputState *inputStatePtr, Hero *hero)
{
	DetermineReactionToHero(hero);

	//When the attack command is given, the attacTimer goes up. When attack is false, the attackTimer gets paused.
	if(m_Attack) ++m_AttackTimer;

	m_Velocity.x = 0;

	//Initialisation of the coordinates of the WeaponCollisionMesh
	double x =0;
	double y = 0;
	double width = 0;
	double height = 0;
	m_WeaponCollisionMeshPtr->CreateRect(x,y,width,height);

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

		if(m_MovementDirection == MOVE_LEFT)
		{
			if(!m_HitWall) {
				SetCurrentState(STATE_WALKING);
			}
			m_Velocity.x = -m_Speed;
			m_HeadingRight = false;
		}

		if(m_MovementDirection == MOVE_RIGHT)
		{
			if(!m_HitWall) {
				SetCurrentState(STATE_WALKING);
			}
			m_Velocity.x = m_Speed;
			m_HeadingRight = true;
		}

		if(!m_HitGround)
		{
			SetCurrentState(STATE_JUMPING);
		}

		if(m_Attack)
		{
			if( m_AttackTimer == 1)
			{
				SetCurrentState(STATE_LIGHT_ATTACK1);
			}else if(m_AttackTimer > ANIM_LATTACK*2 + randomBetween(20,60))
			{
				SetCurrentState(STATE_LIGHT_ATTACK1);
			}
		}

		CheckDead();
		break;
	
	case STATE_WALKING:

		// When the left arrow (VK_LEFT) is pressed, the x component of the velocity is -m_Speed.
		if(m_MovementDirection == MOVE_LEFT)
		{
				m_Velocity.x = -m_Speed;
				m_HeadingRight = false;
		}
		// When the right arrow (VK_RIGHT) is pressed, the x component of the velocity is m_Speed.
		if(m_MovementDirection == MOVE_RIGHT)
		{
			m_Velocity.x = m_Speed;
			m_HeadingRight = true;
		}
		//if the character is hitting a wall, he shouldn't move
		if(m_HitWall)
		{
			SetCurrentState(STATE_WAITING);
			m_CurrentAnimationStep = 1;
		} else {
			// animation code
			if(m_CurrentAnimationStep == 14)
			{
				m_CurrentAnimationStep = 0;
			} else {
				++m_CurrentAnimationStep;
			}

			//When the character is not hitting the ground, he is falling, which means he cannot jump
			if(m_Velocity.y > 120)
			{
				SetCurrentState(STATE_FALLING);
			} else {
				//When the enemy is walking on the ground, but the hero is too far removed from the enemy, the enemy will stop
				if(m_MovementDirection == STAND_STILL)
				{
					SetCurrentState(STATE_WAITING);
				}
			}
		}
		CheckDead();
		break;

	case STATE_JUMPING:
		if(m_HitGround)
		{
			SetCurrentState(STATE_WAITING);
			CheckDead();
		}
		break;
	case STATE_FALLING:
		if(m_HitGround)
		{
			SetCurrentState(STATE_WAITING);
			CheckDead();
		} else {
			if(m_HeadingRight)
			{
				if(m_MovementDirection == MOVE_RIGHT)
				{
					m_Velocity.x = m_Speed;
				} else {
					m_Velocity.x = m_Speed/2;
				}
			} else {
				if(m_MovementDirection == MOVE_LEFT)
				{
					m_Velocity.x = -m_Speed;
				} else {
					m_Velocity.x = -m_Speed/2;
				}
			}
		}
		break;
	case STATE_LIGHT_ATTACK1:
		if(m_CurrentAnimationStep == ANIM_LATTACK)
		{
			SetCurrentState(STATE_LIGHT_ATTACK2);
			//Sets amount of damage
			m_DamageAmount = -1;
			//WeaponCollisionMesh coordinaten
			x = m_HCollisionMeshPtr->GetBounds().GetMaxX();
			y = m_HCollisionMeshPtr->GetBounds().GetMinY();
			width = m_HCollisionMeshPtr->GetBounds().GetWidth()/2;
			height = m_HCollisionMeshPtr->GetBounds().GetHeight();
			m_WeaponCollisionMeshPtr->CreateRect(x,y,width,height);

			CheckDead();
		} else {
			++m_CurrentAnimationStep;
		}
		break;

	case STATE_LIGHT_ATTACK2:
		if(m_CurrentAnimationStep == ANIM_LATTACK)
		{
			if(m_AttackTimer > ANIM_LATTACK*5)
			{
				SetCurrentState(STATE_HEAVY_ATTACK);
			} else {
				SetCurrentState(STATE_WAITING);
			}

			//Sets amount of damage
			m_DamageAmount = -1;
			//WeaponCollisionMesh coordinaten
			x = m_HCollisionMeshPtr->GetBounds().GetMaxX();
			y = m_HCollisionMeshPtr->GetBounds().GetMinY();
			width = m_HCollisionMeshPtr->GetBounds().GetWidth()/2;
			height = m_HCollisionMeshPtr->GetBounds().GetHeight();
			m_WeaponCollisionMeshPtr->CreateRect(x,y,width,height);

			CheckDead();
		} else {
			++m_CurrentAnimationStep;
		}

		break;

	case STATE_HEAVY_ATTACK:
		if(m_CurrentAnimationStep == ANIM_HATTACK)
		{

			if(m_HeadingRight)
			{
				m_Velocity.x = m_Speed;
			} else {
				m_Velocity.x = -m_Speed;
			}

			SetCurrentState(STATE_WAITING);
			m_AttackTimer = -1;
			
			//Sets amount of damage
			m_DamageAmount = -2;
			//WeaponCollisionMesh coordinaten
			x = m_HCollisionMeshPtr->GetBounds().GetMaxX();
			y = m_HCollisionMeshPtr->GetBounds().GetMinY();
			width = m_HCollisionMeshPtr->GetBounds().GetWidth();
			height = m_HCollisionMeshPtr->GetBounds().GetHeight();
			m_WeaponCollisionMeshPtr->CreateRect(x,y,width,height);

			CheckDead();
		} else {
			++m_CurrentAnimationStep;
		}
		break;

	case STATE_BLOCKING:
		if(m_CurrentAnimationStep > 10)
		{
			SetCurrentState(STATE_WAITING);
			CheckDead();
		} 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;
	}

	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-10,m_Position.y);
	if(!m_HeadingRight)
	{
		Matrix2D matTranslate, matMirror;
		matMirror.SetAsScale(-1,1);
		Rect2D collisionbounds = m_HCollisionMeshPtr->GetBounds();
		matTranslate.SetAsTranslate(collisionbounds.MaxX - collisionbounds.MinX+10*2,0);
		matTransform = matMirror * matTranslate;

		//flip the weapon collisionmesh
		x = -(m_WeaponCollisionMeshPtr->GetBounds().GetMinX() - m_HCollisionMeshPtr->GetBounds().GetMinX()) + m_HCollisionMeshPtr->GetBounds().GetMaxX();
		y = m_WeaponCollisionMeshPtr->GetBounds().GetMinY();
		width = -m_WeaponCollisionMeshPtr->GetBounds().GetWidth();
		height = m_WeaponCollisionMeshPtr->GetBounds().GetHeight();
		m_WeaponCollisionMeshPtr->CreateRect(x,y,width,height);
	}
	m_MatWorld = matTransform * matPosition;
}

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

		//When the hero is within range of the enemy, the enemy will start walking towards him
		if(abs(diff) < m_Range)
		{
			if(diff > 0)
			{
				m_MovementDirection = MOVE_LEFT;
				m_HeadingRight = false;
			} else {
				m_MovementDirection = MOVE_RIGHT;
				m_HeadingRight = true;;
			}
		}

		//When the enemy reaches the Hero, the enemy will start attacking
		if(m_CurrentState != STATE_FALLING &&  m_CurrentState != STATE_JUMPING)
		{
			CollisionMesh *characterHMesh = hero->GetHCollisionMesh();
			if(characterHMesh->HitTest(m_HCollisionMeshPtr))
			{
				//m_CurrentState = STATE_LIGHT_ATTACK1;
				m_Attack = true;
				m_MovementDirection = STAND_STILL;
			} else {
				m_Attack = false;
			}
		}
		Enemy::DetermineReactionToHero(hero);
		hero->detectHealthChange(m_WeaponCollisionMeshPtr,m_DamageAmount);
	}
}
