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


Summator::Summator(Options opt)
{
	params = opt.GetParams();
	std::cout << "LICZENIE"<< std::endl;
}

void Summator::sum()
{
	std::vector< std::pair<std::string, std::string> > matrixPaths = params.m_vMatrixNameToPath;
	std::vector<Matrices::SuperMatrixPtr> matrices;//[matrixPaths.size()];

	// Loading matrices to vector
	for(int i=0;i<(int)params.m_vMatrixNameToPath.size();i++)
	{
		matrices.push_back(Matrices::IO::LoadSuperMatrix(matrixPaths[i].second,matrixPaths[i].first,true,false));
	}

	// Maping and stroing all boundaries
	std::map<std::string,std::pair<int,int> > boundary2Indexes[matrices.size()];
	std::set<std::string> allPossibleBoundaries;
	for(int i=0;i<(int)matrices.size();i++)
	{
		std::map<size_t, std::string > boundaries = matrices[i]->Boundaries();

		int counter=0;
		for(std::map<size_t, std::string >::iterator iter=boundaries.begin();iter!=boundaries.end();++iter)
		{
			boundary2Indexes[i][iter->second]=std::pair<int,int>(counter,iter->first-1);
			counter=iter->first;
			allPossibleBoundaries.insert(iter->second);
		}
	}

	// Creating new boundaries
	std::map<size_t, std::string > newBoundaries;
	std::map<std::string,std::set<std::string> > newBoundaries2Labels;
	int counter=0;
	for(std::set<std::string>::iterator iter=allPossibleBoundaries.begin();iter!=allPossibleBoundaries.end();++iter)
	{
		for(int i=0;i<(int)matrices.size();i++)
		{
			Matrices::FeatureVectorPtr colFeatures = matrices[i]->GetColumnFeatures();
			if(boundary2Indexes[i].find(*iter)!=boundary2Indexes[i].end())
			{
				for(int labelIndex=boundary2Indexes[i][*iter].first;labelIndex<=boundary2Indexes[i][*iter].second;labelIndex++)
				{
					newBoundaries2Labels[*iter].insert(colFeatures->at(labelIndex).GetLabel());
				}
			}

		}
		counter+=newBoundaries2Labels[*iter].size();
		newBoundaries[counter]=*iter;
	}

	// Creating new columns features
	std::vector<std::string> colLabels;
	std::map<std::string,std::map<std::string,int> > newBound2colLabels2Indexes;
	Matrices::FeatureVectorPtr newColFeatures(new Matrices::FeatureVector());
	Matrices::FeatureVectorPtr newRowFeatures(new Matrices::FeatureVector());

	for(std::map<size_t, std::string >::iterator iter = newBoundaries.begin();iter!=newBoundaries.end();++iter)
	{
		for(std::set<std::string>::iterator inner_iter = newBoundaries2Labels[iter->second].begin();inner_iter != newBoundaries2Labels[iter->second].end();++inner_iter)

		{
			colLabels.push_back(*inner_iter);
			newBound2colLabels2Indexes[iter->second][*inner_iter] = colLabels.size()-1;
			newColFeatures->push_back(Matrices::Feature());
			newColFeatures->at(newColFeatures->size()-1).SetLabel(colLabels[colLabels.size()-1]);
		}
	}
	// Creating new rows features
	std::vector<std::string> rowLabels;
	std::set<std::string> rowLabelsSet;
	for(int i=0;i<(int)matrices.size();i++)
	{
		Matrices::FeatureVectorPtr rowFeatures = matrices[i]->GetRowFeatures();
		for(int j=0;j<(int)rowFeatures->size();j++)
		{
			rowLabelsSet.insert(rowFeatures->at(j).GetLabel());
		}
	}
	std::map<std::string,int> rowLabels2Indexes;
	for(std::set<std::string>::iterator iter=rowLabelsSet.begin();iter!=rowLabelsSet.end();++iter)
	{
		rowLabels.push_back(*iter);
		rowLabels2Indexes[*iter] = rowLabels.size()-1;
		newRowFeatures->push_back(Matrices::Feature());
		newRowFeatures->at(newRowFeatures->size()-1).SetLabel(rowLabels[rowLabels.size()-1]);
	}
	//Filling final matrix
	Matrices::CCSMatrixPtr ccsMatrixPtr(new Matrices::CCSMatrix("ccs",rowLabels.size(),colLabels.size()));
	Matrices::CRSMatrixPtr crsMatrixPtr(new Matrices::CRSMatrix("ccs",rowLabels.size(),colLabels.size()));
	int newColumnIndex;
	int newRowIndex;
	for(int i=0;i<(int)matrices.size();i++)
	{
		std::map<size_t, std::string > matrixBoundaries = matrices[i]->Boundaries();
		int counter=0;
		Matrices::FeatureVectorPtr colFeatures = matrices[i]->GetColumnFeatures();
		Matrices::FeatureVectorPtr rowFeatures = matrices[i]->GetRowFeatures();
		for(std::map<size_t, std::string >::iterator iter = matrixBoundaries.begin();iter!=matrixBoundaries.end();++iter)
		{
			for(;counter<(int)iter->first;counter++)
			{
				Matrices::CompressedVectorPtr column = matrices[i]->GetColumn(counter);
				newColumnIndex = newBound2colLabels2Indexes[iter->second][colFeatures->at(counter).GetLabel()];

				if(params.appendTF)
					newColFeatures->at(newColumnIndex).SetGlobalTermFrequency(colFeatures->at(counter).GetGlobalTermFrequency());
				else
					newColFeatures->at(newColumnIndex).SetGlobalTermFrequency(newColFeatures->at(newColumnIndex).GetGlobalTermFrequency()+colFeatures->at(counter).GetGlobalTermFrequency());
				Matrices::STDoubleMapPtr values = column->GetValues();
				for(Matrices::STDoubleMapIter iter=values->begin();iter!=values->end();++iter)
				{
					newRowIndex = rowLabels2Indexes[rowFeatures->at(iter->first).GetLabel()];

					ccsMatrixPtr->AddToCell(iter->second,newRowIndex,newColumnIndex);
					crsMatrixPtr->AddToCell(iter->second,newRowIndex,newColumnIndex);
				}
			}
		}
		for(int i=0;i<(int)rowFeatures->size();i++)
		{
			newRowIndex = rowLabels2Indexes[rowFeatures->at(i).GetLabel()];
			if(params.appendTF)
				newRowFeatures->at(newRowIndex).SetGlobalTermFrequency(rowFeatures->at(i).GetGlobalTermFrequency());
			else
				newRowFeatures->at(newRowIndex).SetGlobalTermFrequency(newRowFeatures->at(newRowIndex).GetGlobalTermFrequency()+rowFeatures->at(i).GetGlobalTermFrequency());
		}

	}
	//Computing features
	for(int i=0;i<(int)newRowFeatures->size();i++)
	{
		newRowFeatures->at(i).SetNZ(crsMatrixPtr->GetCompressedRow(i)->GetValues()->size());
		newRowFeatures->at(i).SetTermFrequnecy(Measures::CountVectorSum(crsMatrixPtr->GetCompressedRow(i)));
		newRowFeatures->at(i).SetEntropy(Measures::CountVectorEntropy(crsMatrixPtr->GetCompressedRow(i)));
	}
	for(int i=0;i<(int)newColFeatures->size();i++)
	{
		newColFeatures->at(i).SetNZ(ccsMatrixPtr->GetCompressedColumn(i)->GetValues()->size());
		newColFeatures->at(i).SetTermFrequnecy(Measures::CountVectorSum(ccsMatrixPtr->GetCompressedColumn(i)));
		newColFeatures->at(i).SetEntropy(Measures::CountVectorEntropy(ccsMatrixPtr->GetCompressedColumn(i)));
	}
	Matrices::SuperMatrixPtr resultMatrix(new Matrices::SuperMatrix(params.m_sMatrixOutName,ccsMatrixPtr,crsMatrixPtr,newRowFeatures,newColFeatures,params.m_stUnitCount,params.m_sCorpusInfo,newBoundaries));
	Matrices::IO::WriteSuperMatrix(resultMatrix,params.m_sOutputDir);
	std::cerr<<"Warning: term frequency is computed as sum in row/column.";

}


















