/*
    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 "arch_headers.h"
#include "MatrixSaver.h"
#include "Config.h"

#define FEATURE_ENTROPY "entropy"
#define FEATURE_TF "tf"
#define FEATURE_GLOBAL_TF "global-tf"
#define FEATURE_DESC_ID "desc_id"
#define FEATURE_DESC "desc"
#define FEATURE_NZ "nz"

static log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("SuperMatrix.parallel.hal_architect.MatrixSaver"));

namespace hal_architect
{

	void MatrixSaver::SaveToSuperMatrix ( Matrices::CRSMatrixPtr crs, size_t unitscount,std::map<std::string, int> wordTF)
	{
		using namespace Matrices;
		CCSMatrix *ccs = new CCSMatrix("data",0,0);
		crs->Clone(ccs);
		pCCS = CCSMatrixPtr(ccs);
		pCRS = crs;

		PrepareFeatures(wordTF);

		Config *c = Config::GetInstance();

		SuperMatrixPtr supermatrix( new SuperMatrix( c->m_sMatrixName, pCCS, pCRS, 
					row_features, column_features, unitscount, c->m_sCorpusInfo) ) ;

		Matrices::IO::SuperMatrixWriter writer;
		LOG4CXX_INFO(logger,"Saving matrix...");
		writer.Write(supermatrix, c->workdir);

		pCCS.reset();
		pCRS.reset();
		row_features.reset();
		column_features.reset();
	}
	void MatrixSaver::getLabels()
	{
		rowLabels.clear();
		colLabels.clear();
		std::vector<LexicalUnits::LexicalUnitPtr> LUVector = ::hal_architect::Config::GetInstance()->m_vLexicalUnits;
		std::vector<size_t> rowLU = ::hal_architect::Config::GetInstance()->rowLU;
		std::vector<size_t> columnLU = ::hal_architect::Config::GetInstance()->columnLU;
		Corpus::CWordDictionary *dict = Corpus::CWordDictionary::GetInstance();
		for(std::vector<size_t>::iterator iter = rowLU.begin();iter!=rowLU.end();iter++)
		{
			int bufferLength=2; // ":", '\0'
			bufferLength+=(dict->GetAt(LUVector[(*iter)]->GetBaseId())).length();
			bufferLength+=strlen(Corpus::CTag::GetFlexClassString(LUVector[(*iter)]->GetFlexClass()));
			char* buffer = new char[bufferLength];

			strcpy(buffer,Corpus::CTag::GetFlexClassString(LUVector[(*iter)]->GetFlexClass()));
			buffer[strlen(Corpus::CTag::GetFlexClassString(LUVector[(*iter)]->GetFlexClass()))] = ':';
			strcpy(&(buffer[strlen(Corpus::CTag::GetFlexClassString(LUVector[(*iter)]->GetFlexClass()))+1]),
				   dict->GetAt(LUVector[(*iter)]->GetBaseId()).c_str());

			rowLabels.push_back(std::string(buffer));
			delete buffer;
		}

		for(std::vector<size_t>::iterator iter = columnLU.begin();iter!=columnLU.end();iter++)
		{
			int bufferLength=2; // ":", '\0'
			bufferLength+=(dict->GetAt(LUVector[(*iter)]->GetBaseId())).length();
			bufferLength+=strlen(Corpus::CTag::GetFlexClassString(LUVector[(*iter)]->GetFlexClass()));
			char* buffer = new char[bufferLength];

			strcpy(buffer,Corpus::CTag::GetFlexClassString(LUVector[(*iter)]->GetFlexClass()));
			buffer[strlen(Corpus::CTag::GetFlexClassString(LUVector[(*iter)]->GetFlexClass()))] = ':';
			strcpy(&(buffer[strlen(Corpus::CTag::GetFlexClassString(LUVector[(*iter)]->GetFlexClass()))+1]),
				   dict->GetAt(LUVector[(*iter)]->GetBaseId()).c_str());
			colLabels.push_back(std::string(buffer));

			delete buffer;

		}
	}

	void MatrixSaver::PrepareFeatures(std::map<std::string, int> wordTF)
	{
		getLabels();
		// row features...
		row_features = Matrices::FeatureVectorPtr( new Matrices::FeatureVector() );
		for( size_t row_no = 0; row_no < pCRS->NumberOfRows(); row_no++)
		{
			Matrices::CompressedVectorPtr v = pCRS->GetCompressedRow(row_no);
			double entropy = Measures::CountVectorEntropy( *v );
			size_t nz = v->GetValues()->size();
			size_t tf = (size_t) Measures::CountVectorSum( *v );
			size_t TF = wordTF[rowLabels[row_no]];
			row_features->push_back( Matrices::Feature(rowLabels[row_no], nz, tf, TF, entropy) ) ;
			if( row_no % 100 == 0)
				LOG4CXX_INFO(logger,"Counting row features... " << row_no << " / " << pCRS->NumberOfRows() );
		}
		// column features...
		column_features = Matrices::FeatureVectorPtr( new Matrices::FeatureVector() );
		for( size_t column_no = 0; column_no < pCCS->NumberOfColumns(); column_no++)
		{
			Matrices::CompressedVectorPtr v = pCCS->GetCompressedColumn(column_no);
			double entropy = Measures::CountVectorEntropy( *v );
			size_t nz = v->GetValues()->size();
			size_t tf = (size_t) Measures::CountVectorSum( *v );
			size_t TF = wordTF[colLabels[column_no]];
			column_features->push_back( Matrices::Feature(colLabels[column_no], nz, tf, TF, entropy) );
			if( column_no % 100 == 0)
				LOG4CXX_INFO(logger, "Counting column features... " << column_no << " / " << pCCS->NumberOfColumns());
		}

	}
}
