/*
    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 "filtrator.h"
#include "options.h"

int main(int ac, char *av[])
{
	Matrices::init_logging();
	try
	{
		filtrator::Options options(ac,av);
		filtrator::Filtrator ve(options.GetParams() );
		ve.Start();
	}
	catch(std::exception &e)
	{
		std::cerr << "Error: " << e.what() << std::endl;
		return -1;
	}
	return 0;
}

namespace filtrator
{
	Filtrator::Filtrator(const Params &p) : m_Params(p)
	{
	}

	void Filtrator::Start()
	{
		LoadWords();
		if(!m_Params.m_bRows)
		{
			FilterColumns();
			WriteMatrixColumnBased();
		}
		else
		{
			FilterRows();
			//TODO saving
		}
	}

	void Filtrator::FilterColumns()
	{
		Matrices::SuperMatrixPtr pMatrix = Matrices::IO::LoadSuperMatrix(m_Params.m_sMatrixDir, m_Params.m_sMatrixName, true, false);
		std::cout << "Filtering columns from matrix " << pMatrix->GetName() << std::endl;
		m_sCorpusInfo = pMatrix->GetCorpusInfo();
		m_stUnitCount = pMatrix->GetTokenCount();
		
		m_pvColumnFeatures = Matrices::FeatureVectorPtr( new Matrices::FeatureVector() );
		m_pvRowFeatures = pMatrix->GetRowFeatures();
		for(size_t col_no = 0; col_no < pMatrix->NumberOfColumns(); col_no++)
		{
			Matrices::Feature &f = pMatrix->GetColumnFeatures()->operator[](col_no);
			if( m_setWords.find( f.GetLabel() ) != m_setWords.end() )
			{
				m_pvColumnFeatures->push_back( f );
				m_vColumns.push_back( pMatrix->GetColumn(col_no) );
			}
		}//for each column

		std::cout << "Filtering columns from matrix " << pMatrix->GetName() << ". OK!" <<std::endl;
	}//	void Filtrator::FilterColumns()

	void Filtrator::FilterRows()
	{
		throw std::runtime_error("Filtering of rows is unimplemented");
	}//	void Filtrator::FilterRows()


	void Filtrator::WriteMatrixColumnBased()
	{
		Matrices::CCSMatrixPtr pCCS( new Matrices::CCSMatrix("ccs", m_pvRowFeatures->size(), m_pvColumnFeatures->size() ) );
		for(size_t col_no = 0; col_no < m_pvColumnFeatures->size(); col_no ++)
			pCCS->SetCompressedColumn(col_no, * m_vColumns[col_no] );
		m_vColumns.clear();
		Matrices::CRSMatrix *crs = new Matrices::CRSMatrix("crs", m_pvRowFeatures->size(), m_pvColumnFeatures->size() );
		pCCS->Clone(crs);
		Matrices::CRSMatrixPtr pCRS( crs );

		PrepareFeaturesColumnBased(pCRS);

		Matrices::SuperMatrixPtr supermatrix( new Matrices::SuperMatrix( m_Params.m_sMatrixOutName, pCCS, pCRS, 
					m_pvRowFeatures, m_pvColumnFeatures, m_stUnitCount, m_sCorpusInfo) ) ;
		Matrices::IO::SuperMatrixWriter writer;
		std::cout << "Saving matrix...\n";
		writer.Write(supermatrix, m_Params.m_sOutputDir);
	}

	void Filtrator::PrepareFeaturesColumnBased(Matrices::CRSMatrixPtr pCRS)
	{
		for(size_t row_no = 0; row_no < pCRS->NumberOfRows(); row_no++)
		{
			Matrices::CompressedVectorPtr row = pCRS->GetCompressedRow(row_no);
			double entropy  = Measures::CountVectorEntropy( *row );
			size_t tf = (size_t) Measures::CountVectorSum( *row );
			Matrices::Feature& feature = (*m_pvRowFeatures)[ row_no ];
			feature.SetTermFrequnecy( tf );
			feature.SetNZ( row->GetValues()->size() );
			feature.SetEntropy( entropy );
		}
	}

	void Filtrator::LoadWords()
	{
		std::ifstream file( m_Params.m_sWordsFile.c_str() );
		if(!file)
			throw std::runtime_error( "Cannot open file: " + m_Params.m_sWordsFile );

		std::string line;
		while( std::getline(file,line) )
		{
			boost::trim(line);
			if(line.length() )
				m_setWords.insert(line);
		}

		std::cout << "Loaded " << m_setWords.size() << " unique words from " << m_Params.m_sWordsFile << std::endl;
	}

}//namespace filtrator
