/** 
* @file CachedExample.cpp
* @brief data caching
* @author Erik Rodner
* @date 04/21/2008

*/
#include <iostream>

#include "vislearning/cbaselib/CachedExample.h"
#include "vislearning/baselib/Conversions.h"
#include "vislearning/baselib/ProgressBar.h"

#include "vislearning/image/GenericImageTools.h"
#include "vislearning/baselib/Preprocess.h"
#include "vislearning/baselib/ICETools.h"

using namespace OBJREC;

using namespace std;
using namespace NICE;


void CachedExample::init ()
{
    dchannels = new MultiChannelImageT<double> [D_NUMCHANNELS];
    ichannels = new MultiChannelImageT<int> [I_NUMCHANNELS];
    lchannels = new MultiChannelImageT<long> [L_NUMCHANNELS];

    svmap = new SparseVector *[SVNUMCHANNELS];
    svmap_xsize = new int [SVNUMCHANNELS];
    svmap_ysize = new int [SVNUMCHANNELS];
    for ( uint k = 0 ; k < SVNUMCHANNELS ; k++ )
    {
	svmap[k] = NULL;
	svmap_xsize[k] = 0;
	svmap_ysize[k] = 0;
    }
}

CachedExample::CachedExample( const std::string & _imgfn,
			      int _newWidth,
			      int _newHeight )
{
    imgfn = _imgfn;
    newWidth = _newWidth;
    newHeight = _newHeight;
    Preprocess::getImageSize ( _imgfn, oxsize, oysize );
    init();
    hasColorInformation = true;
}

CachedExample::CachedExample( const NICE::Image & _img )
{
    imgfn = "";
    newWidth = -1;
    newHeight = -1;
    init();

    oxsize = _img.width();
    oysize = _img.height();
    int *gray = new int [ oxsize*oysize ];
    int k = 0;
    for ( int y = 0 ; y < oysize ; y++ )
	for ( int x = 0 ; x < oxsize ; x++,k++ )
	    gray[k] = _img.getPixel(x,y);

    ichannels[I_GRAYVALUES].reInit ( oxsize, oysize, 1, false );
    ichannels[I_GRAYVALUES].setImage ( gray, oxsize, oysize, 0 );

    hasColorInformation = false;
}

CachedExample::CachedExample( const NICE::ColorImage & img, bool disableGrayConversion )
{
    imgfn = "";
    oxsize = img.width();
    oysize = img.height();
    newWidth = -1;
    newHeight = -1;
    init();

    if ( ! disableGrayConversion )
    {
	// refactor-nice.pl: check this substitution
	// old: Image imggray;
	NICE::Image imggray;
	ICETools::calcGrayImage ( img, imggray );

	ichannels[I_GRAYVALUES].reInit ( oxsize, oysize, 1, true );
	int *gray = ichannels[I_GRAYVALUES].data[0];
	int k = 0;
	for ( int y = 0 ; y < oysize ; y++ )
	    for ( int x = 0 ; x < oxsize ; x++,k++ )
		// refactor-nice.pl: check this substitution
		// old: gray[k] = GetVal(imggray,x,y);
		gray[k] = imggray.getPixel(x,y);
    }

    ichannels[I_COLOR].reInit ( oxsize, oysize, 3, true );

    long int k = 0;
    for ( int y = 0 ; y < oysize ; y++ )
	for ( int x = 0 ; x < oxsize ; x++,k++ )
	{
	    // refactor-nice.pl: check this substitution
	    // old: ichannels[I_COLOR].data[0][k] = GetVal(img.RedImage(), x, y);
	    ichannels[I_COLOR].data[0][k] = img.getPixel(x,y,0);
	    // refactor-nice.pl: check this substitution
	    // old: ichannels[I_COLOR].data[1][k] = GetVal(img.GreenImage(), x, y);
	    ichannels[I_COLOR].data[1][k] = img.getPixel(x,y,1);
	    // refactor-nice.pl: check this substitution
	    // old: ichannels[I_COLOR].data[2][k] = GetVal(img.BlueImage(), x, y);
	    ichannels[I_COLOR].data[2][k] = img.getPixel(x,y,2);
	}

    hasColorInformation = true;
}
	
CachedExample::~CachedExample()
{
    delete [] dchannels;
    delete [] ichannels;
    delete [] lchannels;

    for ( uint k = 0 ; k < SVNUMCHANNELS ; k++ )
	if ( svmap[k] != NULL )
	    delete [] (svmap[k]);

    delete [] svmap;
    delete [] svmap_xsize;
    delete [] svmap_ysize;

    // remove all temporary files
    for ( map<int, string>::const_iterator j = dtemps.begin();
					   j != dtemps.end();
					   j++ )
    {
	//fprintf (stderr, "CachedExample: removing temp file %s\n", j->second.c_str() );
	FileMgt::deleteTempFile ( j->second );
    }
    
    for ( map<int, string>::const_iterator j = itemps.begin();
					   j != itemps.end();
					   j++ )
    {
	//fprintf (stderr, "CachedExample: removing temp file %s\n", j->second.c_str() );
	FileMgt::deleteTempFile ( j->second );
    }

    for ( map<int, string>::const_iterator j = ltemps.begin();
					   j != ltemps.end();
					   j++ )
    {
	//fprintf (stderr, "CachedExample: removing temp file %s\n", j->second.c_str() );
	FileMgt::deleteTempFile ( j->second );
    }

}

void CachedExample::readImageData ()
{
    if ( imgfn == "" ) return;

    NICE::Image orig = Preprocess::ReadImgAdv(imgfn);
    NICE::Image imggray;

    if ( newWidth > 0 )
	Conversions::resizeImage ( orig, imggray, newWidth, newHeight );
    else
	imggray = orig;

    oxsize = imggray.width();
    oysize = imggray.height();

    ichannels[I_GRAYVALUES].reInit ( oxsize, oysize, 1, true );
    int *gray = ichannels[I_GRAYVALUES].data[0];
    int k = 0;
    for ( int y = 0 ; y < oysize ; y++ )
	for ( int x = 0 ; x < oxsize ; x++,k++ )
	    gray[k] = imggray.getPixel(x,y);
}

void CachedExample::readImageDataRGB ()
{
    if ( imgfn == "" ) return;

    NICE::ColorImage img;
    try {
	img = Preprocess::ReadImgAdvRGB(imgfn);
    } catch ( NICE::ImageException & ) {
	fprintf (stderr, "error reading rgb image %s\n", imgfn.c_str());
	hasColorInformation = false;
	return;
    }

    oxsize = img.width();
    oysize = img.height();

    hasColorInformation = true;
    
    ichannels[I_COLOR].reInit ( oxsize, oysize, 3, true );

    long k = 0;
    for ( int y = 0 ; y < oysize ; y++ )
	for ( int x = 0 ; x < oxsize ; x++,k++ )
	{
	    ichannels[I_COLOR].data[0][k] = img.getPixel(x,y,0);
	    ichannels[I_COLOR].data[1][k] = img.getPixel(x,y,1);
	    ichannels[I_COLOR].data[2][k] = img.getPixel(x,y,2);
	}
}

void CachedExample::calcIntegralImage ()
{
    if (ichannels[I_GRAYVALUES].xsize == 0)
    {
	readImageData ();
	if ( ichannels[I_GRAYVALUES].xsize == 0 )
	{
	    fprintf (stderr, "CachedExample::getChannel: unable to recover data channel\n");
	    exit(-1);
	}
    }

    lchannels[L_INTEGRALIMAGE].reInit ( ichannels[I_GRAYVALUES].xsize,
					ichannels[I_GRAYVALUES].ysize,
					1, true );
    
		GenericImageTools::calcIntegralImage ( 
		lchannels[L_INTEGRALIMAGE].data[0], 
		ichannels[I_GRAYVALUES].data[0], 
		ichannels[I_GRAYVALUES].xsize, 
		ichannels[I_GRAYVALUES].ysize );

}

void CachedExample::buildIntegralSV ( int svchannel, 
				      SparseVector *_map, 
				      int xsize_s, int ysize_s )
{
    SparseVector *map = _map;
    svmap[svchannel] = _map;
    svmap_xsize[svchannel] = xsize_s;
    svmap_ysize[svchannel] = ysize_s;

    int k = xsize_s;
    for ( int y = 1 ; y < ysize_s; y++, k+=xsize_s )
	map[k].add ( (map[k-xsize_s]) );

    k = 1;
    for ( int x = 1 ; x < xsize_s; x++, k++ )
	map[k].add ( (map[k-1]) );

    k = xsize_s + 1;

    for ( int y = 1 ; y < ysize_s ; y++,k++ )
    {
	for ( int x = 1 ; x < xsize_s ; x++,k++ )
	{
	    map[k].add ( (map[k-1]) );
	    map[k].add ( (map[k-xsize_s]) );
	    map[k].add ( (map[k-xsize_s-1]), -1.0 );
	}
    }
}

void CachedExample::setSVMap ( int svchannel, 
			      SparseVector *_map, 
			      int xsize_s, int ysize_s )
{
    svmap[svchannel] = _map;
    svmap_xsize[svchannel] = xsize_s;
    svmap_ysize[svchannel] = ysize_s;
}

SparseVector *CachedExample::getSVMap ( int svchannel,
				        int & _xsize, int & _ysize,
				        int & _tm_xsize, int & _tm_ysize ) const
{
    _xsize = oxsize;
    _ysize = oysize;
    _tm_xsize = svmap_xsize[svchannel];
    _tm_ysize = svmap_ysize[svchannel];
    assert ( svmap[svchannel] != NULL );
    return svmap[svchannel];
}

bool CachedExample::colorInformationAvailable() const
{
    if ( hasColorInformation ) return true;
    else {
	if ( imgfn.size() == 0 ) return false;

	int tmp_xsize, tmp_ysize, tmp_maxval, tmp_nr;
	// refactor: InfImgFile ( imgfn, tmp_xsize, tmp_ysize, tmp_maxval, tmp_nr );
	ImageFile imgf ( imgfn );
	const ImageFile::Header & imgfheader = imgf.getHeader();
	tmp_xsize = imgfheader.width;
	tmp_ysize = imgfheader.height;
	tmp_maxval = 255;
	tmp_nr = imgfheader.channel;

	if ( tmp_nr > 1 ) return true;
	else return false;
    }
}

void CachedExample::dropPreCached()
{
    dropImages<double> ( dchannels, dtemps, D_NUMCHANNELS );
    dropImages<int> ( ichannels, itemps, I_NUMCHANNELS );
    dropImages<long> ( lchannels, ltemps, L_NUMCHANNELS );
}