#include <cmath>
#define ALLEGRO_FIX_H
#include <allegro.h>
#include <winalleg.h>
#include "erkMap.h"
#include <algorithm>

erkTile::erkTile() :
	m_pType(NULL),
	m_bLit(false),
	m_dwNeighbourType(0),
	m_dwHealth(0)
{
	m_pvNeighbours[ET_N_NORTH] =
	m_pvNeighbours[ET_N_EAST] =
	m_pvNeighbours[ET_N_SOUTH] =
	m_pvNeighbours[ET_N_WEST] = NULL;
	m_pvCommand[0] = m_pvCommand[1] = NULL;
}

erkTile::~erkTile()
{
}

void erkTile::Draw(BITMAP* pDest, gbInt dwX, gbInt dwY)
{
	if(m_pType)
	{
		if(m_bLit)
		{
			BITMAP* pBmp = m_pType->GetLit();
			if(pBmp)
			{
				draw_sprite(pDest, pBmp, dwX, dwY);
			}
		}
		else
		{
			BITMAP* pBmp = m_pType->GetUnlit(m_dwNeighbourType);
			if(pBmp)
			{
				draw_sprite(pDest, pBmp, dwX, dwY);
			}
		}
	}
}

void erkTile::DrawUnits(BITMAP* pDest, gbInt dwX, gbInt dwY)
{
	dwX += EM_TILE_SIZE/2;
	dwY += EM_TILE_SIZE/2;

	for(gbLinkListIter(erkUnit_p) iPos=m_pvUnits.begin(); iPos!=m_pvUnits.end(); ++iPos)
	{
			(*iPos)->Draw(pDest, dwX, dwY);
	}

/*	if(m_pType  &&  !m_pType->IsSolid())
	{
		gbInt dwRad = m_dwHealth*EM_TILE_SIZE/(ET_HEALTH*6);
		if(m_bLit)
		{
			circlefill(pDest, dwX, dwY, dwRad, makecol(255, 0, 0));
		}
		else
		{
			circlefill(pDest, dwX, dwY, dwRad, makecol(0, 0, 255));
		}

		gbFloat fAngle = m_dwHealth/256.0f;
		line(pDest, (int)(dwX-sin(fAngle)*dwRad), (int)(dwY-cos(fAngle)*dwRad), (int)(dwX+sin(fAngle)*dwRad), (int)(dwY+cos(fAngle)*dwRad), 0);
	}*/

	if(m_pvCommand[0])
	{
		m_pvCommand[0]->Draw(pDest, dwX, dwY+1);
	}
	if(m_pvCommand[1])
	{
		m_pvCommand[1]->Draw(pDest, dwX, dwY-1);
	}
}

void erkTile::Update()
{
	m_dwvTeamCounts[0] = m_dwvTeamCounts[1] = 0;
	for(int lp=0; lp<EU_UT_COUNT*2; lp++)
		m_dwvUnitCounts[lp] = 0;

	gbInt dwvTileCounts[2] = { 0, 0 };
	for(gbLinkListIter(erkUnit_p) iPos=m_pvUnits.begin(); iPos!=m_pvUnits.end(); ++iPos)
	{
		if((*iPos)->GetSide())
		{
			m_dwvTeamCounts[1] += eu_dwvDamage[(*iPos)->GetType()];
			dwvTileCounts[1] += eu_dwvTileDamage[(*iPos)->GetType()];
			m_dwvUnitCounts[(*iPos)->GetType()+EU_UT_COUNT];
		}
		else
		{
			m_dwvTeamCounts[0] += eu_dwvDamage[(*iPos)->GetType()];
			dwvTileCounts[0] += eu_dwvTileDamage[(*iPos)->GetType()];
			m_dwvUnitCounts[(*iPos)->GetType()];
		}
	}

	gbInt dwRedDamage = m_dwvTeamCounts[0]/4;
	gbInt dwBlueDamage = m_dwvTeamCounts[1]/4;

	if(m_dwvTeamCounts[1])
	{
		dwBlueDamage = MAX(4, dwBlueDamage);
		for(gbLinkListIter(erkUnit_p) iPos=m_pvUnits.begin(); iPos!=m_pvUnits.end(); ++iPos)
		{
			if(!(*iPos)->GetSide())
			{
				(*iPos)->DecHealth(dwBlueDamage);
			}
		}
	}
	if(m_dwvTeamCounts[0])
	{
		dwRedDamage = MAX(4, dwRedDamage);
		for(gbLinkListIter(erkUnit_p) iPos=m_pvUnits.begin(); iPos!=m_pvUnits.end(); ++iPos)
		{
			if((*iPos)->GetSide())
			{
				(*iPos)->DecHealth(dwRedDamage);
			}
		}
	}

	if(m_pType)
	{
		m_pType->Update(this);
	}
	if(m_pvCommand[0])
	{
		m_pvCommand[0]->Update();
	}
	if(m_pvCommand[1])
	{
		m_pvCommand[1]->Update();
	}

	if(m_bLit)
	{
		if(dwvTileCounts[1])
			IncHealth(dwvTileCounts[1]);
		if(dwvTileCounts[0])
			DecHealth(dwvTileCounts[0]);
	}
	else
	{
		if(dwvTileCounts[0])
			IncHealth(dwvTileCounts[0]);
		if(dwvTileCounts[1])
			DecHealth(dwvTileCounts[1]);
	}
}

void erkTile::SetType(erkTileType_p pType)
{
	m_pType = pType;
}

void erkTile::SetLit(gbBool bLit)
{
	if(bLit != m_bLit  &&  m_pvCommand[m_bLit?1:0])
	{
		delete m_pvCommand[0];
		m_pvCommand[0] = NULL;

		delete m_pvCommand[1];
		m_pvCommand[1] = NULL;
	}

	m_bLit = bLit;

// Update the neighbours
	if(m_pvNeighbours[0])
		m_pvNeighbours[0]->CheckNeighbours();
	if(m_pvNeighbours[1])
		m_pvNeighbours[1]->CheckNeighbours();
	if(m_pvNeighbours[2])
		m_pvNeighbours[2]->CheckNeighbours();
	if(m_pvNeighbours[3])
		m_pvNeighbours[3]->CheckNeighbours();
}

void erkTile::CheckNeighbours()
{
	m_dwNeighbourType = 0;
	if(m_pvNeighbours[0]  &&  m_pvNeighbours[0]->m_bLit)
		m_dwNeighbourType += 0x1;
	if(m_pvNeighbours[1]  &&  m_pvNeighbours[1]->m_bLit)
		m_dwNeighbourType += 0x2;
	if(m_pvNeighbours[2]  &&  m_pvNeighbours[2]->m_bLit)
		m_dwNeighbourType += 0x4;
	if(m_pvNeighbours[3]  &&  m_pvNeighbours[3]->m_bLit)
		m_dwNeighbourType += 0x8;
}

void erkTile::SetNeighbour(gbInt dwDirection, erkTile* pTile)
{
	m_pvNeighbours[MID(0, dwDirection, 3)] = pTile;
}

erkTile* erkTile::GetNeighbour(gbInt dwDirection)
{
	return m_pvNeighbours[MID(0, dwDirection, 3)];
}

void erkTile::AddUnit(erkUnit_p pUnit)
{
	m_pvUnits.push_back(pUnit);
	pUnit->SetTile(this);
}

void erkTile::MoveUnit(erkUnit_p pUnit, gbInt dwDirection)
{
	gbLinkListIter(erkUnit_p) iPos = std::find(m_pvUnits.begin(), m_pvUnits.end(), pUnit);
	if(iPos == m_pvUnits.end())
		return;

	erkTile_p pNeighbour = GetNeighbour(dwDirection);
	if(pNeighbour)
	{
		pNeighbour->AddUnit(pUnit);
		m_pvUnits.erase(iPos);
	}
}

void erkTile::RemoveUnit(erkUnit_p pUnit)
{
	gbLinkListIter(erkUnit_p) iPos = std::find(m_pvUnits.begin(), m_pvUnits.end(), pUnit);
	if(iPos == m_pvUnits.end())
		return;

	m_pvUnits.erase(iPos);
}

gbBool erkTile::IsSolid()
{
	return m_pType?m_pType->IsSolid():true;
}

gbBool erkTile::IsLit()
{
	return m_bLit;
}

void erkTile::DecHealth(gbInt dwAmount)
{
	m_dwHealth -= dwAmount;
	if(m_dwHealth <= 0)
	{
		m_dwHealth = ET_HEALTH/2;
		SetLit(!m_bLit);
	}
}

void erkTile::IncHealth(gbInt dwAmount)
{
	m_dwHealth = MIN(ET_HEALTH, m_dwHealth+dwAmount);
}

void erkTile::SetHealth(gbInt dwHealth)
{
	m_dwHealth = dwHealth;
}

gbInt erkTile::GetHealth()
{
	return m_dwHealth;
}
