/**
* @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 );
}