#include "Operations.h"

using namespace OBJREC;
using namespace std;
using namespace NICE;

Operation::Operation()
{
  values = NULL;
  maxtypes = 1000;
}

void Operation::set ( int _x1, int _y1, int _x2, int _y2, int _channel1, int _channel2, ValueAccess *_values )
{
  x1 = _x1;
  y1 = _y1;
  x2 = _x2;
  y2 = _y2;
  channel1 = _channel1;
  channel2 = _channel2;
  values = _values;
}

void Operation::setContext ( bool _context )
{
  context = _context;
}

bool Operation::getContext()
{
  return context;
}

void Operation::setFeatType ( int _featType )
{
  featType = _featType;
}

int Operation::getFeatType()
{
  return featType;
}

void Operation::getXY ( const Features &feats, int &xsize, int &ysize )
{
  xsize = feats.feats->width();
  ysize = feats.feats->height();
}


void Operation::store ( std::ostream & os )
{
  os << x1 << " " << x2 << " " << y1 << " " << y2 << " " << channel1 << " " << channel2 << " " << featType << std::endl;
  if ( values == NULL )
    os << -1 << std::endl;
  else
    os << values->getType() << std::endl;
}

void Operation::restore ( std::istream &is )
{
  is >> x1;
  is >> x2;
  is >> y1;
  is >> y2;
  is >> channel1;
  is >> channel2;
  is >> featType;

  int tmp;
  is >> tmp;

  if ( tmp >= 0 )
  {
    if ( tmp == RAWFEAT )
    {
      values = new MCImageAccess();
    }
    else if ( tmp == CONTEXT )
    {
      values = new ClassificationResultAccess();
    }
    else
    {
      throw ( "no valid ValueAccess" );
    }
  }
  else
  {
    values = NULL;
  }
}

std::string Operation::writeInfos()
{
  std::stringstream ss;
  ss << " x1: " << x1 << " y1: " << y1 << " x2: " << x2 << " y2: " << y2 << " c1: " << channel1 << " c2: " << channel2;
  return ss.str();
}

double RegionFeat::getVal ( const Features &feats, const int &x, const int &y )
{
  return (*feats.rProbs)[(*feats.feats)(x,y,channel1)][channel2];
}

double Minus::getVal ( const Features &feats, const int &x, const int &y )
{
  int xsize, ysize;
  getXY ( feats, xsize, ysize );
  double v1 = values->getVal ( feats, BOUND ( x + x1, 0, xsize - 1 ), BOUND ( y + y1, 0, ysize - 1 ), channel1 );
  double v2 = values->getVal ( feats, BOUND ( x + x2, 0, xsize - 1 ), BOUND ( y + y2, 0, ysize - 1 ), channel2 );
  return v1 -v2;
}

double MinusAbs::getVal ( const Features &feats, const int &x, const int &y )
{
  int xsize, ysize;
  getXY ( feats, xsize, ysize );
  double v1 = values->getVal ( feats, BOUND ( x + x1, 0, xsize - 1 ), BOUND ( y + y1, 0, ysize - 1 ), channel1 );
  double v2 = values->getVal ( feats, BOUND ( x + x2, 0, xsize - 1 ), BOUND ( y + y2, 0, ysize - 1 ), channel2 );
  return abs ( v1 -v2 );
}

double Addition::getVal ( const Features &feats, const int &x, const int &y )
{
  int xsize, ysize;
  getXY ( feats, xsize, ysize );
  double v1 = values->getVal ( feats, BOUND ( x + x1, 0, xsize - 1 ), BOUND ( y + y1, 0, ysize - 1 ), channel1 );
  double v2 = values->getVal ( feats, BOUND ( x + x2, 0, xsize - 1 ), BOUND ( y + y2, 0, ysize -
                               1 ), channel2 );
  return v1 + v2;
}

double Only1::getVal ( const Features &feats, const int &x, const int &y )
{
  int xsize, ysize;
  getXY ( feats, xsize, ysize );
  double v1 = values->getVal ( feats, BOUND ( x + x1, 0, xsize - 1 ), BOUND ( y + y1, 0, ysize - 1 ), channel1 );
  return v1;
}

double RelativeXPosition::getVal ( const Features &feats, const int &x, const int &y )
{
  int xsize, ysize;
  getXY ( feats, xsize, ysize );
  return ( double ) x / ( double ) xsize;
}

double RelativeYPosition::getVal ( const Features &feats, const int &x, const int &y )
{
  int xsize, ysize;
  getXY ( feats, xsize, ysize );
  return ( double ) y / ( double ) ysize;
}

double IntegralOps::getVal ( const Features &feats, const int &x, const int &y )
{
  return feats.feats->getIntegralValue(x + x1, y + y1, x + x2, y + y2, channel1);
}

double GlobalFeats::getVal ( const Features &feats, const int &x, const int &y )
{
  int xsize, ysize;
  getXY ( feats, xsize, ysize );
  return feats.feats->getIntegralValue( 0, 0, xsize - 1, ysize - 1, channel1 );
}

double IntegralCenteredOps::getVal ( const Features &feats, const int &x, const int &y )
{
  return feats.feats->getIntegralValue(x - x1, y - y1, x + x1, y + y1, channel1);
}

double BiIntegralCenteredOps::getVal ( const Features &feats, const int &x, const int &y )
{
  return feats.feats->getIntegralValue(x - x1, y - y1, x + x1, y + y1, channel1 ) - feats.feats->getIntegralValue(x - x2, y - y2, x + x2, y + y2, channel1);
}

double HaarHorizontal::getVal ( const Features &feats, const int &x, const int &y )
{
  int tlx = x - x1;
  int tly = y - y1;
  int lrx = x + x1;
  int lry = y + y1;

  return feats.feats->getIntegralValue(tlx, tly, lrx, y, channel1 ) - feats.feats->getIntegralValue(tlx, y, lrx, lry, channel1);
}

double HaarVertical::getVal ( const Features &feats, const int &x, const int &y )
{
  int tlx = x - x1;
  int tly = y - y1;
  int lrx = x + x1;
  int lry = y + y1;

  return feats.feats->getIntegralValue(tlx, tly, x, lry, channel1) - feats.feats->getIntegralValue(x, tly, lrx, lry, channel1);
}

double HaarDiag::getVal ( const Features &feats, const int &x, const int &y )
{
  int tlx = x - x1;
  int tly = y - y1;
  int lrx = x + x1;
  int lry = y + y1;

  return feats.feats->getIntegralValue(tlx, tly, x, y, channel1) + feats.feats->getIntegralValue(x, y, lrx, lry, channel1) - feats.feats->getIntegralValue(tlx, y, x, lry, channel1) - feats.feats->getIntegralValue(x, tly, lrx, y, channel1);
}

double Haar3Horiz::getVal ( const Features &feats, const int &x, const int &y )
{
  int tlx = x - x2;
  int tly = y - y2;
  int mtly = y - y1;
  int mlry = y + y1;
  int lrx = x + x2;
  int lry = y + y2;

  return feats.feats->getIntegralValue(tlx, tly, lrx, mtly, channel1) - feats.feats->getIntegralValue(tlx, mtly, lrx, mlry, channel1) + feats.feats->getIntegralValue(tlx, mlry, lrx, lry, channel1);
}

double Haar3Vert::getVal ( const Features &feats, const int &x, const int &y )
{
  int tlx = x - x2;
  int tly = y - y2;
  int mtlx = x - x1;
  int mlrx = x + x1;
  int lrx = x + x2;
  int lry = y + y2;

  return feats.feats->getIntegralValue(tlx, tly, mtlx, lry, channel1) - feats.feats->getIntegralValue(mtlx, tly, mlrx, lry, channel1) + feats.feats->getIntegralValue(mlrx, tly, lrx, lry, channel1);
}

void IntegralOps::set ( int _x1, int _y1, int _x2, int _y2, int _channel1, int _channel2, ValueAccess *_values )
{
  x1 = std::min ( _x1, _x2 );
  y1 = std::min ( _y1, _y2 );
  x2 = std::max ( _x1, _x2 );
  y2 = std::max ( _y1, _y2 );
  channel1 = _channel1;
  channel2 = _channel2;
  values = _values;
}

void IntegralCenteredOps::set ( int _x1, int _y1, int _x2, int _y2, int _channel1, int _channel2, ValueAccess *_values )
{
  x1 = abs ( _x1 );
  y1 = abs ( _y1 );
  x2 = abs ( _x2 );
  y2 = abs ( _y2 );
  channel1 = _channel1;
  channel2 = _channel2;
  values = _values;
}

void BiIntegralCenteredOps::set ( int _x1, int _y1, int _x2, int _y2, int _channel1, int _channel2, ValueAccess *_values )
{
  x1 = std::min ( abs ( _x1 ), abs ( _x2 ) );
  y1 = std::min ( abs ( _y1 ), abs ( _y2 ) );
  x2 = std::max ( abs ( _x1 ), abs ( _x2 ) );
  y2 = std::max ( abs ( _y1 ), abs ( _y2 ) );
  channel1 = _channel1;
  channel2 = _channel2;
  values = _values;
}