#ifdef NICE_USELIB_OPENMP
#include <omp.h>
#endif

#include <iostream>

#include "vislearning/features/localfeatures/sift.h"
#include "vislearning/features/localfeatures/LocalFeatureRGBSift.h"

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


///////////////////// ///////////////////// /////////////////////
//                   CONSTRUCTORS / DESTRUCTORS
///////////////////// ///////////////////// /////////////////////

LocalFeatureRGBSift::LocalFeatureRGBSift() : LocalFeatureSift () 
{
  //set deletemode variable of partent object
  this->deletemode = false;
}

LocalFeatureRGBSift::LocalFeatureRGBSift ( const NICE::Config * _conf )
{
  this->initFromConfig( _conf );  
}

LocalFeatureRGBSift::~LocalFeatureRGBSift()
{
}

void LocalFeatureRGBSift::initFromConfig( const NICE::Config* _conf, const std::string& _confSection )
{
  //first of all, call method of parent object
  LocalFeatureSift::initFromConfig( _conf );
  
  //set deletemode variable of parent object
  this->deletemode = false;
}

///////////////////// ///////////////////// /////////////////////
//                      FEATURE STUFF
///////////////////// ///////////////////// ////////////////// 

int
LocalFeatureRGBSift::getDescriptors ( const NICE::ColorImage & img, VVector & positions, VVector & descriptors ) const
{
  this->sortPositions ( positions );
  descriptors.clear();
  for ( int i = 0; i < ( int ) positions.size(); i++ )
  {
    NICE::Vector v;
    descriptors.push_back ( v );
  }

  std::vector< NICE::VVector > desc ( 3 );

#ifdef NICE_USELIB_OPENMP
  // check whether siftGPU should be used
  int numberOfCPU = omp_get_num_procs();
  int numberOfThreads = 0;
  if ( this->isGpuUsed() )
  {
    // in case of siftGPU it is possible to use one device
    numberOfThreads = 1;
    clog << "[log] LocalFeatureRGBSift: no multithreading" << endl;
  }
  else
  {
    // in case of siftpp it is possible to use all given cores
    numberOfThreads = numberOfCPU;
    clog << "[log] LocalFeatureRGBSift: multithreading with (max) " << numberOfCPU << " threads" << endl;
  }
#endif

#pragma omp parallel for num_threads(numberOfThreads)
  for ( int i = 0; i < 3; i++ )
  {
    NICE::Image tmp ( img.width(), img.height() );

    for ( int y = 0; y < img.height(); y++ )
    {
      for ( int x = 0; x < img.width(); x++ )
      {
        tmp.setPixel ( x, y, img.getPixel ( x, y, i ) );
      }
    }
    NICE::VVector pos = positions;
    this->computeDesc ( tmp, pos, desc[i] );
  }

  for ( int i = 0; i < 3; i++ )
  {
    assert ( desc[i].size() == descriptors.size() );

    if ( i == 0 ) {
#pragma omp parallel for num_threads( numberOfCPU )
      for ( int j = 0; j < ( int ) desc[i].size(); j++ )
      {
        descriptors[j] = desc[i][j];
      }
    }
    else 
    {
#pragma omp parallel for num_threads( numberOfCPU )
      for ( int j = 0; j < ( int ) desc[i].size(); j++ )
      {
        descriptors[j].append ( desc[i][j] );
      }
    }
  }

  return positions.size();
}

///////////////////// INTERFACE PERSISTENT /////////////////////
// interface specific methods for store and restore
///////////////////// INTERFACE PERSISTENT ///////////////////// 

void LocalFeatureRGBSift::restore ( std::istream & is, int format )
{
  //delete everything we knew so far...
  this->clear();
  
  
  if ( is.good() )
  {
    
    std::string tmp;
    is >> tmp; //class name 
    
    if ( ! this->isStartTag( tmp, "LocalFeatureRGBSift" ) )
    {
      std::cerr << " WARNING - attempt to restore LocalFeatureRGBSift, but start flag " << tmp << " does not match! Aborting... " << std::endl;
      throw;
    }   
    
    bool b_endOfBlock ( false ) ;
    
    while ( !b_endOfBlock )
    {
      is >> tmp; // start of block 
      
      if ( this->isEndTag( tmp, "LocalFeatureRGBSift" ) )
      {
        b_endOfBlock = true;
        continue;
      }      
      
      tmp = this->removeStartTag ( tmp );    
      
      ///////////////////////////////
      //       PARENT OBJECT       //
      ///////////////////////////////
      if ( tmp.compare("LocalFeatureSift--Parent") == 0 )
      {
        // restore parent object
        LocalFeatureSift::restore(is);
        is >> tmp; // end of block 
        tmp = this->removeEndTag ( tmp );        
      }      
      else
      {
      std::cerr << "WARNING -- unexpected LocalFeatureRGBSift object -- " << tmp << " -- for restoration... aborting" << std::endl;
      throw;
      }
    }
  }
  else
  {
    std::cerr << "LocalFeatureRGBSift::restore -- InStream not initialized - restoring not possible!" << std::endl;
    throw;
  }
}

void LocalFeatureRGBSift::store ( std::ostream & os, int format ) const
{ 
  if (os.good())
  {
    // show starting point
    os << this->createStartTag( "LocalFeatureRGBSift" ) << std::endl;    
        
    ///////////////////////////////
    //       PARENT OBJECT       //
    ///////////////////////////////
    os << this->createStartTag( "LocalFeatureSift--Parent" ) << std::endl;
    LocalFeatureSift::store(os);  
    os << this->createStartTag( "LocalFeatureSift--Parent" ) << std::endl;   
    
    // done
    os << this->createEndTag( "LocalFeatureRGBSift" ) << std::endl;    
  }
  else
  {
    std::cerr << "OutStream not initialized - storing not possible!" << std::endl;
  }
}

void LocalFeatureRGBSift::clear ()
{
}
