/** 
* @file EMDDistance.cpp
* @brief Earth Movers Distance
* @author Erik Rodner
* @date 10/24/2007

*/

#include <iostream>

#include "vislearning/math/distances/emd.h"
#include "vislearning/math/distances/EMDDistance.h"

using namespace OBJREC;

using namespace std;
// refactor-nice.pl: check this substitution
// old: using namespace ice;
using namespace NICE;

// global variable work around :(
int global_dimension;

float euclidian_distance (double **x, double **y)
{
    double *xx = *x;
    double *yy = *y;
    float sum = 0.0;

    for ( int i = 1 ; i < global_dimension ; i++ )
    {
		double diff = xx[i] - yy[i];
		sum += diff*diff;
    }

    return sqrt(sum);
}


EMDDistance::EMDDistance ( int _descriptor_size )
{
    // add dimension for weights
    descriptor_size = _descriptor_size + 1;
}

EMDDistance::~EMDDistance()
{
}

// refactor-nice.pl: check this substitution
// old: double EMDDistance::calculate (const Vector & x, const Vector & y) const
double EMDDistance::doCalculate (const NICE::Vector & x, const NICE::Vector & y) const
{
    signature_t x_signature;  
    signature_t y_signature;  

    if ( x.size() % descriptor_size != 0 )
    {
		fprintf (stderr, "EMDDistance::distance: wrong dimensions: x.size()=%d, descriptor_size=%d\n",
		    x.size(), descriptor_size );
		exit(-1);
    }

    x_signature.n = x.size() / descriptor_size;
    y_signature.n = y.size() / descriptor_size;
 
    x_signature.Features = new double * [ x_signature.n ];
    x_signature.Weights  = new float    [ x_signature.n ];
    y_signature.Features = new double * [ y_signature.n ];
    y_signature.Weights  = new float    [ y_signature.n ];

    
    double *dataX = const_cast<double *>( x.getDataPointer() );
    double *dataY = const_cast<double *>( y.getDataPointer() );

    for ( int i = 0; i < x_signature.n ; i++ )
    {
		x_signature.Features[i] = dataX + i*descriptor_size;
		x_signature.Weights[i]  = (x_signature.Features[i])[0]; 
    }

	for ( int i = 0; i < y_signature.n ; i++ )
	{
		y_signature.Features[i] = dataY + i*descriptor_size;
		y_signature.Weights[i]  = (y_signature.Features[i])[0]; 
	}

	global_dimension = descriptor_size;
	double result = emd ( &x_signature, &y_signature, 
	euclidian_distance, 0, 0 ); 

	delete [] x_signature.Features;
	delete [] y_signature.Features;
	delete [] x_signature.Weights;
	delete [] y_signature.Weights;

	return result;
}
