/**
 * \file PlaygroundStatistics.cpp
 * \date 06.03.2005
 * \author Marian Tines
 *
 * Implementation of the PlaygroundStatistics class
 */


#include "Coach/PlaygroundStatistics.h"
#include "Common/World/Point.h"
#include "Common/Support/Debug.h"
#include <math.h>
#include <iostream>
#include <direct.h>

using namespace std;

// Construction and destruction
PlaygroundStatistics::PlaygroundStatistics(int xZoneNumber, int yZoneNumber)
{
	this->xZoneNumber = xZoneNumber;
	this->yZoneNumber = yZoneNumber;
	this->xZoneLength = X_LENGTH / xZoneNumber;
	this->yZoneLength = Y_LENGTH / yZoneNumber;
	this->zoneStatistic = new SquareZoneStatistic[xZoneNumber * yZoneNumber];

	for (int y = 0; y < yZoneNumber; y++)
		for (int x = 0; x < xZoneNumber; x++)
			zoneStatistic[y * xZoneNumber + x].Reset();
}

PlaygroundStatistics::~PlaygroundStatistics()
{
	if (zoneStatistic != NULL)
	{
		delete zoneStatistic;
		zoneStatistic = NULL;
	}
}

const SquareZoneStatistic* PlaygroundStatistics::GetSquareZoneStatistic(int xIndex, int yIndex) const
{
	if (zoneStatistic == NULL || xIndex < 0 || xIndex >= xZoneNumber || yIndex < 0 || yIndex >= yZoneNumber)
		return NULL;

	return &zoneStatistic[yIndex * xZoneNumber + xIndex];
}

// Serialization of the class
void PlaygroundStatistics::SerializeYourself(std::ofstream &fs)
{
	for (int y = 0; y < yZoneNumber; y++)
		for (int x = 0; x < xZoneNumber; x++)
		{
			zoneStatistic[y * xZoneNumber + x].SerializeYourself(fs);
			fs << endl;
		}

		fs.flush();
}

// Deserialization of the class
void PlaygroundStatistics::DeserializeYourself(std::ifstream &fs)
{
	for (int y = 0; y < yZoneNumber; y++)
		for (int x = 0; x < xZoneNumber; x++)
			zoneStatistic[y * xZoneNumber + x].DeserialileYourself(fs);
}

// Serialize class to the specified file
void PlaygroundStatistics::SerializeYourself(char *fileName, char *path)
{
	// Create directory "path" if it does not exist
#ifdef _MSC_VER
	(void) _mkdir(path);
#else // _MSC_VER
	(void) mkdir(path, 0755);
#endif // _MSC_VER

	// store informations about movable objects position density to the file
	int len = strlen(fileName) + strlen(path) + 2;
	char *buffer = new char[len];
	sprintf(buffer, "%s/%s", path, fileName);
	std::ofstream *fs = new std::ofstream(buffer);
	delete buffer;
	buffer = NULL;

	SerializeYourself(*fs);
	fs->flush();
	fs->close();
	delete fs;
	fs = NULL;
}

// Gets the index of the square zone which contains specified point
int PlaygroundStatistics::GetZoneIndex(float x, float y)
{
	int xIndex = (int)ceil((x + X_LENGTH/2) / xZoneLength);
	int yIndex = (int)ceil((y + Y_LENGTH/2)/ yZoneLength);

	if (xIndex >= xZoneNumber || yIndex >= yZoneNumber)
		DBGN("Identified zone [%i, %i] is out of range [%i, %i] (on PlaygroundStatistics::GetZoneIndex)", xIndex, yIndex, xZoneNumber - 1, yZoneNumber - 1);

	if (xIndex < 0 || yIndex < 0)
		DBGN("Identified zone [%i, %i] is out of range [%i, %i] (on PlaygroundStatistics::GetZoneIndex)", xIndex, yIndex, xZoneNumber - 1, yZoneNumber - 1);

	// the index can not point outisde the playground
	xIndex = (xIndex < 0) ? 0 : xIndex;
	xIndex = (xIndex >= xZoneNumber) ? xZoneNumber - 1 : xIndex;
	yIndex = (yIndex < 0) ? 0 : yIndex;
	yIndex = (yIndex >= yZoneNumber) ? yZoneNumber - 1 : yIndex;

	return xIndex + yIndex * xZoneNumber;
}

#ifndef MOVABLE_OBJECT_DENSITY
// Updates statistics for the zones according to received visual info
void PlaygroundStatistics::OnReceiveVisualInfo(const COACH_VISUAL_INFO& vi)
{
	int		i;
	Point	actPos; // position of the actual processed player

	for (i = 0; i < vi.oursCount; i++)
	{
		// Ignore goalie position
		if (vi.ours[i].goalie)
			continue;

		actPos = vi.ours[i].pos;

		zoneStatistic[GetZoneIndex(actPos.GetX(), actPos.GetY())].IncFriendPlayerInTheZone();
	}

	for (i = 0; i < vi.theirCount; i++)
	{
		// Ignore goalie position
		if (vi.their[i].goalie)
			continue;

		actPos = vi.their[i].pos;

		zoneStatistic[GetZoneIndex(actPos.GetX(), actPos.GetY())].IncEnemyPlayerInTheZone();
	}

	zoneStatistic[GetZoneIndex(vi.ball.pos.GetX(), vi.ball.pos.GetY())].IncBallInTheZone();
}
#endif // MOVABLE_OBJECT_DENSITY


///////////////////////////////////////////////////////////////////////////////////
// Impelmentation of the BitPlaygroundObjectStat class

// Gets bits value indicating the statistics of the occupation of the specified playground field
bool BitPlaygroundObjectStat::GetBitPlaygroundStat(int xIndex, int yIndex)
{
	// coordinates out of the playground
	if (xIndex < 0 || xIndex >= xZoneNumber || yIndex < 0 || yIndex >= yZoneNumber)
		return false;

	// not initialize so return null
	if (bitPlaygroundStat == NULL)
		return false;

	return bitPlaygroundStat[yIndex * xZoneNumber + xIndex];
}

void BitPlaygroundObjectStat::SetBitPlaygroundStat(int xIndex, int yIndex, bool value)
{
	// coordinates out of the playground
	if (xIndex < 0 || xIndex >= xZoneNumber || yIndex < 0 || yIndex >= yZoneNumber)
		return;

	// not initialize so return null
	if (bitPlaygroundStat == NULL)
		return;

	bitPlaygroundStat[yIndex * xZoneNumber + xIndex] = value;
}

void BitPlaygroundObjectStat::LoadByFloodAlgorithm(const PlaygroundStatistics *stat, float toProcent, StatisticsType type)
{
	this->xZoneNumber = stat->GetXZoneNumber();
	this->yZoneNumber = stat->GetYZoneNumber();

	int zoneNumbers = xZoneNumber * yZoneNumber;
	int	actFalseCount = 0;
	int actLevel = 0;

	if (bitPlaygroundStat != NULL)
		delete bitPlaygroundStat;

	bitPlaygroundStat = new bool[zoneNumbers];

	while ((float)actFalseCount / zoneNumbers < toProcent)
	{
		for (int i = 0; i < xZoneNumber; i++)
			for (int j = 0; j < yZoneNumber; j++)
			{
				if (actLevel == stat->GetSquareZoneStatistic(i, j)->GetInTheZone(type))
				{
					actFalseCount++;
					bitPlaygroundStat[i + xZoneNumber * j] = false;
				}
				else if (actLevel == 0)
					bitPlaygroundStat[i + xZoneNumber * j] = true;
			}

		actLevel++;
	}
}

void BitPlaygroundObjectStat::LoadByPeakAlgorithm(const PlaygroundStatistics *stat, float toProcent, StatisticsType type)
{
	this->xZoneNumber = stat->GetXZoneNumber();
	this->yZoneNumber = stat->GetYZoneNumber();

	int zoneNumbers = xZoneNumber * yZoneNumber;
	int actLevel = 0;

	if (bitPlaygroundStat != NULL)
		delete bitPlaygroundStat;

	bitPlaygroundStat = new bool[zoneNumbers];

	int i;
	int peak = 0;
	for (i = 0; i < xZoneNumber; i++)
		for (int j = 0; j < yZoneNumber; j++)
			peak = (((signed)stat->GetSquareZoneStatistic(i, j)->GetInTheZone(type)) > peak) ? stat->GetSquareZoneStatistic(i, j)->GetInTheZone(type) : peak;

	for (i = 0; i < xZoneNumber; i++)
		for (int j = 0; j < yZoneNumber; j++)
		{
			if (((signed)stat->GetSquareZoneStatistic(i, j)->GetInTheZone(type)) / (float)peak < toProcent)
				bitPlaygroundStat[i + xZoneNumber * j] = false;
			else
				bitPlaygroundStat[i + xZoneNumber * j] = true;
		}
}

void BitPlaygroundObjectStat::LoadByLocalMaximumAlgorithm(const PlaygroundStatistics *stat, StatisticsType type)
{
	this->xZoneNumber = stat->GetXZoneNumber();
	this->yZoneNumber = stat->GetYZoneNumber();

	int zoneNumbers = xZoneNumber * yZoneNumber;

	if (bitPlaygroundStat != NULL)
		delete bitPlaygroundStat;

	bitPlaygroundStat = new bool[zoneNumbers];

	unsigned int center;
	for (int i = 0; i < xZoneNumber; i++)
		for (int j = 0; j < yZoneNumber; j++)
		{
			center = stat->GetSquareZoneStatistic(i, j)->GetInTheZone(type);

			if (i + 1 >= 0 && i + 1 < xZoneNumber && j + 1 >= 0 && j + 1 < yZoneNumber && stat->GetSquareZoneStatistic(i + 1, j + 1)->GetInTheZone(type) >= center)
				bitPlaygroundStat[i + xZoneNumber * j] = false;
			else if (i + 1 >= 0 && i + 1 < xZoneNumber && j     >= 0 && j     < yZoneNumber && stat->GetSquareZoneStatistic(i + 1, j    )->GetInTheZone(type) >= center)
				bitPlaygroundStat[i + xZoneNumber * j] = false;
			else if (i + 1 >= 0 && i + 1 < xZoneNumber && j - 1 >= 0 && j - 1 < yZoneNumber && stat->GetSquareZoneStatistic(i + 1, j - 1)->GetInTheZone(type) >= center)
				bitPlaygroundStat[i + xZoneNumber * j] = false;
			else if (i     >= 0 && i     < xZoneNumber && j + 1 >= 0 && j + 1 < yZoneNumber && stat->GetSquareZoneStatistic(i    , j + 1)->GetInTheZone(type) >= center)
				bitPlaygroundStat[i + xZoneNumber * j] = false;
			else if (i     >= 0 && i     < xZoneNumber && j - 1 >= 0 && j - 1 < yZoneNumber && stat->GetSquareZoneStatistic(i    , j - 1)->GetInTheZone(type) >= center)
				bitPlaygroundStat[i + xZoneNumber * j] = false;
			else if (i - 1 >= 0 && i - 1 < xZoneNumber && j + 1 >= 0 && j + 1 < yZoneNumber && stat->GetSquareZoneStatistic(i - 1, j + 1)->GetInTheZone(type) >= center)
				bitPlaygroundStat[i + xZoneNumber * j] = false;
			else if (i - 1 >= 0 && i - 1 < xZoneNumber && j     >= 0 && j     < yZoneNumber && stat->GetSquareZoneStatistic(i - 1, j    )->GetInTheZone(type) >= center)
				bitPlaygroundStat[i + xZoneNumber * j] = false;
			else if (i - 1 >= 0 && i - 1 < xZoneNumber && j - 1 >= 0 && j - 1 < yZoneNumber && stat->GetSquareZoneStatistic(i - 1, j - 1)->GetInTheZone(type) >= center)
				bitPlaygroundStat[i + xZoneNumber * j] = false;
			else
				bitPlaygroundStat[i + xZoneNumber * j] = true;
		}
}

void BitPlaygroundObjectStat::Clear()
{
	if (bitPlaygroundStat != NULL)
	{
		delete bitPlaygroundStat;
		bitPlaygroundStat = NULL;
	}
}