/**
* @file SemanticFeature.cpp
* @brief texton feature similar to jamie shottons idea
* @author Erik Rodner
* @date 05/07/2008

*/
#include <iostream>

#include "SemanticFeature.h"
#include "vislearning/cbaselib/FeaturePool.h"

using namespace OBJREC;

using namespace std;
using namespace NICE;



/** simple constructor */
SemanticFeature::SemanticFeature ( const Config *conf,
                                   const set<int> *_possibleClassNos )
    : possibleClassNos ( _possibleClassNos )
{
  window_size_x = conf->gI ( "SemanticFeature", "window_size_x", 21 );
  window_size_y = conf->gI ( "SemanticFeature", "window_size_y", 21 );
  scaleStep = conf->gD ( "SemanticFeature", "scale_step", sqrt ( 2 ) );
  numScales = conf->gI ( "SemanticFeature", "num_scales", 5 );
  end_shiftx = conf->gI ( "SemanticFeature", "end_shift_x", 40 );
  end_shifty = conf->gI ( "SemanticFeature", "end_shift_y", 40 );
  step_shiftx = conf->gI ( "SemanticFeature", "step_shift_x", 5 );
  step_shifty = conf->gI ( "SemanticFeature", "step_shift_y", 5 );

  shiftx = 0;
  shifty = 0;
}

SemanticFeature::SemanticFeature ( const Config *conf )
{
  SemanticFeature ( conf, NULL );
}

/** simple destructor */
SemanticFeature::~SemanticFeature()
{
}

double SemanticFeature::val ( const Example *example ) const
{
  const NICE::MultiChannelImageT<double> & img = example->ce->getDChannel (
        CachedExample::D_INTEGRALPRIOR );

  int xsize;
  int ysize;
  example->ce->getImageSize ( xsize, ysize );
  int tm_xsize = img.width();
  int tm_ysize = img.height();

#if 0
  int xtl = example->x - window_size_x / 2;
  int ytl = example->y - window_size_y / 2;
  int xrb = example->x + window_size_x / 2;
  int yrb = example->y + window_size_y / 2;

  xtl = xtl * tm_xsize / xsize;
  ytl = ytl * tm_ysize / ysize;
  xrb = xrb * tm_xsize / xsize;
  yrb = yrb * tm_ysize / ysize;
#endif

  int wsx2 = window_size_x * tm_xsize / ( 2 * xsize );
  int wsy2 = window_size_y * tm_ysize / ( 2 * ysize );
  int xx = ( example->x + shiftx ) * tm_xsize / xsize;
  int yy = ( example->y + shifty ) * tm_ysize / ysize;
  int xtl = xx - wsx2;
  int ytl = yy - wsy2;
  int xrb = xx + wsx2;
  int yrb = yy + wsy2;

#define BOUND(x,min,max) (((x)<(min))?(min):((x)>(max)?(max):(x)))
  xtl = BOUND ( xtl, 0, tm_xsize - 1 );
  ytl = BOUND ( ytl, 0, tm_ysize - 1 );
  xrb = BOUND ( xrb, 0, tm_xsize - 1 );
  yrb = BOUND ( yrb, 0, tm_ysize - 1 );
#undef BOUND

  double A, B, C, D;

  A = img.get(xtl,ytl,classno);
  B = img.get(xrb,ytl,classno); 
  C = img.get(xtl,yrb,classno);
  D = img.get(xrb,yrb,classno);

  int area = ( xrb - xtl ) * ( yrb - ytl );

  /*******************************
   BE CAREFUL
  THIS INCORPORATES POSTION
  INFORMATION INDIRECTLY
  ********************************/

  if ( area == 0 )
  {
    return 0.0;
  }
  else
  {
    /* A B
    C D  */
    return ( D - B - C + A ) / area;
  }
}

void SemanticFeature::explode ( FeaturePool & featurePool, bool variableWindow ) const
{
  if ( possibleClassNos == NULL )
  {
    fprintf ( stderr, "SemanticFeature::explode: no classno set given !\n" );
    exit ( -1 );
  }
  // use leaf nodes only !!
  for ( set<int>::const_iterator k = possibleClassNos->begin();
        k != possibleClassNos->end();
        k++ )
  {
    for ( int sy = 0 ; sy <= end_shifty ; sy += step_shifty )
    {
      for ( int sx = 0 ; sx <= end_shiftx ; sx += step_shiftx )
      {
        int wsy = window_size_y;
        int wsx = window_size_x;
        for ( int i = 0 ; i < numScales ; i++ )
        {
          SemanticFeature *f = new SemanticFeature();
          f->classno = *k;
          f->window_size_x = wsx;
          f->window_size_y = wsy;
          f->shiftx = sx;
          f->shifty = sy;
          featurePool.addFeature ( f, step_shiftx * step_shifty / ( double ) ( end_shiftx * end_shifty * possibleClassNos->size() ) );
          wsx = ( int ) ( scaleStep * wsx );
          wsy = ( int ) ( scaleStep * wsy );
        }
      }
    }
  }
}

Feature *SemanticFeature::clone() const
{
  SemanticFeature *f = new SemanticFeature();
  f->window_size_x = window_size_x;
  f->window_size_y = window_size_y;
  f->classno = classno;
  f->shiftx = shiftx;
  f->shifty = shifty;

  return f;
}

Feature *SemanticFeature::generateFirstParameter () const
{
  return clone();
}

void SemanticFeature::restore ( istream & is, int format )
{
  is >> window_size_x;
  is >> window_size_y;
  is >> shiftx;
  is >> shifty;
  is >> classno;
}

void SemanticFeature::store ( ostream & os, int format ) const
{
  os << "SemanticFeature "
  << window_size_x << " "
  << window_size_y << " "
  << shiftx << " "
  << shifty << " "
  << classno;
}

void SemanticFeature::clear ()
{
}