/** 
* @file LFMikolajczyk.cpp
* @brief interface to Mikolajczyk implementation
* @author Erik Rodner
* @date 11/19/2007

*/
#include <iostream>

#include "core/basics/StringTools.h"
#include "core/basics/FileMgt.h"

#include "vislearning/features/localfeatures/LFMikolajczyk.h"

using namespace OBJREC;

// refactor-nice.pl: check this substitution
#define DESCSIZE_DUMMY "/home/dbv/bilder/PicDatabase/ImageData2/monica.1.pgm"

using namespace std;
using namespace NICE;

///////////////////// ///////////////////// /////////////////////
//                   CONSTRUCTORS / DESTRUCTORS
///////////////////// ///////////////////// /////////////////

LFMikolajczyk::LFMikolajczyk()
{
    this->c_binaryExecutable = "";
    this->c_params = "-haraff -sift";
    this->c_minScale = 1.0;
    this->descriptor_size = -1;
}

LFMikolajczyk::LFMikolajczyk( const Config *conf )
{
    c_binaryExecutable = conf->gS( "LFMikolajczyk", "binaryExecutable", "/home/rodner/script/extract_features_64bit.ln" );
    c_params = conf->gS("LFMikolajczyk", "params", "-haraff -sift");
    c_minScale = conf->gD("LFMikolajczyk", "min_scale", 1.0);

    descriptor_size = conf->gI("LFMikolajczyk", "descriptor_size", -1 );
   
    if ( descriptor_size <= 0 ) 
    {
		fprintf (stderr, "LFMikolajczyk::LFMikolajczyk: No descriptor size found in config -> self test\n");
		/** get feature dimension **/
		NICE::Image testimg (DESCSIZE_DUMMY);
		VVector features;
		VVector positions;
		extractFeatures ( testimg, features, positions );
		if ( features.size() <= 0 )
		{
			fprintf (stderr, "LFMikolajczyk::LFMikolajczyk: No features found in descriptor_size_DUMMY picture !!\n");
			exit(-1);
		}
		descriptor_size = features[0].size();

		fprintf (stderr, "LFMikolajczyk::LFMikolajczyk Self Test features:%d dimension:%d\n", (int)features.size(), descriptor_size );
    }

    if ( descriptor_size != conf->gI("features", "descriptor_size", 128) )
    {
	fprintf (stderr, "FATAL ERROR LFMikolajczyk: descriptor sizes do not match !!!\n");
	exit(-1);
    }
}

LFMikolajczyk::~LFMikolajczyk()
{
}

///////////////////// ///////////////////// /////////////////////
//                      FEATURE STUFF
///////////////////// ///////////////////// ////////////////// 

int LFMikolajczyk::getDescSize () const
{
    return descriptor_size;
}

int LFMikolajczyk::extractFeatures ( const NICE::Image & img, VVector & features, 
				     VVector & positions ) const
{
    FILE *f;
    // refactor-nice.pl: check this substitution
    // old: string pgmfile   = FileMgt::createTempFile ( "/tmp/osl_lfmikolajczyk_input_%s.pgm" );
    std::string pgmfile   = FileMgt::createTempFile ( "/tmp/osl_lfmikolajczyk_input_%s.pgm" );
    // refactor-nice.pl: check this substitution
    // old: string outputfn  = FileMgt::createTempFile ( "/tmp/osl_lfmikolajczyk_output_%s" ) ;
    std::string outputfn  = FileMgt::createTempFile ( "/tmp/osl_lfmikolajczyk_output_%s" ) ;

    // refactor-nice.pl: check this substitution
    // old: string call = c_binaryExecutable + " " + 
    std::string call = c_binaryExecutable + " " + 
		  c_params + 
		  " -i " + pgmfile + 
		  " -o1 " + outputfn +
		  " 3>&1 2>&3 1>/dev/null";

    // refactor-nice.pl: check this substitution
    // old: WriteImg ( img, pgmfile );
    img.write (pgmfile);

    f = popen ( call.c_str(), "r" );
    if ( f == NULL )
    {
	fprintf (stderr, "LFMikolajczyk::extractFeatures: FATAL ERROR, unable to run the implementation of Mikolajczyk\n");
	exit(-1);
    }

    pclose(f);

    f = fopen ( outputfn.c_str(), "r" );
    if ( f == NULL )
    {
	fprintf (stderr, "LFMikolajczyk::extractFeatures: FATAL ERROR, unable to read output of Mikolajczyks implementation\n");
	exit(-1);
    }

    const int buffersize = 4048;
    char *buffer = new char [buffersize];
    fgets ( buffer, buffersize, f );
    int dimension = atoi (buffer);

    if ( (descriptor_size >= 0) && (dimension != descriptor_size) )
    {
	fprintf (stderr, "LFMikolajczyk::extractFeatures: FATAL ERROR dimension != descriptor_size\n");
	exit(-1);
    }

    fgets ( buffer, buffersize, f );
    int noDesc = atoi (buffer);

    fprintf (stderr, "LFMikolajczyk::extractFeatures: no. of descriptors = %d\n", noDesc );
 
    // refactor-nice.pl: check this substitution
    // old: Vector x;
    NICE::Vector x;
    while ( ! feof(f) ) 
    {
	if ( fgets(buffer, buffersize, f) == NULL )
	    break;
	// refactor-nice.pl: check this substitution
	// old: string buffer_s (buffer);
	std::string buffer_s (buffer);
	StringTools::splitVector ( buffer_s, ' ', x );
	if ( (int)x.size() != dimension + 5 ) 
	{
	    cerr << "Line = " << buffer_s << endl;
	    cerr << "Vector = " << x << endl;
	    cerr << "dimension = " << dimension << endl;
	    cerr << "x.size() = " << x.size() << endl;
	    fprintf (stderr, "LFMikolajczyk::extractFeatures: error parsing output !!\n");
	    exit(-1);
	} else {
	    double area = 2*M_PI/sqrt(x[2]*x[4] - x[3]*x[3]);
	    area /= 36.0; // be comparable to SiftPP
	    if ( area < c_minScale ) {
		continue;
	    }

	    // refactor-nice.pl: check this substitution
	    // old: Vector pos ( x[0], // x coordinate

	    NICE::Vector pos ( 5 );

	    pos[0] = x[0]; // x coordinate
	    pos[1] = x[1]; // y coordinate
	    pos[2] = x[2]; // a
	    pos[3] = x[3]; // b
	    pos[4] = x[4]; // c
	    // where a(x-u)(x-u)+2b(x-u)(y-v)+c(y-v)(y-v)=1

	    positions.push_back( pos );
	    features.push_back ( x.getRange(5, x.size()-1) );
	}
    }

    fclose (f);

    FileMgt::deleteTempFile ( pgmfile );
    FileMgt::deleteTempFile ( outputfn + ".params" );
    FileMgt::deleteTempFile ( outputfn );

    delete [] buffer;

    return 0;
}

///////////////////// INTERFACE PERSISTENT /////////////////////
// interface specific methods for store and restore
///////////////////// INTERFACE PERSISTENT ///////////////////// 

void LFMikolajczyk::restore ( std::istream & is, int format )
{ 
  fthrow ( Exception, "LFMikolajczyk::restore not implemented yet." );
  //TODO  
}

void LFMikolajczyk::store ( std::ostream & os, int format ) const
{ 
  fthrow ( Exception, "LFMikolajczyk::store not implemented yet." );
  //TODO  
}

void LFMikolajczyk::clear ()
{ 
  fthrow ( Exception, "LFMikolajczyk::clear not implemented yet." );
  //TODO  
}
