/*
    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.
*/

#ifndef REMOVER_CPP
#define REMOVER_CPP
#include "matrices_all.h"
#include <cmath>
#include <boost/regex.hpp>
#include "remover.h"

namespace remover
{
	std::vector<int> getFeature2Group(std::string groupfileStr)
	{

		std::vector<int> ret;
		std::ifstream groupFile;
		int group;
		groupFile.open(groupfileStr.c_str());
		groupFile>>group;
		while(!groupFile.eof())
		{
			ret.push_back(group);
			groupFile>>group;
		}
		return ret;
	}

	Matrices::SuperMatrixPtr getInputMatrix(std::string matrixDir, std::string matrixName)
	{
		Matrices::SuperMatrixPtr matrix = Matrices::IO::LoadSuperMatrix(matrixDir, matrixName, true, false);
		return matrix;
	}

	int getNumberOfGroups(std::vector<int> groupVector)
	{
		int max = 0;
		for (size_t i=0; i<groupVector.size(); i++)
		{
			max = std::max(max,groupVector[i]);
		}
		return max+1;
	}

	size_t getNumberOfOutliers(std::vector<int> groupVector)
	{
		size_t outliers = 0;
		for (size_t i=0; i<groupVector.size(); i++)
		{
			if (groupVector[i] == -1)
			{
				outliers++;
			}
		}
		return groupVector.size() - outliers;

	}

	void setRowFeatures(Matrices::SuperMatrixPtr outMatrix,  Matrices::SuperMatrixPtr inMatrix)
	{
		Matrices::FeatureVectorPtr rowF = outMatrix->GetRowFeatures();
		Matrices::FeatureVector inColf = (*inMatrix->GetColumnFeatures());
		Matrices::FeatureVector inRowF = (*inMatrix->GetRowFeatures());
		for (size_t i = 0; i<outMatrix->NumberOfRows(); i++)
		{
			Matrices::CompressedVectorPtr rowContents = outMatrix->GetRow(i);
			std::string featurename = inRowF[i].GetLabel();
			size_t TF = inRowF[i].GetGlobalTermFrequency();
			size_t tf = (size_t) Measures::CountVectorSum(rowContents);
			rowF->push_back(Matrices::Feature(featurename,rowContents->GetValues()->size(),tf,TF,Measures::CountVectorEntropy(rowContents)));
		}
	}

	std::string getCurrentBoundary(Matrices::SuperMatrixPtr m, size_t colNo)
	{
		for (std::map<size_t, std::string>::iterator it = m->Boundaries().begin(); it != m->Boundaries().end(); ++it)
		{
			if (colNo <= (*it).first)
			{
				return (*it).second;
			}
		}
		throw std::runtime_error("Column index out of all boundaries!");
	}

	Matrices::SuperMatrixPtr getOutputMatrix(Matrices::SuperMatrixPtr inMatrix, std::vector<int> groupVector, std::string outMatrixName)
	{
		int column_no = getNumberOfOutliers(groupVector);
		Matrices::CRSMatrixPtr outCRS(new Matrices::CRSMatrix(outMatrixName.c_str(),inMatrix->NumberOfRows(), column_no));
		Matrices::CCSMatrixPtr outCCS(new Matrices::CCSMatrix(outMatrixName.c_str(),inMatrix->NumberOfRows(), column_no));
		Matrices::FeatureVectorPtr columnF(new Matrices::FeatureVector());
		Matrices::FeatureVectorPtr rowF(new Matrices::FeatureVector());
		size_t tokens = inMatrix->GetTokenCount();
		std::string corpus_info = inMatrix->GetCorpusInfo();
		std::map<size_t, std::string> boundaries = inMatrix->Boundaries();
		std::map<std::string, size_t> revBoundaries;
		std::string currentBoundary;
		Matrices::SuperMatrixPtr outMatrix(new Matrices::SuperMatrix(outMatrixName.c_str(),outCCS,outCRS,rowF,columnF,tokens,corpus_info,boundaries));
		Matrices::FeatureVectorPtr sourceColumnF = inMatrix->GetColumnFeatures();

		size_t outMatrixIndex = 0;
		for (size_t i = 0; i<inMatrix->NumberOfColumns(); i++)
		{
			if (groupVector[i] != -1)
			{
				columnF->push_back((*sourceColumnF)[i]);
				Matrices::CompressedVectorPtr col = inMatrix->GetCCS()->GetCompressedColumn(i);
				outCCS->SetCompressedColumn(outMatrixIndex, col);
				currentBoundary = getCurrentBoundary(inMatrix,i);
				revBoundaries[currentBoundary] = outMatrixIndex;
				outMatrixIndex ++;
			}
		}
		std::map<size_t, std::string> newBounds;
		for (std::map<std::string, size_t>::iterator it = revBoundaries.begin(); it !=revBoundaries.end(); ++it)
		{
			newBounds[(*it).second] = (*it).first;
		}
		outMatrix->SetBoundaries(newBounds);
		outMatrix->SyncCCSToCRS();
		setRowFeatures(outMatrix, inMatrix);
		return outMatrix;
	}
	int main(int ac, char**av)
	{
		Matrices::init_logging();
		std::vector<int> groupVector = getFeature2Group(av[3]);
		Matrices::SuperMatrixPtr inMatrix = getInputMatrix(av[1],av[2]);
		Matrices::SuperMatrixPtr outMatrix = getOutputMatrix(inMatrix,groupVector,av[5]);
		Matrices::IO::WriteSuperMatrix(outMatrix,av[4]);
		return 0;
	}

}
#endif // REMOVER_CPP
