/*
    Copyright (C) 2012 Bartosz Broda, Jacek Bochenek, Łukasz Biłeńkij, 
    Damian Jaworski, Wojciech Mazur, Dominik Piasecki, Maciej Piasecki, 
    Radosław Ramocki
    
    This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser 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 LICENSE and COPYING files for more details.
*/

#include "wbst_meta_optimizer.h"

void appendVector(std::vector<int> &a, std::vector<int> b)
{
	for(std::vector<int>::iterator iter=b.begin();iter!=b.end();++iter)
	{
		a.push_back(*iter);
	}
}

std::vector<std::string> MetaOptimizer::loadWBSTFile(std::string filename)
{

	std::ifstream file(filename.c_str() );
	if(!file)
		throw std::runtime_error( "Cannot open wbst file: " + filename);
	std::string line;
	std::getline(file, line);//first line is only a header
	WBSTFileHeader= line;

	std::vector<std::string> results;

	while(std::getline(file,line) )
	{
		boost::trim(line);
		if(line.length() == 0 )
			continue;

		results.push_back( line );
	}
	return results;
}

void MetaOptimizer::initFolds(int numOfQuestions, int numOfFolds)
{
	for(int i=0;i<numOfFolds;i++)
	{
		folds.push_back(new std::vector<int>);
		for(int j=(numOfQuestions*i)/numOfFolds;j<(numOfQuestions*(i+1))/numOfFolds;j++)
			folds[i]->push_back(j);
	}

	currentFold=0;


}

std::pair<std::vector<int>,std::vector<int> >  MetaOptimizer::nextFold()
{
	std::vector<int> learning;

	for(int i=0;i<(int)folds.size();i++)
		if(i!=currentFold)
			appendVector(learning,(*folds[i]));


	return std::pair<std::vector<int>,std::vector<int> > (learning,(*folds[currentFold++]));

}
void MetaOptimizer::createTest(std::vector<std::string> WBSTQuestions,std::string fileName,std::vector<int> IDVector)
{

	std::ofstream outFile(fileName.c_str());
	if(!outFile)
		throw std::runtime_error( "Cannot open fold file: " + fileName);
	outFile<<WBSTFileHeader<<std::endl;
	for(std::vector<int>::iterator iter=IDVector.begin();iter!=IDVector.end();++iter)
		outFile<<WBSTQuestions[(*iter)]<<std::endl;


	outFile.close();

}

void MetaOptimizer::start()
{
	Config* cfg=Config::getInstance();
	std::vector<std::string> WBSTQuestions = loadWBSTFile(cfg->wbstTestFile);
	initFolds(WBSTQuestions.size(),cfg->numOfFolds);
	for(int i=0;i<cfg->numOfFolds;i++)
	{
		std::stringstream ssOptimizerConfig;
		ssOptimizerConfig<<cfg->workdir<<"optimizer_fold"<<i<<".cfg";
		std::string optimizerConfigFileName=ssOptimizerConfig.str();
		std::ofstream optimizerConfigFile(optimizerConfigFileName.c_str());

		std::stringstream ssLearnFoldFile;
		ssLearnFoldFile<<cfg->workdir<<"learn_fold"<<i;
		std::string learnFileName=ssLearnFoldFile.str();

		std::stringstream ssTestFoldFile;
		ssTestFoldFile<<cfg->workdir<<"test_fold"<<i;
		std::string testFileName=ssTestFoldFile.str();

		std::pair<std::vector<int>, std::vector<int> >fold=nextFold();
		createTest(WBSTQuestions,learnFileName,fold.first);
		createTest(WBSTQuestions,testFileName,fold.second);

		//Filling in config file
		optimizerConfigFile<<"wbst-tester="<<cfg->wbstTesterPath<<std::endl;
		if(cfg->numOfNodes!=2)
			optimizerConfigFile<<"nodes="<<cfg->numOfNodes<<std::endl;
		optimizerConfigFile<<"hostfile-path="<<cfg->hostFile<<std::endl;
		optimizerConfigFile<<"seed="<<cfg->randomSeed<<std::endl;
		optimizerConfigFile<<"workdir="<<cfg->workdir<<std::endl;
		optimizerConfigFile<<"wbst-learning-fold="<<learnFileName<<std::endl;
		optimizerConfigFile<<"wbst-testing-fold="<<testFileName<<std::endl;
		optimizerConfigFile<<"matrix-path="<<cfg->matrix<<std::endl;
		optimizerConfigFile<<"flex="<<cfg->flex<<std::endl;
		if(cfg->loadCCS)
			optimizerConfigFile<<"load-ccs=1"<<std::endl;
		optimizerConfigFile<<"function-file="<<cfg->functionFile<<std::endl;
		optimizerConfigFile<<"parents-population-size="<<cfg->parentsPopulationSize<<std::endl;
		optimizerConfigFile<<"children-population-size="<<cfg->childrenPopulationSize<<std::endl;
		optimizerConfigFile<<"iterations="<<cfg->iterations<<std::endl;
		optimizerConfigFile<<"search-method=genetic"<<std::endl;
	}

}
