/** 
* @file NegativeFactory.cpp
* @brief obtain negative examples from some images
* @author Erik Rodner
* @date 11/13/2008

*/
#include <iostream>
#include <time.h>

#include "NegativeFactory.h"

using namespace OBJREC;

using namespace std;
using namespace NICE;


NegativeFactory::NegativeFactory()
{
}

NegativeFactory::~NegativeFactory()
{
}

void NegativeFactory::createNegativesFromText ( Examples & examples,
				      vector<CachedExample *> & cexamples,
				      const std::string & filename,
				      ImageFeatures & imgf,
				      int negativeClassDST )
{  
    ifstream ifs ( filename.c_str(), ios::in );
    if ( ! ifs.good() )
    {
	fprintf (stderr, "Error reading %s\n", filename.c_str() );
	exit(-1);
    }
    
    long int count = 0;
    // refactor-nice.pl: check this substitution
    // old: string imgfn;
    std::string imgfn;
    int xi, yi, xa, ya;
    map<string, CachedExample *> cexamples_map;
    double confidence = 1.0;
    while ( ! ifs.eof() )
    {
	if ( !(ifs >> imgfn) ) break;
	if ( !(ifs >> confidence) ) break;
	if ( !(ifs >> xi) ) break;
	if ( !(ifs >> yi) ) break;
	if ( !(ifs >> xa) ) break;
	if ( !(ifs >> ya) ) break;

	map<string, CachedExample *>::const_iterator i = 
	    cexamples_map.find ( imgfn );
	
	CachedExample *ce = NULL;
	if ( i == cexamples_map.end() )
	{
	    fprintf (stderr, "Loading negative image: %s\n", imgfn.c_str() );
	    ce = new CachedExample ( imgfn );
	    imgf.fillExample ( ce );
	    cexamples.push_back ( ce );
	    cexamples_map.insert ( pair<string, CachedExample *> ( imgfn, ce ) );
	} else {
	    ce = i->second;
	}
	
	int xsize;
	int ysize;
	ce->getImageSize ( xsize, ysize );

	int x = (xi+xa) / 2;
	int y = (yi+ya) / 2;
	int width = xa - xi;
	int height = ya - yi;
	Example pce ( ce, x, y, width, height );

	examples.push_back ( pair<int, Example> ( negativeClassDST, pce ) );
	count++;
    }

    ifs.close ();

    fprintf (stderr, "%ld negative examples loaded..\n", count );
}

void NegativeFactory::createNegativesExhaustiveSearch ( Examples & examples,
				      vector<CachedExample *> & cexamples,
				      const LabeledSet *ls,
				      ImageFeatures & imgf,
				      int examplesPerImage,
				      int negativeClassSRC,
				      int negativeClassDST,
				      FeaturePoolClassifier *fpc,
				      double & falsePositiveEstimate,
				      const VVector & bb,
				      int subsample )
{  
    falsePositiveEstimate = 0.0;
    int noImages = 0;

    LOOP_ALL_S ( (*ls) )
    {
	EACH_S ( classno, filename );
	if ( classno != negativeClassSRC ) continue;
    
	long rejected = 0;

	fprintf (stderr, "Loading negative image: %s\n", filename.c_str() );
	
	CachedExample *ce = new CachedExample ( filename );

	cexamples.push_back ( ce );
	imgf.fillExample ( ce );
	
	int xsize;
	int ysize;
	ce->getImageSize ( xsize, ysize );

	long k = 0;
	assert ( bb.size() > 0 );
	assert ( fpc != NULL );

	for ( int i = 0 ; i < (int)bb.size() ; i++ )
	{
	    // refactor-nice.pl: check this substitution
	    // old: const Vector & box = bb[i];
	    const NICE::Vector & box = bb[i];
	    int width = (int)box[0];
	    int height = (int)box[1];
	    assert ( width > 0.0 );
	    assert ( height > 0.0 );

	    if ( width >= xsize ) 
		width = xsize - 3;
	    if ( height >= ysize ) 
		height = ysize - 3;

	    for ( int y = height/2 ; y < ysize - height/2 ; y+=subsample )
	    {
		for ( int x = width/2 ; x < xsize - width/2 ; x+=subsample )
		{
		    Example pce ( ce, x, y, width, height );
		    ClassificationResult r = fpc->classify(pce);
		    if ( r.classno == negativeClassDST ) {
			rejected++;
			continue; // already correctly classified
		    }
		
		    examples.push_back ( pair<int, Example> ( negativeClassDST, pce ) );
		    k++;
		}
	    }
	}

	fprintf (stderr, "Image processed: %s (rejected %ld/obtained %ld/%f)\n", filename.c_str(), rejected, k,
	    k/(double)(rejected+k));

	falsePositiveEstimate += k / (double)(rejected+k);
	noImages++;
    }

    falsePositiveEstimate /= noImages;
}


void NegativeFactory::createNegatives ( Examples & examples,
				      vector<CachedExample *> & cexamples,
				      const LabeledSet *ls,
				      ImageFeatures & imgf,
				      int noImages,
				      int examplesPerImage,
				      int negativeClassSRC,
				      int negativeClassDST,
				      FeaturePoolClassifier *fpc,
				      double & falsePositiveEstimate,
				      const VVector & bb )
{  
    int maxRejected = 1000*examplesPerImage;
    srand(time(NULL));

    LabeledSet randSel (true);
    LabeledSet dummy (true);
    map<int,int> selection;

    assert ( ls->count(negativeClassSRC) >= noImages );

    selection[negativeClassSRC] = noImages;

    LabeledSetSelection<LabeledSet>::selectRandom ( selection,
	*ls, randSel, dummy );

    falsePositiveEstimate = 0.0;

#define SAVE_RANDOM_POSITIONS
#ifdef SAVE_RANDOM_POSITIONS
    ofstream ofs ( "/tmp/randomlocations.txt", ios::out );
    if ( ! ofs.good() )
    {
	fprintf (stderr, "Error writing to /tmp/randomlocations.txt.\n" );
	exit(-1);
    }
#endif

    LOOP_ALL_S ( randSel )
    {
	EACH_S ( classno, filename );
    
	long rejected = 0;

	fprintf (stderr, "Loading negative image: %s\n", filename.c_str() );
	
	CachedExample *ce = new CachedExample ( filename );

	cexamples.push_back ( ce );
	imgf.fillExample ( ce );
	
	int xsize;
	int ysize;
	ce->getImageSize ( xsize, ysize );

	long k = 0;
	bool usebb = (bb.size() > 0);

#ifdef CSFPNegatives_DISTRIBUTION_ANALYSIS
	NICE::Image img (xsize, ysize);
	img.set(0);
#endif

	while( (k < examplesPerImage) && (rejected < maxRejected) )
	{
	    int width, height;
	    if ( ! usebb ) {
		width = rand() % (xsize/3) + 20;
		height = rand() % (ysize/3) + 20;
	    } else {
		const NICE::Vector & x = bb[ rand() % bb.size() ];
		width = (int)x[0];
		height = (int)x[1];
		assert ( width > 0.0 );
		assert ( height > 0.0 );

		if ( width >= xsize ) 
		    width = xsize - 3;
		if ( height >= ysize ) 
		    height = ysize - 3;
	    }


	    int x = rand() % (xsize-width) + width/2;
	    int y = rand() % (ysize-height) + height/2;

	    Example pce ( ce, x, y, width, height );
	    if ( fpc != NULL )
	    {
		ClassificationResult r = fpc->classify(pce);
		if ( r.classno == negativeClassDST ) {
		    rejected++;
		    continue; // already correctly classified
		}
	    }

#ifdef SAVE_RANDOM_POSITIONS
	    ofs << filename << " 1.0 ";
	    int xi = x - width/2;
	    int xa = x + width/2;
	    int yi = y - height/2;
	    int ya = y + height/2;
	    ofs << xi << " " << yi << " " << xa << " " << ya << endl;
#endif

	    examples.push_back ( pair<int, Example> ( negativeClassDST, pce ) );

	    k++;
	}

	fprintf (stderr, "Image processed: %s (rejected %ld/obtained %ld/%f)\n", filename.c_str(), rejected, k,
	    k/(double)(rejected+k));

	falsePositiveEstimate += k / (double)(rejected+k);
    }

#ifdef SAVE_RANDOM_POSITIONS
    ofs.close();
#endif

    falsePositiveEstimate /= noImages;
}


