/**
* @file KernelClassifier.h
* @brief classifier interface for kernel based methods
* @author Erik Rodner
* @date 12/02/2009

*/
#ifndef KERNELCLASSIFIERINCLUDE
#define KERNELCLASSIFIERINCLUDE

#include "vislearning/math/kernels/Kernel.h"
#include "vislearning/math/kernels/KernelData.h"
#include "core/vector/VVector.h"

#include "vislearning/cbaselib/ClassificationResult.h"
#include "vislearning/cbaselib/LabeledSet.h"
#include "vislearning/classifier/classifierbase/VecClassifier.h"

namespace OBJREC
{

/** classifier interface for kernel based methods */
class KernelClassifier : public VecClassifier
{
  public:
    enum
    {
      KERNELCLASSIFIER_NORMALIZATION_EUCLIDEAN = 0,
      KERNELCLASSIFIER_NORMALIZATION_NONE
    };

  protected:

    /** This variable might be NULL, if you do not specify a kernel function */
    Kernel *kernelFunction;

    /** This is the training set, if you specify a kernel function */
    NICE::VVector vecSet;

    /** These are the labels of the training set, if you specify a kernel function */
    NICE::Vector vecSetLabels;

    /** Maybe you want to normalize feature vectors before training */
    int normalizationType;

    /** stored config to initialize KernelData with noiseSigma, cholesky method etc. */
    NICE::Config conf;

  public:
    /** simple constructor */
    KernelClassifier() {};

    /** specify a kernel function which works on vectors and a normalization method ( use the enum defined in KernelClassifier ) */
    KernelClassifier ( const NICE::Config *conf, Kernel *kernelFunction = NULL, int normalizationType = KERNELCLASSIFIER_NORMALIZATION_EUCLIDEAN );

    /** copy constructor which you should also call in subclasses */
    KernelClassifier ( const KernelClassifier & src );

    /** simple destructor */
    virtual ~KernelClassifier();


    // interface function

    /** teach the classifier with a kernel matrix and the corresponding class labels @param y ! */
    virtual void teach ( KernelData *kernelData, const NICE::Vector & y ) = 0;

    /** classify an example by using its kernel values with the training set,
     be careful with the order in @param kernelVector */
    virtual ClassificationResult classifyKernel ( const NICE::Vector & kernelVector, double kernelSelf ) const = 0;


    // functions to build an interface to VecClassifier

    /** classify using simple vector, this works only if you specify a kernel function */
    ClassificationResult classify ( const NICE::Vector & x ) const;

    /** teach classifier with a labeled set of feature vectors, this works only if you specify a kernel function */
    virtual void teach ( const LabeledSetVector & teachSet );

    /** calculate classifier stuff as the last training step, pretty useless, deprecated */
    void finishTeaching() {};

    /** clone this object */
    KernelClassifier *clone ( void ) const
    {
      fthrow ( NICE::Exception, "clone() not yet implemented." );
    }

    Kernel *getKernelFunction () const
    {
      return kernelFunction;
    };

    virtual void restore ( std::istream&, int );
    virtual void store ( std::ostream&, int ) const;
};

}

#endif
