/** 
* @file calcNormTrainingSet.cpp
* @brief save normalized object images
* @author Erik Rodner
* @date 07/21/2008

*/
#include "core/vector/VectorT.h"
#include "core/vector/MatrixT.h"
#include "core/image/ImageT.h"
#include "core/imagedisplay/ImageDisplay.h"

#include <core/image/CrossT.h>

#include <sys/errno.h>

#include <core/basics/Config.h>
#include <vislearning/baselib/cmdline.h>
#include <vislearning/baselib/Preprocess.h>
#include <core/vector/VVector.h>
#include <vislearning/math/cluster/KMeans.h>

#include <vislearning/cbaselib/MultiDataset.h>

#include <vislearning/baselib/ProgressBar.h>
#include <vislearning/baselib/Globals.h>

using namespace OBJREC;



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


/** 
    
    save normalized object images 
    
*/
int main (int argc, char **argv)
{   
#ifndef __clang__
#ifndef __llvm__
    std::set_terminate(__gnu_cxx::__verbose_terminate_handler);
#endif
#endif

    char configfile [300];
    char objectclass_c [1024];
    char setname_c [1024];

    struct CmdLineOption options[] = {
	{"config", "use config file", NULL, "%s", configfile},
	{"ds", "use data set", "train", "%s", setname_c},
	{NULL, NULL, NULL, NULL, NULL} 
    };
    int ret;
    char *more_options[argc];
    ret = parse_arguments( argc, (const char**)argv, options, more_options);
    fprintf (stderr, "data set name: %s\n", setname_c );

    if ( ret != 0 )
    {
	if ( ret != 1 ) fprintf (stderr, "Error parsing command line !\n");
	exit (-1);
    }

    Config conf ( configfile );
    Preprocess::Init ( &conf );
    
    MultiDataset md ( &conf );

    // refactor-nice.pl: check this substitution
    // old: string setname ( setname_c );
    std::string setname ( setname_c );
    const LabeledSet & ls = *(md[setname]);

    map<int, double> maxwidth;
    map<int, double> maxheight;
    map<int, double> minwidth;
    map<int, double> minheight;
    map<int, double> avgheight;
    map<int, double> avgwidth;
    map<int, int> count;
    map<int, VVector> objectpositions;

    const ClassNames & classNames = md.getClassNames( setname );
    
    // refactor-nice.pl: check this substitution
    // old: Image img = NewImg ( 1024, 1024, 255 );
    NICE::Image img (1024, 1024);
    // refactor-nice.pl: check this substitution
    // old: ClearImg(img);
    img.set(0);

    ProgressBar pb ("Statistics");

    pb.show();

    LOOP_ALL_S(ls)
    {
	EACH_INFO(classno,info);
	pb.update ( ls.count() );
    
	fprintf (stderr, "Filename %s\n", info.img().c_str());
	if ( ! info.hasLocalizationInfo() ) {
	    fprintf (stderr, "No localization information available !!\n");
	    exit(-1);
	}
	const LocalizationResult *l = info.localization();

	if ( l->size() <= 0 ) {
	    fprintf (stderr, "No objects found in this image !!\n");
	    exit(-1);
	}
	fprintf (stderr, "Analyzing bounding boxes\n");
	for ( LocalizationResult::const_iterator i = l->begin();
	      i != l->end(); i++ )
	{
	    SingleLocalizationResult *slr = *i;
	    fprintf (stderr, "checking classno\n");
	    assert ( slr->r != NULL );
	    int c = slr->r->classno;
		
	    fprintf (stderr, "getting bounding box\n");
	    int xi, xa, yi, ya;
	    slr->getBoundingBox ( xi, yi, xa, ya );

	    if ( !NICE::isFinite(xi) || !NICE::isFinite(yi) || !NICE::isFinite(xa) || !NICE::isFinite(ya) )
	    {
		fprintf (stderr, "illegal bounding box information: %s\n", info.img().c_str() );
		exit(-1);
	    }

	    double width = xa - xi;
	    double height = ya - yi;
	
	    if ( width <= 0 ) {
		fprintf (stderr, "negative width: %s !\n", info.img().c_str());
		exit(-1);
	    }
	    if ( height <= 0 ) {
		fprintf (stderr, "negative height %s !\n", info.img().c_str());
		exit(-1);
	    }

	    if ( objectpositions.find(c) == objectpositions.end() )
		objectpositions[c] = VVector();

	    // refactor-nice.pl: check this substitution
	    // old: objectpositions[c].push_back ( Vector(width, height) );
	    // REFACTOR-FIXME Unable to std::map this statement

	    if ( (minwidth.find(c) == minwidth.end()) || (minwidth[c] > width ) )
		minwidth[c] = width;
	    if ( (maxwidth.find(c) == maxwidth.end()) || (maxwidth[c] < width ) )
		maxwidth[c] = width;

	    if ( (minheight.find(c) == minheight.end()) || (minheight[c] > height ) )
		minheight[c] = height;
	    if ( (maxheight.find(c) == maxheight.end()) || (maxheight[c] < height ) )
		maxheight[c] = height;

	    if ( avgheight.find(c) == avgheight.end() )
		avgheight[c] = height;
	    else
		avgheight[c] += height;

	    if ( avgwidth.find(c) == avgwidth.end() )
		avgwidth[c] = width;
	    else
		avgwidth[c] += width;

	    if ( count.find(c) == count.end() )
		count[c] = 0;
	    else
		count[c] ++;
	    
	    fprintf (stderr, "ready for the next file\n");
	}
    }

    fprintf (stderr, "-- Object Statistics --\n");
    for ( map<int, int>::iterator i = count.begin();
				 i != count.end();
				 i++ )
    {
	int c = i->first;
	int count = i->second;

	avgheight[c] /= count;
	avgwidth[c] /= count;

	fprintf (stderr, "[%s]\n", classNames.text(c).c_str() ); 
	fprintf (stderr, "width: min %f max %f avg %f\n", minwidth[c], maxwidth[c], avgwidth[c] );
	fprintf (stderr, "height: min %f max %f avg %f\n", minheight[c], maxheight[c], avgheight[c] );

	const VVector & pos = objectpositions[c];
	KMeans kmeans (4);
	VVector prototypes;
	vector<double> weights;
	vector<int> assignment;

	kmeans.cluster ( pos, prototypes, weights, assignment );

	// refactor-nice.pl: check this substitution
	// old: Image img = NewImg ( (int)maxwidth[c]+5, (int)maxheight[c]+5, 255 );
	NICE::Image img ((int)maxwidth[c]+5, (int)maxheight[c]+5);
	// refactor-nice.pl: check this substitution
	// old: ClearImg(img);
	img.set(0);

	for ( VVector::const_iterator j = pos.begin();
		j != pos.end(); j++ )
	{
	    // refactor-nice.pl: check this substitution
	    // old: const Vector & x = *j;
	    const NICE::Vector & x = *j;
	    Cross cross ( Coord((int)x[0], (int)x[1]), 4 );
	    img.draw ( cross, 1 );
	}

	fprintf (stderr, "%s ", classNames.text(c).c_str() );
	for ( VVector::const_iterator j = prototypes.begin();
		j != prototypes.end(); j++ )
	{
	    // refactor-nice.pl: check this substitution
	    // old: const Vector & x = *j;
	    const NICE::Vector & x = *j;
	    Cross cross ( Coord((int)x[0], (int)x[1]), 4 );
	    img.draw ( cross, 2 );

	    fprintf (stderr, "%dx%d ", (int)round(x[0]), (int)round(x[1]) );
	}
	fprintf (stderr, "\n");

#ifndef NOVISUAL
	NICE::showImageOverlay ( img, img );
#endif

    }

    return 0;
}
