/*
    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.
*/

#ifndef SMARTCOMPARATOR_FUNCTIONFACTORY2_H
#define SMARTCOMPARATOR_FUNCTIONFACTORY2_H
#include "../comparator_stdheaders.h"
#include "../comparator_all.h"

namespace smartcomparator
{
	namespace compare
	{
		typedef std::map<std::string, std::string> STR2STR;

		class FunctionFactory2
		{
		public:
			FunctionFactory2();

			CompareFunctionPtr CreateComparator(const std::string& filter_str,
							    Matrices::SuperMatrixPtr matrix);

			CompareFunctionPtr CreateComparatorEnsemble(const std::string& filter_str,
							    Matrices::SuperMatrixPtr matrix);

			filters::FilterFeaturePtr CreateFilter(const std::string& filter_str,
							       Matrices::SuperMatrixPtr matrix);
			selectors::SelectorPtr CreateSelector(const std::string& selector_str,
							      Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeigher(const std::string& weigher_str,
								Matrices::SuperMatrixPtr matrix);
			weights::RankBuilderPtr CreateRankBuilder(const std::string& rank_str,
								  Matrices::SuperMatrixPtr matrix);
			weights::LocalWeightFeaturePtr CreateLocalWeigher(const std::string& weigher_str);
			simfunctions::SimilarityFunctionPtr CreateSimfunction(const std::string& simfunction_str,
									      Matrices::SuperMatrixPtr matrix);
			transformations::TransformationPtr CreateTransformation(const std::string& transformation_str,
										Matrices::SuperMatrixPtr matrix);
			selectors::RowRelativeSelectorPtr CreateRowRelativeSelector(const std::string& relativeselector_str,
										    Matrices::SuperMatrixPtr matrix);
			simfunctions::LocalSimilarityFunctionPtr CreateLocalSimfunction(const std::string& simfunction_str);
			distances::DistanceFunctionPtr CreateDistfunction(const std::string& relativeselector_str,
									  Matrices::SuperMatrixPtr matrix);
		protected:
			std::vector<std::string> legal_comparator_args;
			std::vector<std::string> legal_ensemble_args;
			std::map<std::string, std::vector<std::string> > legal_filter_args;
			std::map<std::string, std::vector<std::string> > legal_selector_args;
			std::map<std::string, std::vector<std::string> > legal_weigher_args;
			std::map<std::string, std::vector<std::string> > legal_rank_args;
			std::map<std::string, std::vector<std::string> > legal_localweigher_args;
			std::map<std::string, std::vector<std::string> > legal_simfunction_args;
			std::map<std::string, std::vector<std::string> > legal_relativeselector_args;
			std::map<std::string, std::vector<std::string> > legal_localsimfunction_args;
			std::map<std::string, std::vector<std::string> > legal_distfunction_args;
			std::map<std::string, std::vector<std::string> > legal_transformation_args;

			std::map<std::string, boost::function<filters::FilterFeaturePtr (FunctionFactory2*, std::map<std::string, std::string>&, Matrices::SuperMatrixPtr)> > filter_functions;
			std::map<std::string, boost::function<selectors::SelectorPtr (FunctionFactory2*, std::map<std::string, std::string>&, Matrices::SuperMatrixPtr)> > selector_functions;
			std::map<std::string, boost::function<weights::WeightFeaturePtr (FunctionFactory2*, std::map<std::string, std::string>&, Matrices::SuperMatrixPtr)> > weight_functions;
			std::map<std::string, boost::function<weights::RankBuilderPtr (FunctionFactory2*, std::map<std::string, std::string>&, Matrices::SuperMatrixPtr)> > rank_functions;
			std::map<std::string, boost::function<weights::LocalWeightFeaturePtr (FunctionFactory2*, std::map<std::string, std::string>&)> > localweight_functions;
			std::map<std::string, boost::function<simfunctions::SimilarityFunctionPtr (FunctionFactory2*, std::map<std::string, std::string>&, Matrices::SuperMatrixPtr)> > simfunctions_functions;
			std::map<std::string, boost::function<selectors::RowRelativeSelectorPtr (FunctionFactory2*, std::map<std::string, std::string>&, Matrices::SuperMatrixPtr)> > relativeselector_functions;
			std::map<std::string, boost::function<simfunctions::LocalSimilarityFunctionPtr (FunctionFactory2*, std::map<std::string, std::string>&)> > localsimfunctions_functions;
			std::map<std::string, boost::function<distances::DistanceFunctionPtr (FunctionFactory2*, std::map<std::string, std::string>&, Matrices::SuperMatrixPtr)> > distfunctions_functions;
			std::map<std::string, boost::function<CompareFunctionPtr (FunctionFactory2*, std::map<std::string, std::string>&, Matrices::SuperMatrixPtr)> > complexcomparator_functions;
			std::map<std::string, boost::function<transformations::TransformationPtr (FunctionFactory2*, std::map<std::string, std::string>&, Matrices::SuperMatrixPtr)> > transformation_functions;

			void getNameAndArgs(const std::string& str, std::string& name, std::string& args);
			void PrepareArgsOld(const std::string &args, std::map<std::string, std::string> & name2val);
			void PrepareArgs(const std::string &args, std::map<std::string, std::string> & name2val, std::string & identifier,
					 std::vector<std::string> & legal_args);

			void initComparators();

			void initFilters();
			void initFilterFeature01();
			void initFilterVector();
			void initNoiseKFilter();
			void initNoiseKTFFilter();
			void initEntropyFilter();

			void initSelectors();
			void initFrequencySelector();
			void initTScoreSelector();
			void initTScoreKBestSelector();
			void initRFFSelector();

			void initWeights();
			void initWeightCRMDt();
			void initWeightCRmDmi();
			void initWeightIdf();
			void initWeightLogEntNormalize();
			void initWeightLogEnt();
			void initWeightMI();					// korzystać z tej wagi
			void initWeightMIQuantified();
			void initWeightMLE();
			void initWeightNormalize();
			void initWeightRFF();					// długo się liczy...
			void initWeightRWF();
			void initWeightRWFChi2();
			void initWeightRWFEvertsMI();
			void initWeightRWFLinFiltered();
			void initWeightRWFLin();
			void initWeightRWFLogLikelihood();
			void initWeightRWFNoWeight();
			void initWeightRWFPMI();
			void initWeightRWFZScore();
			void initWeightRWFZScoreInMatrix();
			void initWeightRWFZScoreLocal();
			void initWeightPMINoLog();				// podobno najlepsza, powstała przez przypadek, chyba...
			void initWeightSimpleMI();
			void initWeightTScore();
			void initWeightTfidfNormalize();
			void initWeightTfidf();
			void initWeightRowScaled();
			void initWeightColumnScaled();
			void initWeightBoundaryScaled();
			void initWeightQuantify();
			void initWeightLogLikelihood();
			void initWeightChi2();
			void initWeightZScore();
			void initWeightZScoreMatrix();
			void initWeightZScoreLocal();
			void initWeightEvertsMI();
			void initWeightBeta();
			void initWeightFirstKulczynsky();
			void initWeightUnigramSubtuples();
			void initWeightSCost();

			void initRankBuilders();
			void initRankNormal();
			void initRankPartial();
			void initRankRoundingBasedPartial();

			void initLocalWeights();
			void initLocalWeightLogEnt();

			void initDistfunctions();
			void initDistfunctionMinkowski();
			void initDistfunctionEuclid();

			void initSimfunctions();
			void initSimfunctionCosineFilter();
			void initSimfunctionCosine();				// Cosine korzysta się głównie z tego
			void initSimfunctionDice();					// Dice
			void initSimfunctionDiceBugged();
			void initSimfunctionEhlert();
			void initSimfunctionJaccard();				// Jaccard
			void initSimfunctionLin();
			void initSimfunctionMCF();					// o tym wspomniał też Maciek
			void initSimfunctionPEntP();
			void initSimfunctionSHD();
			void initSimfunctionCRM();
			void initSimfunctionFile();
			void initSimfunctionDistance();
			void initSimfunctionRatio();
			void initSimfunctionIntersectionScaled();
			void initSimfunctionPartialMSR();
			void initParamsForPartialMSR2( std::vector<std::string>& pParams );
			void initSimfunctionPartialMSR2A();
			void initSimfunctionPartialMSR2B();
			void initSimfunctionPartialMSR2Bp();
			void initSimfunctionBhattacharyya();

			void initLocalSimfunctions();
			void initLocalSimfunctionLocalCosine();
			void initLocalSimfunctionIRad();

			void initRowRelativeSelectors();
			void initRowRelativeSelectorTScoreKBest();

			void initTransformations();
			void initSVDTransformation();
			void initTransformationLDA();

			filters::FilterFeaturePtr CreateFilterFeature01(std::map<std::string, std::string> & args,
									Matrices::SuperMatrixPtr matrix);
			filters::FilterFeaturePtr CreateFilterVector(std::map<std::string, std::string> & args,
								     Matrices::SuperMatrixPtr matrix);
			filters::FilterFeaturePtr CreateFilterNoiseKTF(std::map<std::string, std::string> & args,
								       Matrices::SuperMatrixPtr matrix);
			filters::FilterFeaturePtr CreateFilterNoiseK(std::map<std::string, std::string> & args,
								     Matrices::SuperMatrixPtr matrix);
			filters::FilterFeaturePtr CreateEntropyFilter(std::map<std::string, std::string> & args,
									 Matrices::SuperMatrixPtr matrix);

			selectors::SelectorPtr CreateSelectorFrequency(std::map<std::string, std::string> & args,
								       Matrices::SuperMatrixPtr matrix);
			selectors::SelectorPtr CreateSelectorTScore(std::map<std::string, std::string> & args,
								    Matrices::SuperMatrixPtr matrix);
			selectors::SelectorPtr CreateSelectorTScoreKBest(std::map<std::string, std::string> & args,
									 Matrices::SuperMatrixPtr matrix);
			selectors::SelectorPtr CreateSelectorRFF(std::map<std::string, std::string> & args,
								 Matrices::SuperMatrixPtr matrix);

			selectors::RFFSelectorPtr RFFCreateSelectorRFF(std::map<std::string, std::string> & args,
								       Matrices::SuperMatrixPtr matrix);
			selectors::RowRelativeSelectorPtr CreateRowRelativeSelectorTScoreKBest(std::map<std::string, std::string> & args,
											       Matrices::SuperMatrixPtr matrix);

			weights::WeightFeaturePtr CreateWeightCRMDt(std::map<std::string, std::string> & args,
								    Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightCRmDmi(std::map<std::string, std::string> & args,
								     Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightIdf(std::map<std::string, std::string> & args,
								    Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightLogEntNormalize(std::map<std::string, std::string> & args,
									      Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightLogEnt(std::map<std::string, std::string> & args,
								     Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightMI(std::map<std::string, std::string> & args,
								 Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightMIQuantified(std::map<std::string, std::string> & args,
									   Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightMLE(std::map<std::string, std::string> & args,
								  Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightNormalize(std::map<std::string, std::string> & args,
									Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightRFF(std::map<std::string, std::string> & args,
								  Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightRWFChi2(std::map<std::string, std::string> & args,
								      Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightRWFEvertsMI(std::map<std::string, std::string> & args,
									  Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightRWFLinFiltered(std::map<std::string, std::string> & args,
									     Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightRWFLin(std::map<std::string, std::string> & args,
								     Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightRWFLogLikelihood(std::map<std::string, std::string> & args,
									       Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightRWFNoWeight(std::map<std::string, std::string> & args,
									  Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightRWFPMI(std::map<std::string, std::string> & args,
								     Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightRWFZScore(std::map<std::string, std::string> & args,
									Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightRWFZScoreInMatrix(std::map<std::string, std::string> & args,
										Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightRWFZScoreLocal(std::map<std::string, std::string> & args,
									     Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightSimpleMI(std::map<std::string, std::string> & args,
								       Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightTScore(std::map<std::string, std::string> & args,
								     Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightTfidfNormalize(std::map<std::string, std::string> & args,
									     Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightTfidf(std::map<std::string, std::string> & args,
								    Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightRowScaled(std::map<std::string, std::string> & args,
									Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightColumnScaled(std::map<std::string, std::string> & args,
									   Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightBoundaryScaled(std::map<std::string, std::string> & args,
									     Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightRWF(std::map<std::string, std::string> & args,
								  Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightQuantify(std::map<std::string, std::string> & args,
								       Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightPMINoLog(std::map<std::string, std::string> & args,
								       Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightLogLikelihood(std::map<std::string, std::string> & args,
								       Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightChi2(std::map<std::string, std::string> & args,
								       Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightZScore(std::map<std::string, std::string> & args,
								       Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightZScoreMatrix(std::map<std::string, std::string> & args,
								       Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightZScoreLocal(std::map<std::string, std::string> & args,
								       Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightEvertsMI(std::map<std::string, std::string> & args,
								       Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightBeta(std::map<std::string, std::string> & args,
								       Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightFirstKulczynsky(std::map<std::string, std::string> & args,
										Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightUnigramSubtuples(std::map<std::string, std::string> & args,
										Matrices::SuperMatrixPtr matrix);
			weights::WeightFeaturePtr CreateWeightSCost(std::map<std::string, std::string> & args,
										Matrices::SuperMatrixPtr matrix);


			weights::RankBuilderPtr CreateRankNormal(std::map<std::string, std::string> & args,
								 Matrices::SuperMatrixPtr matrix);
			weights::RankBuilderPtr CreateRankPartial(std::map<std::string, std::string> & args,
								  Matrices::SuperMatrixPtr matrix);
			weights::RankBuilderPtr CreateRankRoundingBasedPartial(std::map<std::string, std::string> & args,
									       Matrices::SuperMatrixPtr matrix);

			weights::LocalWeightFeaturePtr CreateLocalWeightLogEnt(std::map<std::string, std::string> & args);


			simfunctions::SimilarityFunctionPtr CreateSimfunctionCosineFilter(std::map<std::string, std::string> & args,
											  Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionCosine(std::map<std::string, std::string> & args,
										    Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionDice(std::map<std::string, std::string> & args,
										  Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionDiceBugged(std::map<std::string, std::string> & args,
										  Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionEhlert(std::map<std::string, std::string> & args,
										    Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionJaccard(std::map<std::string, std::string> & args,
										     Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionLin(std::map<std::string, std::string> & args,
										 Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionMCF(std::map<std::string, std::string> & args,
										 Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionPEntP(std::map<std::string, std::string> & args,
										   Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionSHD(std::map<std::string, std::string> & args,
										 Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionCRM(std::map<std::string, std::string> & args,
										 Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionFile(std::map<std::string, std::string> & args,
										  Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionDistance(std::map<std::string, std::string> & args,
										      Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionRatio(std::map<std::string, std::string> & args,
										   Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionIntersectionScaled(std::map<std::string, std::string> & args,
												Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionPartialMSR(std::map<std::string, std::string> & args,
										Matrices::SuperMatrixPtr matrix);
			void								verifyParamsForPartialMSR2( std::map<std::string, std::string> const& pParams );
			simfunctions::SimilarityFunctionPtr CreateSimfunctionPartialMSR2A(std::map<std::string, std::string> & args,
										Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionPartialMSR2B(std::map<std::string, std::string> & args,
										Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionPartialMSR2Bp(std::map<std::string, std::string> & args,
										Matrices::SuperMatrixPtr matrix);
			simfunctions::SimilarityFunctionPtr CreateSimfunctionBhattacharyya(std::map<std::string, std::string> & args,
									    Matrices::SuperMatrixPtr matrix);


			simfunctions::LocalSimilarityFunctionPtr CreateLocalSimfunctionLocalCosine(std::map<std::string, std::string> & args);
			simfunctions::LocalSimilarityFunctionPtr CreateLocalSimfunctionIRad(std::map<std::string, std::string> & args);

			distances::DistanceFunctionPtr CreateDistfunctionMinkowski(std::map<std::string, std::string> & args,
										   Matrices::SuperMatrixPtr matrix);
			distances::DistanceFunctionPtr CreateDistfunctionEuclid(std::map<std::string, std::string> & args,
										Matrices::SuperMatrixPtr matrix);

			transformations::TransformationPtr CreateTransformationSVD(std::map<std::string, std::string> & args,
										   Matrices::SuperMatrixPtr matrix);
			transformations::TransformationPtr CreateTransformationLDA(std::map<std::string, std::string> & args,
										   Matrices::SuperMatrixPtr matrix);

			CompareFunctionPtr CreateDomainComparator(std::map<std::string, std::string> & args,
								  Matrices::SuperMatrixPtr matrix);

		};
	}//compare
}//smartcomparator

#endif //SMARTCOMPARATOR_FUNCTIONFACTORY2_H
