#ifndef _NICE_OBJREC_GENERICCLASSIFIERSELECTION_INCLUDE
#define _NICE_OBJREC_GENERICCLASSIFIERSELECTION_INCLUDE

//STL
#include <vector>

//core
#include "core/basics/StringTools.h"


//vislearning  -- vector classifiers
#include "vislearning/classifier/vclassifier/VCAmitSVM.h"
#include "vislearning/classifier/vclassifier/VCNearestClassMean.h"
#include "vislearning/classifier/vclassifier/VCSimpleGaussian.h"
#include "vislearning/classifier/vclassifier/VCNearestNeighbour.h"
#include "vislearning/classifier/vclassifier/VCCrossGeneralization.h"
#include "vislearning/classifier/classifierinterfaces/VCFeaturePool.h"
#include "vislearning/classifier/vclassifier/VCOneVsOne.h"
#include "vislearning/classifier/vclassifier/VCOneVsAll.h"
#include "vislearning/classifier/vclassifier/VCDTSVM.h"
#include "vislearning/classifier/vclassifier/VCTransform.h"

//vislearning -- kernel classifiers
#include "vislearning/classifier/kernelclassifier/KCGPRegression.h"
#include "vislearning/classifier/kernelclassifier/KCGPLaplace.h"
#include "vislearning/classifier/kernelclassifier/KCGPLaplaceOneVsAll.h"
#include "vislearning/classifier/kernelclassifier/KCOneVsAll.h"
#include "vislearning/classifier/kernelclassifier/KCGPRegOneVsAll.h"
#include "vislearning/classifier/kernelclassifier/KCMinimumEnclosingBall.h"
#include "vislearning/classifier/kernelclassifier/KCGPOneClass.h"

//vislearning -- kernels
#include "vislearning/math/kernels/KernelStd.h"
#include "vislearning/math/kernels/KernelExp.h"
#include "vislearning/math/kernels/KernelRBF.h"
#include "vislearning/math/kernels/genericKernel.h"

//vislearning -- feature pool classifier
#include "vislearning/classifier/fpclassifier/boosting/FPCBoosting.h"
#include "vislearning/classifier/fpclassifier/randomforest/FPCRandomForests.h"
#include "vislearning/classifier/fpclassifier/randomforest/FPCDecisionTree.h"
#include "vislearning/classifier/fpclassifier/logisticregression/FPCSMLR.h"
#include "vislearning/classifier/fpclassifier/FPCGPHIK.h"

//vislearning -- classifier combinations
#include "vislearning/classifier/classifiercombination/VCPreRandomForest.h"


//vislearning -- SVM-based classifiers (vclassifier, kernelclassifier)
#ifdef NICE_USELIB_SVMLIGHT
#include "vislearning/classifier/vclassifier/VCSVMLight.h"
#include "vislearning/classifier/vclassifier/VCSVMOneClass.h"
#include "vislearning/classifier/kernelclassifier/KCSVMLight.h"
#endif

//external stuff
#ifdef NICE_USELIB_NICEDTSVM
#include "nice-dtsvm/VCTreeBasedClassifier.h"
#endif

// #include "gp-hik-exp/GPHIKClassifierNICE.h"







namespace OBJREC {

class GenericClassifierSelection
{
  public:

    static VecClassifier *selectVecClassifier ( const NICE::Config *conf, std::string classifier_type )
    {
      std::vector<std::string> submatches;
      VecClassifier *classifier = NULL;

      if ( classifier_type == "amit" ) {
        classifier = new VCAmitSVM ( conf );
     } else if ( classifier_type == "nn" ) {
	classifier = new VCNearestNeighbour( conf, new NICE::EuclidianDistance<double>() );
#ifdef NICE_USELIB_ICE 
     } else if ( classifier_type == "gauss" ) {
        classifier = new VCSimpleGaussian( conf );
     } else if ( classifier_type == "nearest_classmean" ) {
        classifier = new VCNearestClassMean( conf, new NICE::EuclidianDistance<double>() );
#endif
      }
      ////////////////////////////////////////
      //                                    //
      //    all Feature Pool Classifiers    //
      //                                    //
      ////////////////////////////////////////
      else if ( classifier_type == "GPHIK" ) {
        FeaturePoolClassifier *fpc = new FPCGPHIK ( conf, "GPHIK" );
        classifier = new VCFeaturePool ( conf, fpc );
      }      
      else if ( classifier_type == "random_forest" ) {
        FeaturePoolClassifier *fpc = new FPCRandomForests ( conf, "RandomForest" );
        classifier = new VCFeaturePool ( conf, fpc );
      }
      else if ( classifier_type == "sparse_logistic_regression" ) {
        FeaturePoolClassifier *fpc = new FPCSMLR ( conf, "SparseLogisticRegression" );
        classifier = new VCFeaturePool ( conf, fpc );

      } else if ( classifier_type == "boost" ) {
        FeaturePoolClassifier *fpc = new FPCBoosting ( conf, "Boost" );
        classifier = new VCFeaturePool ( conf, fpc );

      } else if ( classifier_type == "decision_tree" ) {
        FeaturePoolClassifier *fpc = new FPCDecisionTree ( conf, "DecisionTree" );
        classifier = new VCFeaturePool ( conf, fpc );
#ifdef NICE_USELIB_ICE
      } else if ( ( classifier_type == "cross_generalization" ) || ( classifier_type == "bart" ) ) {
        classifier = new VCCrossGeneralization ( conf );
#endif
#ifdef NICE_USELIB_SVMLIGHT
      } else if ( ( classifier_type == "svmlight" ) || ( classifier_type == "svm" ) ) {
        classifier = new VCSVMLight ( conf );
      } else if ( ( classifier_type == "svm_onevsone" ) ) {
        classifier = new VCOneVsOne ( conf, new VCSVMLight ( conf ) );
      } else if ( ( classifier_type == "svm_onevsall" ) ) {
        classifier = new VCOneVsAll ( conf, new VCSVMLight ( conf ) );
      } else if ( ( classifier_type == "svmlight_kernel" ) ) {
        classifier = new KCSVMLight ( conf, new KernelStd() );
      } else if ( ( classifier_type == "svm_one_class" ) ) {
        classifier = new VCSVMOneClass ( conf, "VCSVMLight" );
#endif
#ifdef NICE_USELIB_NICEDTSVM
        // this classifier requires nice-dtsvm, which is an optional
        // nice sub-library
      } else if ( classifier_type == "treebased" ) {
        classifier = new VCTreeBasedClassifier ( conf );
#endif
      } else if ( ( classifier_type == "dtgp" ) ) {
        classifier = new VCDTSVM ( conf );
      } else if ( ( classifier_type == "minimum_enclosing_ball" ) ) {
        std::string kernel_type = conf->gS ( "Kernel", "kernel_function", "rbf" );
        classifier = new KCMinimumEnclosingBall ( conf, GenericKernelSelection::selectKernel ( conf, kernel_type ) );
      } else if ( ( classifier_type == "gp_one_class" ) ) {
        std::string kernel_type = conf->gS ( "Kernel", "kernel_function", "rbf" );
        classifier = new KCGPOneClass ( conf, GenericKernelSelection::selectKernel ( conf, kernel_type ) );
      } else if ( ( classifier_type == "gp_regression_rbf" ) ) {
        std::string kernel_type = conf->gS ( "Kernel", "kernel_function", "rbf" );
        classifier = new KCGPRegression ( conf, GenericKernelSelection::selectKernel ( conf, kernel_type ) );
      } else if ( ( classifier_type == "gp_laplace_rbf" ) ) {
        std::string kernel_type = conf->gS ( "Kernel", "kernel_function", "rbf" );
        classifier = new KCGPLaplace ( conf, GenericKernelSelection::selectKernel ( conf, kernel_type ) );
      } else if ( ( classifier_type == "gp_regression_rbf_onevsall" ) ) {
        std::string kernel_type = conf->gS ( "Kernel", "kernel_function", "rbf" );
        classifier = new KCGPRegOneVsAll ( conf, GenericKernelSelection::selectKernel ( conf, kernel_type ) );
      } else if ( ( classifier_type == "gp_laplace_rbf_onevsall" ) ) {
        std::string kernel_type = conf->gS ( "Kernel", "kernel_function", "rbf" );
        classifier = new KCGPLaplaceOneVsAll ( conf, GenericKernelSelection::selectKernel ( conf, kernel_type ) );
      } else if ( NICE::StringTools::regexMatch ( classifier_type, "^one_vs_one\\(([^\\)]+)\\)$", submatches ) && ( submatches.size() == 2 ) ) {
        classifier = new VCOneVsOne ( conf, selectVecClassifier ( conf, submatches[1] ) );
      } else if ( NICE::StringTools::regexMatch ( classifier_type, "^one_vs_all\\(([^\\)]+)\\)$", submatches ) && ( submatches.size() == 2 ) ) {
        classifier = new VCOneVsAll ( conf, selectVecClassifier ( conf, submatches[1] ) );
      } else if ( NICE::StringTools::regexMatch ( classifier_type, "^random_forest\\(([^\\)]+)\\)$", submatches ) && ( submatches.size() == 2 ) ) {
        classifier = new VCPreRandomForest ( conf, "VCPreRandomForest", selectVecClassifier ( conf, submatches[1] ) );
      } else {
        fthrow ( NICE::Exception, "Classifier type " << classifier_type << " not (yet) supported." << std::endl <<
                 "(genericClassifierSelection.h contains a list of classifiers to choose from)" );
      }

      return classifier;
    }

};

}

#endif
