/** 
* @file FCCodebookHistBin.cpp
* @brief create features with codebook
* @author Erik Rodner
* @date 02/05/2008

*/
#include <iostream>
#include <fstream>

#include "vislearning/features/localfeatures/LFGenericLocal.h"
#include "vislearning/features/simplefeatures/FCCodebookHistBin.h"

using namespace OBJREC;

using namespace std;
using namespace NICE;



FCCodebookHistBin::FCCodebookHistBin( 
    const Config *conf, 
    const LocalFeatureRepresentation *_lfrep,
    const std::string & normalizationMethod,
    const Codebook *_codebook )
    : FeatureFactory ( conf ), lfrep(_lfrep),
      codebook(_codebook)
{
    if ( normalizationMethod == "sum" )
		n_method = NORMALIZE_SUM;
    else if ( normalizationMethod == "binzero" )
		n_method = NORMALIZE_BINZERO;
    else if ( normalizationMethod == "raw" )
		n_method = NORMALIZE_RAW;
    else if ( normalizationMethod == "thresh" )
		n_method = NORMALIZE_THRESH;
    else {
		fprintf (stderr, "FCCodebookHistBin::FCCodebookHistBin: unknown normalization method\n");
		exit(-1);
    }
}

FCCodebookHistBin::~FCCodebookHistBin()
{
}

void FCCodebookHistBin::calcHistogram ( const VVector & features,
					NICE::Vector & histogram )
{
    histogram.set(0);
    fprintf (stderr, "FCCodebookHistBin: features size = %d, codebook size = %d\n",
	(int)features.size(), (int)codebook->getCodebookSize());
    int cluster_index = 0;
    double weight = 0;
    double distance = 0.0;
    for ( vector<Vector>::const_iterator i  = features.begin();
					 i != features.end();
					 i++ )
    {
		const NICE::Vector & x = *i;
		codebook->vote ( x, histogram, cluster_index, weight, distance );
    }
}

void FCCodebookHistBin::calcHistogram ( const VVector & features,
					NICE::Vector & histogram,
					NICE::Matrix & assignments )
{
    histogram.set(0);
    size_t l = 0;
    int cluster_index = 0;
    double weight = 0;
    double distance;

	assignments.resize ( 3, features.size() );
    for ( vector<Vector>::const_iterator i  = features.begin();
					 i != features.end();
					 i++,l++ )
    {
		const NICE::Vector & x = *i;
		codebook->vote ( x, histogram, cluster_index, weight, distance );
		histogram[cluster_index]++;
		assignments(0,l) = distance;
		assignments(1,l) = cluster_index;
		assignments(2,l) = l;
    }
}

void FCCodebookHistBin::normalizeHistogram ( NICE::Vector & histogram )
{
    if ( n_method == NORMALIZE_RAW ) {
		// do nothing
    } else if ( n_method == NORMALIZE_BINZERO ) {
		for ( size_t i = 0 ; i < histogram.size() ; i++ )
			if ( histogram[i] > 0 ) histogram[i] = 1.0; 
    } else if ( n_method == 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, "FCCodebookHistBin::normalizeHistogram: WARNING histogram is zero !!\n");
			return;
		}

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

		if ( thresholds.size() <= 0 ) {
			fprintf (stderr, "FCCodebookHistBin:: 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 FCCodebookHistBin::convert ( const NICE::Image & img, NICE::Vector & vec )
{
    VVector features;
    VVector positions;
    lfrep->extractFeatures ( img, features, positions );        

    if ( features.size() <= 0 ) return -1;

    vec.resize(codebook->getCodebookSize());
    calcHistogram ( features, vec );
    normalizeHistogram ( vec );

    return 0;
}
	
int FCCodebookHistBin::calcAssignments ( const VVector & features, NICE::Vector & vec, NICE::Matrix & assignments )
{
    if ( features.size() <= 0 ) return -1;

    assignments = Matrix(0,3);
    vec.resize(codebook->getCodebookSize());
    calcHistogram ( features, vec, assignments );
    normalizeHistogram ( vec );

    return 0;
}

int FCCodebookHistBin::getNormalizationMethod () const
{
    return n_method;
}

void FCCodebookHistBin::setNormalizationMethod ( int normalizationMethod )
{
    n_method = normalizationMethod;
}