#define VCMI_DLL
#include "../stdafx.h"
#include "CBuildingHandler.h"
#include "CGeneralTextHandler.h"
#include "CLodHandler.h"
#include "../lib/VCMI_Lib.h"
#include <sstream>
#include <fstream>
#include <assert.h>
#include <boost/assign/list_of.hpp>
#include <boost/foreach.hpp>
#include "../lib/JsonNode.h"

extern CLodHandler * bitmaph;

/*
 * CBuildingHandler.cpp, part of VCMI engine
 *
 * Authors: listed in file AUTHORS in main folder
 *
 * License: GNU General Public License v2.0 or later
 * Full text of license available in license.txt file, in main folder
 *
 */

static unsigned int readNr(std::string &in, int &it)
{
	int last=it;
	for(;last<in.size();last++)
		if(in[last]=='\t' || in[last]=='\n' || in[last]==' ' || in[last]=='\r' || in[last]=='\n')
			break;
	if(last==in.size())
		throw std::string("Cannot read number...");

	std::istringstream ss(in.substr(it,last-it));
	it+=(1+last-it);
	ss >> last;
	return last;
}
static CBuilding * readBg(std::string &buf, int& it)
{
	CBuilding * nb = new CBuilding();
	for(int res=0;res<7;res++)
		nb->resources[res] = readNr(buf,it);
	/*nb->refName = */readTo(buf,it,'\n');
	//reference name is omitted, it's seems to be useless
	return nb;
}
void CBuildingHandler::loadBuildings()
{
	std::string buf = bitmaph->getTextFile("BUILDING.TXT"), temp;
	int it=0; //buf iterator

	temp = readTo(buf,it,'\n');temp = readTo(buf,it,'\n');//read 2 lines of file info

	//read 9 special buildings for every faction
	buildings.resize(F_NUMBER);
	for(int i=0;i<F_NUMBER;i++)
	{
		temp = readTo(buf,it,'\n');//read blank line and faction name
		temp = readTo(buf,it,'\n');
		for(int bg = 0; bg<9; bg++)
		{
			CBuilding *nb = readBg(buf,it);
			nb->tid = i;
			nb->bid = bg+17;
			buildings[i][bg+17] = nb;
		}
	}

	//reading 17 neutral (common) buildings
	temp = readTo(buf,it,'\n');temp = readTo(buf,it,'\n');temp = readTo(buf,it,'\n');//neutral buildings - skip 3 lines
	for(int bg = 0; bg<17; bg++)
	{
		CBuilding *nb = readBg(buf,it);
		for(int f=0;f<F_NUMBER;f++)
		{
			buildings[f][bg] = new CBuilding(*nb);
			buildings[f][bg]->tid = f;
			buildings[f][bg]->bid = bg;
		}
		delete nb;
	}

	//create Grail entries
	for(int i=0; i<F_NUMBER; i++)
		buildings[i][26] = new CBuilding(i,26);

	//reading 14 per faction dwellings
	temp = readTo(buf,it,'\n');temp = readTo(buf,it,'\n');//dwellings - skip 2 lines
	for(int i=0;i<F_NUMBER;i++)
	{
		temp = readTo(buf,it,'\n');//read blank line
		temp = readTo(buf,it,'\n');// and faction name
		for(int bg = 0; bg<14; bg++)
		{
			CBuilding *nb = readBg(buf,it);
			nb->tid = i;
			nb->bid = bg+30;
			buildings[i][bg+30] = nb;
		}
	}
	/////done reading BUILDING.TXT*****************************
	const JsonNode config(DATA_DIR "/config/hall.json");

	BOOST_FOREACH(const JsonNode &town, config["town"].Vector())
	{
		int tid = town["id"].Float();

		hall[tid].first = town["image"].String();
		(hall[tid].second).resize(5); //rows

		int row_num = 0;
		BOOST_FOREACH(const JsonNode &row, town["boxes"].Vector())
		{
			BOOST_FOREACH(const JsonNode &box, row.Vector())
			{
				(hall[tid].second)[row_num].push_back(std::vector<int>()); //push new box
				std::vector<int> &box_vec = (hall[tid].second)[row_num].back();

				BOOST_FOREACH(const JsonNode &value, box.Vector())
				{
					box_vec.push_back(value.Float());
				}
			}
			row_num ++;
		}

		assert (row_num == 5);
	}
}

CBuildingHandler::~CBuildingHandler()
{
	for(std::vector< bmap<int, ConstTransitivePtr<CBuilding> > >::iterator i=buildings.begin(); i!=buildings.end(); i++)
		for(std::map<int, ConstTransitivePtr<CBuilding> >::iterator j=i->begin(); j!=i->end(); j++)
			j->second.dellNull();
}

static std::string emptyStr = "";

const std::string & CBuilding::Name() const
{
	if(name.length())
		return name;
	else if(vstd::contains(VLC->generaltexth->buildings,tid) && vstd::contains(VLC->generaltexth->buildings[tid],bid))
		return VLC->generaltexth->buildings[tid][bid].first;
	tlog2 << "Warning: Cannot find name text for building " << bid << "for " << tid << "town.\n";
	return emptyStr;
}

const std::string & CBuilding::Description() const
{
	if(description.length())
		return description;
	else if(vstd::contains(VLC->generaltexth->buildings,tid) && vstd::contains(VLC->generaltexth->buildings[tid],bid))
		return VLC->generaltexth->buildings[tid][bid].second;
	tlog2 << "Warning: Cannot find description text for building " << bid << "for " << tid << "town.\n";
	return emptyStr;
}

CBuilding::CBuilding( int TID, int BID )
{
	tid = TID;
	bid = BID;
}

int CBuildingHandler::campToERMU( int camp, int townType, std::set<si32> builtBuildings )
{
	using namespace boost::assign;
	static const std::vector<int> campToERMU = list_of(11)(12)(13)(7)(8)(9)(5)(16)(14)(15)(-1)(0)(1)(2)(3)(4)
		(6)(26)(17)(21)(22)(23)
		; //creature generators with banks - handled separately
	if (camp < campToERMU.size())
	{
		return campToERMU[camp];
	}

	static const std::vector<int> hordeLvlsPerTType[F_NUMBER] = {list_of(2), list_of(1), list_of(1)(4), list_of(0)(2),
		list_of(0), list_of(0), list_of(0), list_of(0), list_of(0)};

	int curPos = campToERMU.size();
	for (int i=0; i<7; ++i)
	{
		if(camp == curPos) //non-upgraded
			return 30 + i;
		curPos++;
		if(camp == curPos) //upgraded
			return 37 + i;
		curPos++;
		//horde building
		if (vstd::contains(hordeLvlsPerTType[townType], i))
		{
			if (camp == curPos)
			{
				if (hordeLvlsPerTType[townType][0] == i)
				{
					if(vstd::contains(builtBuildings, 37 + hordeLvlsPerTType[townType][0])) //if upgraded dwelling is built
						return 19;
					else //upgraded dwelling not presents
						return 18;
				}
				else
				{
					if(hordeLvlsPerTType[townType].size() > 1)
					{
						if(vstd::contains(builtBuildings, 37 + hordeLvlsPerTType[townType][1])) //if upgraded dwelling is built
							return 25;
						else //upgraded dwelling not presents
							return 24;
					}
				}
			}
			curPos++;
		}

	}
	assert(0);
	return -1; //not found
}