
#include "../comparator_stdheaders.h"
#include "../comparator_precompiled.h"
#include "PartialMSR.h"

namespace smartcomparator
{
	namespace simfunctions
	{

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

		PartialMSR::IndicesPtr PartialMSR::ReadBadFeatures( std::string const& pFile ){
		//	CheckFile( pFile );

			std::ifstream stream( pFile.c_str() );
			if( !stream.is_open() ){
				throw Matrices::IO::filesystem_error("PartialMSR::ReadBadFeatures",
						std::string("Cannot open file: ") + pFile );
			}

			IndicesPtr indices( new Indices() );

			size_t index;
			while( !stream.eof() ){
				stream >> index;
				indices->insert( index );
			}

			return indices;
		}

		void PartialMSR::CheckFile( std::string const& pFile ){
			boost::filesystem::path file = boost::filesystem::path( pFile );
			file.normalize();

			if( !boost::filesystem::exists(file) )
				throw Matrices::IO::filesystem_error( "PartialMSR::CheckFile",
					std::string("File with indices dosn't exist: ") + file.string() );
		}


		PartialMSR::PartialMSR(
			Matrices::SuperMatrixPtr&	pWeightsMatrix,
			Matrices::SuperMatrixPtr&	pFrequencies,
			IndicesPtr&					pBadFeaturesIncides,
			SimilarityFunctionPtr&		pSimilarityFunction )
		:
			SimilarityFunction( pWeightsMatrix ),
			mBadFeatures( pBadFeaturesIncides ),
			mFrequenciesMatrix( pFrequencies ),
			mSimFunction( pSimilarityFunction )
		{
			Init();
		}

		PartialMSR::~PartialMSR(void)
		{
		}

		void PartialMSR::Init(){
			size_t size = m_pMatrix->GetColumnFeatures()->size();
			mFeatureWeightToFreq.resize( size );
			for( size_t wi=0; wi<size; ++wi ){
				mFeatureWeightToFreq[ wi ] = findFeatureFreqIndex( wi );
			}
		}

		double PartialMSR::CountSimilarity(
			Matrices::CompressedVector& pWeights1,
			Matrices::CompressedVector& pWeights2,
			const std::set<size_t>&		pNonZeroIndices1,
			const std::set<size_t>&		pNonZeroIndices2 )
		{
			throw new Matrices::IO::filesystem_error(
					"PartialMSR::CountSimilarity local version",
					"Lemmas indices are required!");
			//return CountSimilarity( pWeights1, pWeights2, -1, -1, pNonZeroIndices1, pNonZeroIndices2 );
		}

		double PartialMSR::CountSimilarity(
			Matrices::CompressedVector& pWeights1,
			Matrices::CompressedVector& pWeights2,
			size_t 						pLemmaIndex1,
			size_t 						pLemmaIndex2,
			const std::set<size_t>&		pNonZeroFeaturesIndices1,
			const std::set<size_t>&		pNonZeroFeaturesIndices2 )
		{
			bool canBeComputed = false;

			size_t freqIdx1 = findWordFreqIndex( pLemmaIndex1 );
			size_t freqIdx2 = findWordFreqIndex( pLemmaIndex2 );

			if(freqIdx1 != static_cast<size_t>(-1) && freqIdx2 != static_cast<size_t>(-1)){
				Matrices::CompressedVectorPtr freqs1( mFrequenciesMatrix->GetRow( freqIdx1 ) );
				Matrices::CompressedVectorPtr freqs2( mFrequenciesMatrix->GetRow( freqIdx2 ) );

				IndicesPtr lz1 = funZN( pNonZeroFeaturesIndices1, *freqs1, pWeights1 );
				IndicesPtr lz2 = funZN( pNonZeroFeaturesIndices2, *freqs2, pWeights2 );

				canBeComputed = funCZ(
					lz1, *freqs1, pWeights1,
					lz2, *freqs2, pWeights2 );
			}

			return canBeComputed ?
 				mSimFunction->CountSimilarity(
 					pWeights1, pWeights2,
 					pLemmaIndex1, pLemmaIndex2,
 					pNonZeroFeaturesIndices1, pNonZeroFeaturesIndices2 ) :
 				MinValue();
		}

		size_t PartialMSR::findWordFreqIndex( size_t pWeightLemmaIndex ){
			Matrices::FeatureVectorPtr featureVector = m_pMatrix->GetRowFeatures();
			std::string const& label = featureVector->at( pWeightLemmaIndex ).GetLabel();
			return mFrequenciesMatrix->GetRowIndex( label );
		}

		size_t PartialMSR::findFeatureFreqIndex( size_t	pWeightFeatureIndex ){
			Matrices::FeatureVectorPtr featureVector = m_pMatrix->GetColumnFeatures();
			std::string const& label = featureVector->at( pWeightFeatureIndex ).GetLabel();
			return mFrequenciesMatrix->GetColumnIndex( label );
		}

		PartialMSR::IndicesPtr PartialMSR::funZN(
			Indices const&			 	pNonZeroFeaturesIndices,
			Matrices::CompressedVector& pFrequencies,
			Matrices::CompressedVector& pWeights )
		{
			IndicesPtr indices( new Indices() );

			Indices::iterator end = pNonZeroFeaturesIndices.end();
			for( Indices::iterator iter = pNonZeroFeaturesIndices.begin(); iter != end; ++iter ){
				if( mFeatureWeightToFreq[ *iter ] != static_cast<size_t>(-1) &&
					pFrequencies[ mFeatureWeightToFreq[ *iter ] ] > 1UL )
						indices->insert( *iter );
			}

			return indices;
		}

		bool PartialMSR::funCZ(
			IndicesPtr& 				pLZ1,
			Matrices::CompressedVector&	pFrequencies1,
			Matrices::CompressedVector& pWeights1,
			IndicesPtr& 				pLZ2,
			Matrices::CompressedVector&	pFrequencies2,
			Matrices::CompressedVector& pWeights2 )
		{
			Indices intersec;

			std::set_intersection(
				pLZ1->begin(), pLZ1->end(),
				pLZ2->begin(), pLZ2->end(),
				std::insert_iterator<Indices>( intersec, intersec.begin() ) );

			if( intersec.size() >= 2UL )
				return true;

			if( intersec.size() == 1UL ){
				size_t c = *intersec.begin();
				for( Indices::iterator i=pLZ1->begin(); i!=pLZ1->end(); ++i){
					if( mFeatureWeightToFreq[ *i ] != static_cast<size_t>(-1) &&
						c != *i && pFrequencies2[ mFeatureWeightToFreq[ *i ] ] > 0UL )
						return true;
				}
				for( Indices::iterator i=pLZ2->begin(); i!=pLZ2->end(); ++i){
					if( mFeatureWeightToFreq[ *i ] != static_cast<size_t>(-1) &&
						c != *i && pFrequencies1[ mFeatureWeightToFreq[ *i ] ] > 0UL )
						return true;
				}
			}

			return false;
		}

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


	}
}
