/**
* @file Codebook.h
* @brief feature codebook
* @author Erik Rodner, Alexander Freytag
* @date 05-06-2013 (dd-mm-yyyy ) (original: 02/15/2008)
*/
#ifndef CODEBOOKINCLUDE
#define CODEBOOKINCLUDE


#include <string>

#include <core/basics/Config.h>
#include "core/basics/Persistent.h"
//
#include "core/image/ImageT.h"
#include "core/imagedisplay/ImageDisplay.h"
//
#include "core/vector/VectorT.h"
#include "core/vector/MatrixT.h"
#include "core/vector/SparseVectorT.h"


namespace OBJREC {

  /** feature codebook */
  class Codebook : virtual public NICE::Persistent
  {
    protected:
        NICE::Vector thresholds;
        NICE::Vector informativeMeasure;
        NICE::VectorT<int> classnos;
        
        /** if Soft Assignment or Hard Assignment instead of Vector Quantization, how many entries are allowed to be non-zero?*/
        int i_noOfNearestClustersToConsidere;
        
        NICE::Config * p_conf;
        std::string s_section;
        
        /** hard or soft assignment? */
        bool b_hardAssignment;

    public:

        /**
         * @brief simple constructor
         */
        Codebook ( );      
      
        /**
         * @brief standard constructor
         */
        Codebook ( const int & _noOfNearestClustersToConsidere);

         /**
         * @brief recommended constructor
         */
        Codebook( NICE::Config * _conf, const std::string & _section);

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

        //vote for a single feature vector
        /**
         * @brief Vector Quantization for a single vector
         * @date 11-06-2013 (dd-mm-yyyy)
         * @author Erik Rodner, Alexander Freytag
         * @param feature the feature that shall be quantized
         * @param codebookEntry the corresponding cluster index for the quantized feature
         * @param weight the weight of the nearest cluster
         * @param distance the distance to its nearest cluster
         */        
        virtual void voteVQ ( const NICE::Vector & feature, int & codebookEntry,
                            double & weight, double & distance ) const = 0;
                            
        /**
         * @brief Vector Quantization for a single vector, directly increases the corresponding entry in histogram 
         * @date 11-06-2013 (dd-mm-yyyy)
         * @author Erik Rodner, Alexander Freytag
         * @param feature the feature that shall be quantized
         * @param histogram a BoW-histogram already given (does not need to be empty before) - the corresponding entry for feature will be increased
         * @param codebookEntry  the corresponding cluster index for the quantized feature
         * @param weight the weight of the nearest cluster
         * @param distance the distance to its nearest cluster
         */        
        virtual void voteVQ (const NICE::Vector &feature, NICE::Vector &histogram, int & codebookEntry, double & weight, double & distance ) const; 
        
        /**
         * @brief Vector Quantization for a single vector, directly increases the corresponding entry in histogram 
         * @date 11-06-2013 (dd-mm-yyyy)
         * @author Erik Rodner, Alexander Freytag
         * @param feature the feature that shall be quantized
         * @param histogram a BoW-histogram already given (does not need to be empty before) - the corresponding entry for feature will be increased
         * @param codebookEntry the corresponding cluster index for the quantized feature
         * @param weight the weight of the nearest cluster
         * @param distance the distance to its nearest cluster
         */        
        virtual void voteVQ (const NICE::Vector &feature, NICE::SparseVector &histogram, int &codebookEntry, double &weight, double &distance ) const;         

        
        /**
         * @brief Hard or Soft Assignment into NICE::Vector for a single vector
         * @date 11-06-2013 (dd-mm-yyyy)
         * @author Alexander Freytag
         * @param feature the feature that shall be quantized
         * @param votes BoW histogram adding non-zero entries at the k nearest clusters (hard or soft),  (does not need to be empty before)
         */    
        virtual void voteVA ( const NICE::Vector & feature, NICE::Vector & votes ) const = 0;

        /**
         * @brief Hard or Soft Assignment into NICE::SparseVector for a single vector 
         * @date 11-06-2013 (dd-mm-yyyy)
         * @author Erik Rodner, Alexander Freytag
         * @param feature the feature that shall be quantized
         * @param votes BoW histogram adding non-zero entries for the k nearest clusters (hard or soft),  (does not need to be empty before)
         */                              
        virtual void voteVA ( const NICE::Vector & feature, NICE::SparseVector & votes ) const = 0;
        
        
        //for backward-compatibility
        virtual void   vote (const NICE::Vector &feature, NICE::Vector &histogram, int &codebookEntry , double &weight , double &distance ) const {
            this->voteVQ ( feature, histogram, codebookEntry, weight, distance );
        }
        
        virtual void   vote (const NICE::Vector &feature, NICE::SparseVector &histogram ) const {
          int codebookEntry;
          double weight, distance;
          this->voteVQ ( feature, histogram, codebookEntry, weight, distance );          
        }
   
        
        
       
        virtual void add ( const Codebook *codebook ) = 0;
        virtual void copy ( const Codebook *codebook );
        virtual Codebook *clone () const = 0;

        size_t getCodebookSize() const {
            return informativeMeasure.size();
        };
        void reinit ( int numCodebookEntries );

        const NICE::Vector & getThresholds () const {
            return thresholds;
        };
        const NICE::Vector & getInformativeMeasure () const {
            return informativeMeasure;
        };
        const NICE::VectorT<int> & getClassNos () const {
            return classnos;
        };

        void setThresholds ( const NICE::Vector & _thresholds ) {
            thresholds = _thresholds;
        };
        void setInformativeMeasure ( const NICE::Vector & _informativeMeasure ) {
            informativeMeasure = _informativeMeasure;
        };
        void setClassNos ( const NICE::VectorT<int> & _classnos ) {
            classnos = _classnos;
        };
        
        void setHardAssignment( const bool & _hardAssignment );
        bool getHardAssignment ( ) const ;
        
        /** 
         * @brief false, if only a single entry for soft or hard assignment can be larger than zero (=> effectively vector quantization)
         */
        virtual bool allowsMultipleVoting () const ;
        
        void setNoOfNearestClustersToConsidere ( const int & _noOfNearestClustersToConsidere );
        int getNoOfNearestClustersToConsidere ( ) const ;

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


} // namespace

#endif
