/*
    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 "matrices_all.h"
#include <string>
#include <iostream>
#include <boost/filesystem.hpp>
#include <cstring>

/**
  * Function processing matrix's path into director and name
  * \param mpath_in Matrix's path
  * \param mdir Output with matrix's directory
  * \param mname Output with matrix's name
  */
void GetMatrixDirName(const std::string mpath_in, std::string &mdir, std::string &mname)
{
	std::string mpath;
	if( mpath_in[ mpath_in.size() - 1] == '\\' ||
		mpath_in[ mpath_in.size() - 1] == '/')
		mpath = mpath_in.substr(0, mpath_in.size() - 1);
	else
		mpath = mpath_in;

	boost::filesystem::path p (mpath);
	mdir = p.parent_path().string();
	mname = p.filename().c_str();
}

/**
  * Function creating 10x10 matrix with hardcoded boundaries. For testing purposes only
  */
void createTestMatrix()
{

	Matrices::CCSMatrixPtr ccsMatrix (new Matrices::CCSMatrix("ccs",10,10));
	Matrices::CRSMatrixPtr crsMatrix (new Matrices::CRSMatrix("ccs",10,10));
	for(int i=0;i<10;i++)
		for(int j=0;j<10;j++)
		{
		ccsMatrix->SetCell(100*j+i,i,j);
		crsMatrix->SetCell(100*j+i,i,j);
	}
	Matrices::FeatureVectorPtr someFeatures(new Matrices::FeatureVector());
	for(int i=0;i<10;i++)
	{
		std::stringstream ss;
		ss<<"label"<<i;
		someFeatures->push_back(*(new Matrices::Feature(ss.str(),i+10,i+100,i+1000,i/10)));
	}

	std::map<size_t, std::string > boundaries;
	boundaries[3]="Pierwszy_operator_index_3";
	boundaries[6]="Drugi_operator_index_6";
	boundaries[10]="Ostatni_operator_index_10";





	Matrices::SuperMatrixPtr matrix(new Matrices::SuperMatrix("test",ccsMatrix,crsMatrix,someFeatures,someFeatures,1000,"opis",boundaries));
	Matrices::IO::WriteSuperMatrix(matrix,"./");
}
void helpMsg(char* av)
{
	std::cout<<"Program splitting matrix according to it's boundaries\n"
			<<"Runtime format: "<<av<<" matrix_to_split output_directory output_prefix\n";
}

int main(int argc,char** argv)
{
	Matrices::init_logging();
	if(argc>0 && (strcmp(argv[1],"--help")==0))
	{
		helpMsg(argv[0]);
		return 1;
	}
	if(argc!=4)
	{
		helpMsg(argv[0]);
		throw std::runtime_error("Invalid number of parameters!\n");
		return -1;
	}
	std::string mdir, mname;
	std::string matrixString(argv[1]);
	if(matrixString.compare("test")==0)
	{
		std::cout<<"Creating test matrix..\n";
		createTestMatrix();
		matrixString = "./test";

	}
	GetMatrixDirName(matrixString, mdir, mname);

	std::cout<<"Got dir: "<<mdir<<" and name: "<<mname<<std::endl;

	Matrices::SuperMatrixPtr baseMatrix = Matrices::IO::LoadSuperMatrix(mdir,mname,false,true);
	//    baseMatrix->SetNewName("test2");
	//    Matrices::IO::WriteSuperMatrix(baseMatrix,mdir);


	std::map<size_t, std::string > boundaries = baseMatrix->Boundaries();

	int lastColumnIndex=-1;
	Matrices::FeatureVectorPtr rowFeatures = baseMatrix->GetRowFeatures();
	Matrices::FeatureVectorPtr baseColFeatures = baseMatrix->GetColumnFeatures();


	for(std::map<size_t, std::string >::iterator iterBound=boundaries.begin();iterBound!=boundaries.end();++iterBound)
	{

		Matrices::CCSMatrixPtr ccsMatrix (new Matrices::CCSMatrix("ccs",rowFeatures->size(),
									  (*iterBound).first-lastColumnIndex-1));
		Matrices::CRSMatrixPtr crsMatrix (new Matrices::CRSMatrix("ccs",rowFeatures->size(),
									  (*iterBound).first-lastColumnIndex-1));
		std::cout<<"Created new ccs and crs matrices "<<rowFeatures->size()<<"x"<<(*iterBound).first-lastColumnIndex-1<<"\n";
		//Copying matrices
		for(int i=0;i<(int)rowFeatures->size();i++)

		{
			Matrices::STDoubleMapPtr currentRow = baseMatrix->GetRow(i)->GetValues();
			//            std::cout<<"Row obtained\n";
			for(Matrices::STDoubleMapIter iter=currentRow->begin();
			iter!=currentRow->end() && (*iter).first <(*iterBound).first;++iter)
			{
				//                std::cout<<"In for loop\n";
				if((int)(*iter).first > lastColumnIndex)
				{
					//                    std::cout<<"Inside if, iter.first: "<<((*iter).first)<<", lastColInd: "<<lastColumnIndex<<"\n";
					ccsMatrix->SetCell((*iter).second,i,(*iter).first-lastColumnIndex-1);
					crsMatrix->SetCell((*iter).second,i,(*iter).first-lastColumnIndex-1);
				}
			}
			//            std::cout<<"Outside for loop\n";
			rowFeatures->at(i).SetNZ(crsMatrix->GetCompressedRow(i)->GetValues()->size());
			rowFeatures->at(i).SetEntropy(Measures::CountVectorEntropy(*(crsMatrix->GetCompressedRow(i))));
			rowFeatures->at(i).SetTermFrequnecy(Measures::CountVectorSum(crsMatrix->GetCompressedRow(i)));

		}

		std::cout<<"Matrices copied\n";
		Matrices::FeatureVectorPtr colFeatures (new Matrices::FeatureVector);
		for(int i=lastColumnIndex+1;i<(int)(*iterBound).first;i++)
			colFeatures->push_back(baseColFeatures->at(i));
		std::map<size_t,std::string> newBoundaries;
		newBoundaries.insert(std::pair<size_t,std::string>((*iterBound).first-lastColumnIndex-1,(*iterBound).second));

		boost::filesystem::path outputPath(argv[2]);
		//		outputPath.normalize();
		outputPath/=std::string(argv[3])+"_"+(*iterBound).second;
		std::cout<<"Trying name: "<<outputPath.string()<<std::endl;
		Matrices::SuperMatrixPtr newMatrix(new Matrices::SuperMatrix(outputPath.filename().c_str(),ccsMatrix,crsMatrix,rowFeatures,colFeatures,
										 baseMatrix->GetTokenCount(),baseMatrix->GetCorpusInfo(),newBoundaries));
		//        std::cout<<"Got here.\n";
		Matrices::IO::WriteSuperMatrix(newMatrix,outputPath.parent_path().string());


		lastColumnIndex = (*iterBound).first-1;
	}

}
