/*
    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 "svdtotalrunner.h"

SVDTotalRunner::SVDTotalRunner()
{
}
void SVDTotalRunner::Start()
{
	std::cout<<"Running base weighting...\n";
	baseWeighting();
	std::cout<<"Converting matrix to st format...\n";
	convert2ST();
	std::cout<<"Running svd runner...\n";
	svdRunning();
	std::cout<<"Converting crs to supermatrix...\n";
	crs2sm();
	std::cout<<"Running similarity function...\n";
	parallelRunner();
	std::cout<<"Running histograms...\n";
	histograms();
	std::cout<<"Converting text matrix to sm...\n";
	txt2sm();
	std::cout<<"Running mean median with filtering...\n";
	meanMedian();
	std::cout<<"Creating domains...\n";
	createDomains();
}
void SVDTotalRunner::txt2sm()
{
	double threshold;
	std::cout<<"Insert threshold for txt matrix: ";
	std::cin>>threshold;
	Config* cfg = Config::getInstance();
	std::stringstream runCommand;
	runCommand<<cfg->txt2smPath<<" --threshold "<<threshold<<" --kbest 5000"<<" --input "<<cfg->workdir
			<<"similarity_matrix_text.crs"<<" --output "<<cfg->workdir<<"similarity_matrix.crs";
	int returnValue = system(runCommand.str().c_str());
	if(returnValue!=0)
		std::cerr<<"Return value from system: "<<returnValue<<std::endl;
}

void SVDTotalRunner::meanMedian()
{
	Config* cfg = Config::getInstance();

	for	(double i=0.1;i<1;i+=0.1)
	{
		std::stringstream runCommand;
		runCommand<<cfg->meanMedianPath<<" "<<cfg->workdir<<"similarity_matrix.crs "<<cfg->workdir
				<<"matrix_filtered"<<i<<".crs"<<" "<<i;

		int returnValue = system(runCommand.str().c_str());
		if(returnValue!=0)
			std::cerr<<"Return value from system: "<<returnValue<<std::endl;
	}
}

void SVDTotalRunner::createDomains()
{
	Config* cfg = Config::getInstance();
	for	(double i=0.1;i<1;i+=0.1)
	{
		std::stringstream ss;
		ss<<cfg->workdir<<"matrix_filtered"<<i<<".crs";
		std::ifstream filtered(ss.str().c_str());
		if(!filtered)
			throw std::runtime_error("Cannot open filtered matrix!\n");

		std::stringstream ss2;
		ss2<<cfg->workdir<<"domain_file"<<i<<".txt";
		std::ofstream domainFile(ss2.str().c_str());
		if(!domainFile)
			throw std::runtime_error("Cannot open file for domains!\n");
		std::string line;
		//header
		std::getline(filtered,line);
		domainFile<<line<<std::endl;
		while((std::getline(filtered,line)))
		{
			boost::trim(line);
			std::vector<std::string> tokens;
			boost::split(tokens, line, boost::is_any_of(" ") );
			for(size_t i=0;i<tokens.size();i+=2)
				domainFile<<tokens[i]<<" ";
			domainFile<<std::endl;
		}
		domainFile.close();
		filtered.close();
	}
}

void SVDTotalRunner::parallelRunner()
{
	Config* cfg = Config::getInstance();

	std::stringstream runCommand;
	runCommand<<"mpirun -n "<<cfg->nodeNum<<" --hostfile "<<cfg->hostFile<<" "<<cfg->parallelSimPath<<" "
			<<"--matrix-dir "<<cfg->workdir<<" --matrix-name matrix_after_svd "
			<<"--measure-of-relatedness \""<<cfg->afterSVDFunction<<"\" --results-file "
			<<cfg->workdir<<"similarity_matrix_text.crs "
			<<"--read-crs "<<"--k-best-results 500000 "
			<<"--results-type textfile";
	int returnValue = system(runCommand.str().c_str());
	if(returnValue!=0)
		std::cerr<<"Return value from system: "<<returnValue<<std::endl;

}
void SVDTotalRunner::crs2sm()
{
	Config* cfg = Config::getInstance();
	boost::filesystem::path p(cfg->windowMatrixPath);
	p.normalize();
	std::string matrix_name = p.filename().c_str();
	std::string matrix_dir = p.branch_path().string();



	Matrices::CRSMatrixPtr crsMatrix = Matrices::IO::ReadCRSFromSingleFile(cfg->workdir+"matrix_after_svd.crs","crs");
	Matrices::SuperMatrixPtr windowSuperMatrix = Matrices::IO::LoadSuperMatrix(matrix_dir,matrix_name,false,true);

	Matrices::CCSMatrixPtr ccsMatrix (new Matrices::CCSMatrix("ccs",1,1));
	crsMatrix->Clone(ccsMatrix.get());

	Matrices::FeatureVectorPtr colFeatures(new Matrices::FeatureVector());
	for(size_t i =0;i<crsMatrix->NumberOfColumns();i++)
	{
		std::stringstream ss;
		ss<<"label"<<i;
		colFeatures->push_back(Matrices::Feature(ss.str(),-1,-1,-1,-1));
	}
	std::map<size_t,std::string> bound;
	Matrices::SuperMatrixPtr afterSvdSupermatrix(new Matrices::SuperMatrix("matrix_after_svd",ccsMatrix,crsMatrix,windowSuperMatrix->GetRowFeatures(),colFeatures,windowSuperMatrix->GetTokenCount(),windowSuperMatrix->GetCorpusInfo(),bound));
	Matrices::IO::WriteSuperMatrix(afterSvdSupermatrix,cfg->workdir);
}



void SVDTotalRunner::histograms()
{
	Config* cfg = Config::getInstance();
	for(size_t i =0 ;i<cfg->histogramValues.size();i++)
	{
		std::cout<<"Running histogram for "<<cfg->histogramValues[i]<<" step.\n";
		std::stringstream runCommand;
		runCommand<<cfg->histogramPath<<" "<<cfg->workdir<<"similarity_matrix_text.crs"<<" "<<cfg->histogramValues[i]<<" textfile"<<" > "<<cfg->workdir<<"histogram"<<cfg->histogramValues[i]<<".txt";
		int returnValue = system(runCommand.str().c_str());
		if(returnValue!=0)
			std::cerr<<"Return value from system: "<<returnValue<<std::endl;
	}
}

void SVDTotalRunner::convert2ST()
{
	Config* cfg = Config::getInstance();
	std::stringstream runCommand;
	runCommand<<cfg->sm2stPath<<" "<<cfg->workdir<<"baseWeightedMatrix"<<" "<<cfg->workdir<<"baseWeightedMatrix.st";
	int returnValue = system(runCommand.str().c_str());
	if(returnValue!=0)
		std::cerr<<"Return value from system: "<<returnValue<<std::endl;
}

void SVDTotalRunner::svdRunning()
{
	Config* cfg = Config::getInstance();
	std::string svdCfgFilename = cfg->workdir+"svdRunner.cfg";
	std::ofstream svdCfgFile(svdCfgFilename.c_str());
	if(!svdCfgFile)
		throw std::runtime_error("Cannot open file for svd config!\n");

	svdCfgFile<<"svd-path="<<cfg->svdPath<<std::endl;
	svdCfgFile<<"dimensions="<<cfg->svdRunnerDimensions<<std::endl;
	svdCfgFile<<"iterations="<<cfg->svdRunnerIterations<<std::endl;
	svdCfgFile<<"workdir="<<cfg->workdir<<std::endl;
	svdCfgFile<<"matrix-path="<<cfg->workdir<<"baseWeightedMatrix.st"<<std::endl;
	svdCfgFile<<"result-matrix="<<cfg->workdir<<"matrix_after_svd.crs"<<std::endl;
	svdCfgFile.close();
	std::stringstream runCommand;
	runCommand<<cfg->svdRunnerPath<<" --cfg-file "<<svdCfgFilename;
	int returnValue = system(runCommand.str().c_str());
	if(returnValue!=0)
		std::cerr<<"Return value from system: "<<returnValue<<std::endl;
}

void SVDTotalRunner::baseWeighting()
{
	Config* cfg = Config::getInstance();
	std::stringstream runCommand;
	runCommand<<cfg->matrixWeighterPath<<" "<<cfg->windowMatrixPath<<" \""<<cfg->baseFunction<<"\" "<<cfg->workdir<<"baseWeightedMatrix";
	std::string command = runCommand.str();
	std::cout<<"Running command: "<<command<<std::endl;
	int returnValue = system(command.c_str());
	if(returnValue!=0)
		std::cerr<<"Return value from system: "<<returnValue<<std::endl;
}
