/*
    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 "../comparator_stdheaders.h"
#include "RFFWeight.h"
#include "../../matrices/io/CRSMatrixReader.h"

namespace smartcomparator
{
	namespace weights
	{


		RFFWeight::RFFWeight(Matrices::SuperMatrixPtr m, Matrices::CRSMatrixPtr SimMatrix, size_t top_k,double simThreshold,selectors::RFFSelectorPtr selectorPtr)
			: WeightFeature(m),
			m_pSimMatrix(SimMatrix),
			m_stTopK(top_k),
			m_dsimThreshold(simThreshold),
			rffSelector(selectorPtr)
		{
			if (m_pSimMatrix->NumberOfRows() != m->NumberOfRows())
			{
				throw std::runtime_error("RFF error: target matrix and similarity matrix row numbers are not equal.");
			}
		}
		RFFWeight::RFFWeight(Matrices::SuperMatrixPtr m, std::string SimMatrixPath, size_t top_k,double simThreshold,selectors::RFFSelectorPtr selectorPtr)
			: WeightFeature(m),
			m_pSimMatrix(Matrices::IO::ReadCRSFromSingleFile(SimMatrixPath, "simmatrix")),
			m_stTopK(top_k),
			m_dsimThreshold(simThreshold),
			rffSelector(selectorPtr)
		{
			if (m_pSimMatrix->NumberOfRows() != m->NumberOfRows())
			{
				throw std::runtime_error("RFF error: target matrix and similarity matrix row numbers are not equal.");
			}

		}

		//		RFFWeight::RFFWeight(Matrices::SuperMatrixPtr m, Matrices::SymmetricSimMatrixPtr pSimMatrix, size_t top_k, double sim_treshold)
		//			: WeightFeature(m),
		//			m_pSimMatrix(pSimMatrix),
		//			m_stTopK(top_k),
		//			m_dsimThreshold(sim_treshold)
		//		{
		//			if(m->GetColumn(0) == NULL )
		//				throw std::runtime_error( "Load matrix " + m->GetName() + " with columns too.");
		//		}
		//
		//		RFFWeight::RFFWeight(Matrices::SuperMatrixPtr m, compare::CompareFunctionPtr pCmp, size_t top_k, double sim_treshold )
		//			: WeightFeature(m),
		//			m_stTopK(top_k),
		//			m_pCmp(pCmp),
		//			m_dsimThreshold(sim_treshold)
		//		{
		//		}

		RFFWeight::~RFFWeight(void)
		{
		}

		void RFFWeight::Weight(size_t rowindex, Matrices::CompressedVector *v, 	std::set<size_t> &filteredIndices)
		{
			std::multimap< double, size_t > rff;
			for(std::set<size_t>::iterator column_no = filteredIndices.begin(); column_no != filteredIndices.end(); column_no++)
			{
				if((rffSelector->CheckIfValueIsRemoved(rowindex, *column_no)))
					continue;
				Matrices::CompressedVectorPtr col = m_pMatrix->GetColumn( *column_no );
				double sum_sim = 0;
				for(Matrices::STDoubleMapIter ws_iter = col->GetValues()->begin(); ws_iter != col->GetValues()->end(); ws_iter++)
				{
					if(rowindex == ws_iter->first)
						continue;
					if((!rffSelector->CheckIfValueIsRemoved(ws_iter->first, *column_no)))
					{
						double sim = m_pSimMatrix->GetCell(rowindex, ws_iter->first);
						if(sim >= m_dsimThreshold)
							sum_sim+=sim;
					}
				}
				if(sum_sim > 0)
					rff.insert( std::pair<double, size_t> ( sum_sim, *column_no ) );
			}
			std::map<size_t, double> *vals = v->GetValues();
			vals->clear();
			filteredIndices.clear();
			size_t inserted = 0;
			Matrices::FeatureVectorPtr row_features = m_pMatrix->GetRowFeatures();
			Matrices::FeatureVectorPtr col_features = m_pMatrix->GetColumnFeatures();
			//std::cout << "Best features for " << (*row_features)[rowindex].GetLabel() << ": ";
			for(std::multimap<double,size_t>::reverse_iterator iter = rff.rbegin(); iter != rff.rend() && inserted < m_stTopK; iter++, inserted++)
			{
				(*vals)[iter->second] = iter->first;
				filteredIndices.insert( iter->second );
				//std::cout << (*col_features)[iter->second].GetLabel() << "(" << iter->first << "), ";
			}

			//std::cout << std::endl << std::endl;
		}

	}
}
