
#include <iostream>

#include "partialmsr/DBManagerMySQL.h"
#include "../compare/FunctionFactory2.h"

#include "PartialMSR2Base.h"


using namespace std;


namespace smartcomparator
{
	namespace simfunctions
	{


// STATIC
Matrices::SuperMatrixPtr PartialMSR2Base::LoadFrequencies(
	std::string const& pDir, std::string const& pName )
{
	return Matrices::IO::LoadSuperMatrix( pDir, pName, false, true );
}


void PartialMSR2Base::updateFeatures(
	Matrices::CRSMatrixPtr& 	pMtx,
	Matrices::FeatureVectorPtr& pRowsFeatures,
	Matrices::FeatureVectorPtr& pColumnsFeatures,
	bool 						pUpdateTf )
{
	Matrices::update_row_features( pMtx, pRowsFeatures, pUpdateTf );
	updateColumnFeatures( pMtx, pColumnsFeatures, pUpdateTf );
}


void PartialMSR2Base::updateColumnFeatures(
	Matrices::CRSMatrixPtr& 	pMtx,
	Matrices::FeatureVectorPtr& pColumnsFeatures,
	bool 						pUpdateTf )
{
	using namespace Matrices;

	double				tval;
	CompressedVector 	vector( std::map<size_t, double>(), pMtx->NumberOfRows() );

	for( size_t column = 0UL; column < pMtx->NumberOfColumns(); ++column ){
		for( size_t row = 0UL; row < pMtx->NumberOfRows(); ++row ){
			tval = pMtx->GetCell( row, column );
			if( tval != 0.0 )
				vector.GetValues()->insert( std::pair<size_t, double>( row, tval ) );
		}

		Feature &f = (*pColumnsFeatures)[column];

		if( pUpdateTf )
			f.SetTermFrequnecy( Measures::CountVectorSum( vector ) );
		f.SetNZ( vector.GetValues()->size() );
		f.SetEntropy(Measures::CountVectorEntropy( vector ) );

		vector.GetValues()->clear();
	}
}

boost::shared_ptr< std::vector<double> > PartialMSR2Base::countFeaturesMeans( Matrices::SuperMatrixPtr& pMtx ){
	size_t columnsCount = pMtx->NumberOfColumns();
	size_t rowsCount	= pMtx->NumberOfRows();

	boost::shared_ptr< std::vector<double> > 	means( new std::vector<double>( columnsCount, 0.0 ) );
	std::vector<size_t> 						counters( columnsCount, 0UL );

	for( size_t r=0UL; r<rowsCount; ++r ){
		std::map<size_t, double>& row 			= *( pMtx->GetRow( r )->GetValues() );
		std::map<size_t, double>::iterator iter = row.begin();
		std::map<size_t, double>::iterator end	= row.end();
		for(; iter != end; ++iter ){
			(*means)[ iter->first ] += iter->second;
			++counters[ iter->first ];
		}
	}

	// czy nie zawsze bedzie wieksze od zera?
	for( size_t r=0UL; r<columnsCount; ++r )
		if( counters[ r ] != 0UL )
			(*means)[ r ] /= counters[ r ];

	return means;
}

double PartialMSR2Base::findFeaturesEntrophyMargin(
	Matrices::FeatureVector const& 	pFeatures,
	double 							pPercentToRemove )
{
	std::vector<double> vec( pFeatures.size() );
	for( size_t f=0UL; f<pFeatures.size(); ++f )
		vec[f] = pFeatures[f].GetEntropy();
	std::sort( vec.begin(), vec.end() );
	return vec[ (1.0 - pPercentToRemove) * ( pFeatures.size()-1 ) ];
}


boost::shared_ptr< std::set<size_t> > PartialMSR2Base::findFeaturesByEntrophy(
	Matrices::FeatureVector const& 	pFeatures,
	double 							pPercentToRemove )
{
	double margin = findFeaturesEntrophyMargin( pFeatures, pPercentToRemove );
	boost::shared_ptr< std::set<size_t> > forbiddenFeatures( new std::set<size_t>() );
	for( size_t f=0UL; f<pFeatures.size(); ++f )
		if( pFeatures[f].GetEntropy() >= margin )
			forbiddenFeatures->insert( f );
	return forbiddenFeatures;
}


boost::shared_ptr< std::vector<size_t> > PartialMSR2Base::buildFeaturesMapping(
	Matrices::SuperMatrixPtr 	pMtxFrom,
	Matrices::SuperMatrixPtr 	pMtxTo )
{
	using namespace Matrices;

	FeatureVector const& srcFeatures = ( *pMtxFrom->GetColumnFeatures() );

	boost::shared_ptr< std::vector<size_t> > mapping( new std::vector<size_t>(
		srcFeatures.size(), static_cast<size_t>( -1 ) ) );

	for( size_t f=0UL; f<srcFeatures.size(); ++f )
		(*mapping)[f] = pMtxTo->GetColumnIndex( srcFeatures[f].GetLabel() );

	return mapping;
}


// NON-STATIC
PartialMSR2Base::PartialMSR2Base(
	Matrices::SuperMatrixPtr&	pWeightsMatrix,
	SimilarityFunctionPtr&		pSimilarityFunction,
	SynsetClassSetPtrS&			pSynsetClasses,
	Params&						pParams )
:
	SimilarityFunction( pWeightsMatrix ),
	mSimFunction( pSimilarityFunction ),
	mSynsetClasses( pSynsetClasses ),
	mMaxEntrophy( std::numeric_limits<double>::max() ),
	mParams( pParams )
{

}

PartialMSR2Base::~PartialMSR2Base(){

}


double PartialMSR2Base::MinValue() const
{
	return 0.0;
}


Matrices::SuperMatrixPtr PartialMSR2Base::getSuperMatrixCxF(){
	return mSmCxF;
}


SynsetClassSetPtrS PartialMSR2Base::getSynsetClasses(){
	return mSynsetClasses;
}


ClassIdsSetByLemmasMapPtrS PartialMSR2Base::getLemmasMapping(){
	return mLemmasMapping;
}


void PartialMSR2Base::init( Matrices::SuperMatrixPtr& pFrequencies ){
	std::cerr << "PartialMSR2Base: splitClasses()" << std::endl;
	splitClasses();

	std::cerr << "PartialMSR2Base: mapLemmasToClasses()" << std::endl;
	mapLemmasToClasses();

	std::cerr << "PartialMSR2Base: createMatrixCxF()" << std::endl;
	createMatrixCxF( pFrequencies );

	mMaxEntrophy 	= findFeaturesEntrophyMargin( *mSmCxF->GetColumnFeatures(), mParams.featuresPercentToRemove );
	mWWordsToWClass = buildFeaturesMapping( m_pMatrix, mSmCxF );

	std::cerr << "PartialMSR2Base: createMatrixCxF() done" << std::endl;
}


void PartialMSR2Base::splitClasses(){
	mSynsetClasses->splitClasses(
		mParams.numberOfClasses,
		mParams.minTreesCutEquality );
}


void PartialMSR2Base::mapLemmasToClasses(){
	mLemmasMapping = mSynsetClasses->mapLemmasToClasses();
}


void PartialMSR2Base::createMatrixCxF( Matrices::SuperMatrixPtr pFreqMatrix ){
	std::cerr << "PartialMSR2Base: createFeatureMatrixCxF()" << std::endl;
	mSmCxF = mSynsetClasses->createFeatureMatrixCF( mLemmasMapping, pFreqMatrix );

	std::cerr << "PartialMSR2Base: updateFeatures()" << std::endl;
	Matrices::FeatureVectorPtr 	v1 	= mSmCxF->GetRowFeatures();
	Matrices::FeatureVectorPtr 	v2 	= mSmCxF->GetColumnFeatures();
	Matrices::CRSMatrixPtr 		m 	= mSmCxF->GetCRS();
	updateFeatures( m, v1, v2, true );

	if( mParams.weightCmpFunction.length() > 0 ){
		std::cerr << "PartialMSR2Base: weightMatrixCxF()" << std::endl;
		weightMatrixCxF();

		std::cerr << "PartialMSR2Base: updateFeatures()" << std::endl;
		updateFeatures( m, v1, v2, true );
	}
}


void PartialMSR2Base::weightMatrixCxF(){
	smartcomparator::compare::CompareFunctionPtr wf =
		smartcomparator::compare::FunctionFactory::CreateFunction(
			mParams.weightCmpFunction, mSmCxF );

	wf->WeightMatrix();
}

	}
}


