// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010  Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.


#include "nel/misc/types_nl.h"
#include "nel/misc/file.h"
#include "nel/3d/quad_tree.h"
#include "nel/3d/zone.h"
#include <vector>
#include <set>
#include <iostream>


using namespace NL3D;
using namespace NLMISC;
using namespace std;


/*******************************************************************\
						getDir()
\*******************************************************************/
std::string getDir (const std::string& path)
{
	char tmpPath[512];
	strcpy (tmpPath, path.c_str());
	char* slash=strrchr (tmpPath, '/');
	if (!slash)
	{
		slash=strrchr (tmpPath, '\\');
	}

	if (!slash)
		return "";

	slash++;
	*slash=0;
	return tmpPath;
}


/*******************************************************************\
						getName()
\*******************************************************************/
std::string getName (const std::string& path)
{
	std::string dir=getDir (path);

	char tmpPath[512];
	strcpy (tmpPath, path.c_str());

	char *name=tmpPath;
	nlassert (dir.length()<=strlen(tmpPath));
	name+=dir.length();

	char* point=strrchr (name, '.');
	if (point)
		*point=0;

	return name;
}


/*******************************************************************\
						getExt()
\*******************************************************************/
std::string getExt (const std::string& path)
{
	std::string dir=getDir (path);
	std::string name=getName (path);

	char tmpPath[512];
	strcpy (tmpPath, path.c_str());

	char *ext=tmpPath;
	nlassert (dir.length()+name.length()<=strlen(tmpPath));
	ext+=dir.length()+name.length();

	return ext;
}

/*******************************************************************\
						getZoneCoordByName()
\*******************************************************************/
bool getZoneCoordByName(const char * name, uint16& x, uint16& y)
{
	uint i;
	
	std::string zoneName(name);

	// y
	string::size_type ind1 = zoneName.find("_");
	if(ind1 == string::npos || ind1>=zoneName.length())
	{
		nlwarning("bad file name");
		return false;
	}
	std::string ystr = zoneName.substr(0,ind1);
	for(i=0; i<ystr.length(); i++)
	{
		if(!isdigit(ystr[i]))
		{
			nlwarning("y code size is not a 2 characters code");
			return false;
		}
	}

	NLMISC::fromString(ystr, y);

	// x
	x = 0;
	uint ind2 = (uint)zoneName.length();
	if((ind2-ind1-1)!=2)
	{
		nlwarning("x code size is not a 2 characters code");
		return false;
	}
	std::string xstr = zoneName.substr(ind1+1,ind2-ind1-1);
	for(i=0; i<xstr.length(); i++)
	{
		if (isalpha(xstr[i]))
		{
			x *= 26;
			x += (tolower(xstr[i])-'a');
		}
		else
		{
			nlwarning("invalid");
			return false;
		}
	}
	return true;
}


/*******************************************************************\
						getLettersFromNum()
\*******************************************************************/
void getLettersFromNum(uint16 num, std::string& code)
{
	if(num>26*26) 
	{
		nlwarning("zone index too high");
		return;
	}
	code.resize(0);
	uint16 remainder = num%26;
	code += 'A' + num/26;
	code += 'A' + remainder;
}


/*******************************************************************\
						getZoneNameByCoord()
\*******************************************************************/
void getZoneNameByCoord(uint16 x, uint16 y, std::string& zoneName)
{
	// y str
	char stmp[10];
	sprintf(stmp,"%d",y);
	std::string ystrtmp = std::string(stmp);

	// x str
	std::string xstrtmp;
	getLettersFromNum(x, xstrtmp);

	// name
	zoneName = ystrtmp;
	zoneName +="_";
	zoneName +=xstrtmp;
}



/*******************************************************************\
						getAdjacentZonesName()
\*******************************************************************/
void getAdjacentZonesName(const std::string& zoneName, std::vector<std::string>& names)
{
	uint16 x,y;
	int xtmp,ytmp;
	std::string nametmp;
	std::string empty("empty");

	names.reserve(8);
	
	getZoneCoordByName(zoneName.c_str(), x, y);

	// top left
	xtmp = x-1;
	ytmp = y-1;
	if(xtmp<0||ytmp<0)
		nametmp = empty;
	else
		getZoneNameByCoord(xtmp, ytmp, nametmp);
	names.push_back(nametmp);

	// top
	xtmp = x;
	ytmp = y-1;
	if(ytmp<0)
		nametmp = empty;
	else
		getZoneNameByCoord(xtmp, ytmp, nametmp);
	names.push_back(nametmp);

	// top right
	xtmp = x+1;
	ytmp = y-1;
	if(ytmp<0)
		nametmp = empty;
	else
		getZoneNameByCoord(xtmp, ytmp, nametmp);
	names.push_back(nametmp);

	// left
	xtmp = x-1;
	ytmp = y;
	if(xtmp<0)
		nametmp = empty;
	else
		getZoneNameByCoord(xtmp, ytmp, nametmp);
	names.push_back(nametmp);

	// right
	xtmp = x+1;
	ytmp = y;
	getZoneNameByCoord(xtmp, ytmp, nametmp);
	names.push_back(nametmp);

	// bottom left
	xtmp = x-1;
	ytmp = y+1;
	if(xtmp<0)
		nametmp = empty;
	else
		getZoneNameByCoord(xtmp, ytmp, nametmp);
	names.push_back(nametmp);

	// bottom
	xtmp = x;
	ytmp = y+1;
	getZoneNameByCoord(xtmp, ytmp, nametmp);
	names.push_back(nametmp);

	// bottom right 
	xtmp = x+1;
	ytmp = y+1;
	getZoneNameByCoord(xtmp, ytmp, nametmp);
	names.push_back(nametmp);
}


/*******************************************************************\
						createZoneId()
\*******************************************************************/
uint16 createZoneId(std::string zoneName)
{
	uint16 x,y;
	getZoneCoordByName(zoneName.c_str(), x, y);
	return ((y-1)<<8) + x;
}