#include <ctpp/ctpp.hpp>
#include <CTPP2.hpp>

#include <fstream>
#include <iostream>
#include <sstream>

#include <sys/time.h>
#include <time.h>
 

#define C_MAX_ITERATIONS 10000000
#define C_PARAMS_ITERATIONS 100

void ConstructData(CTPP::CDT & oData)
{
	using namespace CTPP;
	oData = CDT(CDT::HASH_VAL);
	CDT oArray(CDT::ARRAY_VAL);
	for (int iPos = 0; iPos < C_PARAMS_ITERATIONS; ++iPos)
	{
		CDT oArrayElt;
		CDT oTMP("name");
		oTMP += iPos;

		oArrayElt["secondname"] = oTMP;

		oTMP = "firstname";
		oTMP += iPos;

		oArrayElt["firstname"] = oTMP;

		CDT oIJArr(CDT::ARRAY_VAL);
		for (int j=0; j<5; j++)
		{
			CDT oIJTMP;
			oIJTMP["tst"] = j; 
			oIJArr.PushBack(oIJTMP);
		}
		oArrayElt["iarr"] = oIJArr;
		oArray.PushBack(oArrayElt);
	}  
	oData["array"] = oArray;
}

void TestCTPP2()
{
	using namespace std;
	using namespace CTPP;

	string sResult;

	CTPP::StringOutputCollector oOutputCollector(sResult);

	CTPP::SyscallFactory oSyscallFactory(100);
	CTPP::STDLibInitializer::InitLibrary(oSyscallFactory);

	CTPP::VMFileLoader oLoader("test.ct2");
	const CTPP::VMMemoryCore * pVMMemoryCore = oLoader.GetCore();
	CTPP::VM oVM(oSyscallFactory, 10240, 10240, 1024 * 1024);

	struct timeval sTimeValLocBegin;
	struct timeval sTimeValLocEnd;
	gettimeofday(&sTimeValLocBegin, NULL);
	for (UINT_32 iIteration = 0; iIteration < C_MAX_ITERATIONS; ++iIteration);
	{
		CTPP::CDT oData;
		ConstructData(oData);

		oVM.Init(oOutputCollector, *pVMMemoryCore);
		UINT_32 iIP = 0;
		oVM.Run(*pVMMemoryCore, iIP, oData);

//		fprintf(stderr, "Result: %s\n", sResult.c_str());
		sResult.erase();
	}
	gettimeofday(&sTimeValLocEnd, NULL);
	fprintf(stderr, "CTPP2 Completed in %f seconds.\n", (1.0 * (sTimeValLocEnd.tv_sec - sTimeValLocBegin.tv_sec) + 1.0 * (sTimeValLocEnd.tv_usec - sTimeValLocBegin.tv_usec) / 1000000));
}


void ConstructData(template_parser_ns::param_data * oData)
{
	using namespace template_parser_ns;

	param_data * pArray  = oData -> hash_insert_new_array("array");

	for (int iPos = 0; iPos < C_PARAMS_ITERATIONS; ++iPos)
	{
		std::ostringstream tmp;
		tmp << "name"<<iPos;

		param_data * pHash =  pArray->array_insert_new_hash();
		pHash->hash_insert_new_var("secondname",tmp.str().c_str());

		tmp.str("");
		tmp << "firstname"<<iPos;

		pHash -> hash_insert_new_var("firstname",tmp.str().c_str());
		param_data * iArray  = pHash->hash_insert_new_array("iarr");

		for (int j=0; j<5; j++)
		{
			param_data * iHash =  iArray->array_insert_new_hash();
			tmp.str("");
			tmp << j;
			iHash->hash_insert_new_var("tst",tmp.str().c_str());
		}
	}	
}

void TestCTPP()
{
	using namespace std;
	using namespace template_parser_ns;

	string sResult;

	template_text oTemplate;
	loader_base   oLoader;
	v_include_dir vIncludeDir;

	oTemplate.clear_template();
	oTemplate.set_include_dir(vIncludeDir);
	oLoader.load_file("test.tmpl");

	oTemplate.parse(oLoader.get_data());

	struct timeval sTimeValLocBegin;
	struct timeval sTimeValLocEnd;
	gettimeofday(&sTimeValLocBegin, NULL);
	for (UINT_32 iIteration = 0; iIteration < C_MAX_ITERATIONS; ++iIteration);
	{
		param_data * oData = new param_data(param_data::HASH);
		ConstructData(oData);
		
		oTemplate.param(oData);
		sResult = oTemplate.output();

//		fprintf(stderr, "Result: %s\n", sResult.c_str());
		sResult.erase();

		delete oData;
	}
	gettimeofday(&sTimeValLocEnd, NULL);
	fprintf(stderr, "CTPP  Completed in %f seconds.\n", (1.0 * (sTimeValLocEnd.tv_sec - sTimeValLocBegin.tv_sec) + 1.0 * (sTimeValLocEnd.tv_usec - sTimeValLocBegin.tv_usec) / 1000000));


}

int main(void)
{
	TestCTPP2();

	TestCTPP();
}

