/** 
* @file BoWFeatureConverter.cpp
* @brief Convert a set of features into a Bag of visual Words histogram (either by Vector Quantization, or Hard / Soft Assignment)
* @author Alexander Freytag
* @date 11-06-2013 (dd-mm-yyyy)
*/
#include <iostream>
#include <fstream>

#include "vislearning/features/simplefeatures/BoWFeatureConverter.h"

using namespace OBJREC;

using namespace std;
using namespace NICE;



BoWFeatureConverter::BoWFeatureConverter( 
    const Config *conf, 
    const Codebook *_codebook, const std::string _section )
    : codebook(_codebook)
{
  this->s_section = _section;
  this->p_conf = conf;
  
  std::string normalizationMethod = conf->gS( _section, "normalizationMethod", "sum" );
  
  if ( normalizationMethod == "sum" )
    this->n_normalizationMethod = NORMALIZE_SUM;
  else if ( normalizationMethod == "binzero" )
    this->n_normalizationMethod = NORMALIZE_BINZERO;
  else if ( normalizationMethod == "raw" )
    this->n_normalizationMethod = NORMALIZE_RAW;
  else if ( normalizationMethod == "thresh" )
    this->n_normalizationMethod = NORMALIZE_THRESH;
  else
  {
    //default: L1 normalization
    this->n_normalizationMethod = NORMALIZE_SUM;    
  }
  
  std::string n_quantizationMethod = conf->gS( _section, "n_quantizationMethod", "VQ" );
  
  if ( normalizationMethod == "VQ" )
    this->n_quantizationMethod = VECTOR_QUANTIZATION;
  else if ( normalizationMethod == "VA" )
    this->n_quantizationMethod = VECTOR_ASSIGNMENT;
  else
  {
    //default: standard vector quantization
    this->n_quantizationMethod = VECTOR_QUANTIZATION;    
  }  
}

BoWFeatureConverter::~BoWFeatureConverter()
{
}

void BoWFeatureConverter::calcHistogram ( const NICE::VVector & features,
          NICE::Vector & histogram , const bool & b_resetHistogram )
{
  if ( b_resetHistogram || (histogram.size() != this->codebook->getCodebookSize() ) )
  {
    histogram.resize( this->codebook->getCodebookSize() );
    histogram.set(0);
  }

  int cluster_index = 0;
  double weight = 0;
  double distance = 0.0;
  if ( this->n_quantizationMethod == VECTOR_QUANTIZATION )
  {
    for ( NICE::VVector::const_iterator featIt  = features.begin();
            featIt != features.end();
            featIt++ )
    {
      const NICE::Vector & x = *featIt;
      this->codebook->voteVQ ( x, cluster_index, weight, distance );
      histogram[ cluster_index ] ++;
    }    
  }
  else // VECTOR_ASSIGNMENT (hard or soft can be set directly in the codebook-object)
  {
    
    NICE::Vector assignment (this->codebook->getCodebookSize() );;
    for ( NICE::VVector::const_iterator featIt  = features.begin();
            featIt != features.end();
            featIt++ )
    { 
      assignment.set(0);
      const NICE::Vector & x = *featIt;
      this->codebook->voteVA ( x, assignment );
      histogram += assignment;
    }      
  }

}

void BoWFeatureConverter::normalizeHistogram ( NICE::Vector & histogram )
{
    if ( n_normalizationMethod == NORMALIZE_RAW ) {
    // do nothing
    } else if ( n_normalizationMethod == NORMALIZE_BINZERO ) {
    for ( size_t i = 0 ; i < histogram.size() ; i++ )
      if ( histogram[i] > 0 ) histogram[i] = 1.0; 
    } else if ( n_normalizationMethod == NORMALIZE_SUM  ) {
    double sum = 0.0;
    for ( size_t i = 0 ; i < histogram.size() ; i++ )
    {
      assert ( histogram[i] >= 0.0 );
      sum += histogram[i];
    }

    if ( sum < 1e-5 ) {
      fprintf (stderr, "BoWFeatureConverter::normalizeHistogram: WARNING histogram is zero !!\n");
      return;
    }

    for ( size_t i = 0 ; i < histogram.size() ; i++ )
      histogram[i] /= sum;
    } else if ( n_normalizationMethod == NORMALIZE_THRESH ) {
    const NICE::Vector & thresholds = codebook->getThresholds();

    if ( thresholds.size() <= 0 ) {
      fprintf (stderr, "BoWFeatureConverter:: This is maybe an OLD codebook ! \n");
      exit(-1);
    }
    for ( size_t i = 0 ; i < histogram.size() ; i++ )
      histogram[i] = (histogram[i] > thresholds[i]) ? 1.0 : 0.0; 
    }
}

int BoWFeatureConverter::getNormalizationMethod () const
{
    return n_normalizationMethod;
}

void BoWFeatureConverter::setNormalizationMethod ( int normalizationMethod )
{
    n_normalizationMethod = normalizationMethod;
}