#ifdef NICE_USELIB_ICE

#include <core/imagedisplay/ImageDisplay.h>
#include <core/iceconversion/convertice.h>

#include <iostream>

#include "vislearning/classifier/vclassifier/VCSimpleGaussian.h"
#include "vislearning/math/pdf/PDFGaussian.h"

using namespace OBJREC;

using namespace std;

using namespace NICE;

VCSimpleGaussian::VCSimpleGaussian( const Config *conf ) 
{
}

VCSimpleGaussian::~VCSimpleGaussian()
{
    clear();
}

double VCSimpleGaussian::calcNLogDensity ( int classno, const NICE::Vector & x ) const
{
    std::map<int, PDF *>::const_iterator im = pdfs.find(classno);
    if ( im == pdfs.end() ) {
	fprintf (stderr, "VCSimpleGaussian: classno %d not trained !!\n", classno);
	exit(-1);
    }
    PDF *pdf = im->second;
    double result = pdf->getNLogDensity ( x );

    return result;
}

/** classify using simple vector */

ClassificationResult VCSimpleGaussian::classify ( const NICE::Vector & x ) const
{
     double min_nlogdensity = std::numeric_limits<double>::max();
     int min_class = -1;
     FullVector scores ( maxClassNo+1 );
     
     for ( map<int, ice::Statistics *>::const_iterator i  = statistics.begin();
           i != statistics.end();
           i++ )
     {
          double nlogdensity = calcNLogDensity ( i->first, x );
          scores[i->first] = - nlogdensity;
          if ( nlogdensity < min_nlogdensity )
          {
               min_nlogdensity = nlogdensity;
               min_class = i->first;
          }
     }
     
     return ClassificationResult ( min_class, scores );
}

void VCSimpleGaussian::getVotings ( const NICE::Vector & x, 
    std::map<int, double> & votings ) const
{
     for ( map<int, ice::Statistics *>::const_iterator i  = statistics.begin();
					          i != statistics.end();
					          i++ )
     {
	double nlogdensity = calcNLogDensity ( i->first, x );
	votings[ i->first ] = nlogdensity;
     }
}

PDF *VCSimpleGaussian::getPDF(int classno) const
{
     std::map<int, PDF*>::const_iterator im = pdfs.find(classno);
     if ( im == pdfs.end() ) {
          fprintf (stderr, "VCSimpleGaussian: classno %d not trained !!\n", classno);
          exit(-1);
     }
     PDF *pdf = im->second;
     return pdf;
}

/** classify using a simple vector */
void VCSimpleGaussian::teach ( const LabeledSetVector & _teachSet )
{
    maxClassNo = _teachSet.getMaxClassno();
    LOOP_ALL(_teachSet)
    {
	EACH(classno,x);
	teach ( classno, x );
    }
}

void VCSimpleGaussian::teach ( int classno, const NICE::Vector & x )
{
   if ( classno > maxClassNo ) maxClassNo = classno;

   std::map<int, ice::Statistics *>::iterator i = statistics.find(classno);
   
   if ( i == statistics.end() )
   {
       statistics[classno] = new ice::Statistics(x.size());
       i = statistics.find(classno); // FIXME
   }

   ice::Statistics *s = i->second;

   Put( *s, NICE::makeIceVectorT(x) );
}

void VCSimpleGaussian::finishTeaching()
{
    for ( map<int, ice::Statistics *>::iterator i  = statistics.begin();
					   i != statistics.end();
					   i++ )
    {
	NICE::Matrix covariance;
	NICE::Vector mean;

	ice::Statistics *s = i->second;
	
	mean = NICE::makeEVector<double>(Mean(*s));
	covariance = NICE::makeDoubleMatrix( Covariance(*s) );
    
	PDF *pdf = new PDFGaussian ( covariance, mean );
	
	pdfs[i->first] = pdf;
    }
}

void VCSimpleGaussian::clear ()
{
    for ( map<int, ice::Statistics *>::iterator i  = statistics.begin();
					   i != statistics.end();
					   i++ )
    {
	ice::Statistics *s = i->second;
	delete s;
    }   
    
    for ( map<int, PDF *>::iterator i  = pdfs.begin();
				    i != pdfs.end();
				    i++ )
    {
	PDF *p = i->second;
	delete p;
    }   

    pdfs.clear();
    statistics.clear();
}

void VCSimpleGaussian::store ( std::ostream & os, int format ) const
{
    fprintf (stderr, "NOT YET IMPLEMENTED\n");
    exit(-1);
}

void VCSimpleGaussian::restore ( std::istream & is, int format )
{
    fprintf (stderr, "NOT YET IMPLEMENTED\n");
    exit(-1);
}

#endif