/**
* @file SemanticSegmentation.cpp
* @brief abstract interface for semantic segmentation algorithms
* @author Erik Rodner
* @date 03/19/2009

*/
#include <iostream>

#include "SemanticSegmentation.h"
#include "vislearning/baselib/Preprocess.h"
#include "vislearning/baselib/Globals.h"

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

void SemanticSegmentation::convertLSetToSparseExamples ( Examples &examples, LabeledSetVector &lvec )
{
#ifdef DEBUG_PRINTS
  cout << "SemSegRegionBased::convertLSetToExamples starts" << endl;
#endif
  for ( map< int, vector<NICE::Vector *> >::iterator iter = lvec.begin(); iter != lvec.end(); ++iter )
  {
    for ( int j = 0; j < ( int ) iter->second.size(); j++ )
    {
      Vector &tmp = * ( iter->second[j] );
      int dim = tmp.size();
      SparseVector *vec = new SparseVector ( dim );
      for ( int j = 0; j < dim; j++ )
      {
        if ( tmp[j] != 0.0 )
        {
          ( *vec ) [j] = tmp[j];
        }
      }
      Example ex;
      ex.svec = vec;
      examples.push_back ( pair<int, Example> ( iter->first, ex ) );
    }
  }
  lvec.clear();
#ifdef DEBUG_PRINTS
  cout << "SemSegRegionBased::convertLSetToExamples finished" << endl;
#endif
}

void SemanticSegmentation::convertLSetToExamples ( Examples &examples, LabeledSetVector &lvec, const bool & removeOldDataPointer )
{
#ifdef DEBUG_PRINTS
  cout << "SemSegRegionBased::convertLSetToExamples starts" << endl;
#endif
  for ( map< int, vector<NICE::Vector *> >::iterator iter = lvec.begin(); iter != lvec.end(); ++iter )
  {
    for ( int j = 0; j < (int)iter->second.size(); j++ )
    {
      NICE::Vector *vec = new NICE::Vector ( * ( iter->second[j] ) );
      Example ex ( vec );
      examples.push_back ( pair<int, Example> ( iter->first, ex ) );
    }
  }
  
  if (!removeOldDataPointer)
  {
    //NOTE this is only useful, if our classifier does NOT need the data explicitely
    lvec.clear();
  }
  else
  {
    lvec.removePointersToDataWithoutDeletion();
    //after setting all the pointers to NULL, we can savely clear the LSet without deleting the previously
    //stored features, which might be needed somewhere else, e.g., in the VCNearestNeighbour
    lvec.clear();
  }

#ifdef DEBUG_PRINTS
  cout << "SemSegRegionBased::convertLSetToExamples finished" << endl;
#endif
}

void SemanticSegmentation::convertExamplesToLSet ( Examples &examples, LabeledSetVector &lvec )
{
#ifdef DEBUG_PRINTS
  cout << "SemSegRegionBased::convertExamplesToLSet starts" << endl;
#endif
  lvec.clear();
  for ( int i = 0; i < ( int ) examples.size(); i++ )
  {
    if ( examples[i].second.vec != NULL )
    {
      lvec.add ( examples[i].first, *examples[i].second.vec );
      delete examples[i].second.vec;
      examples[i].second.vec = NULL;
    }
    else
    {
      if ( examples[i].second.svec != NULL )
      {
        NICE::Vector v;
        examples[i].second.svec->convertToVectorT(v);
        lvec.add ( examples[i].first, v );
        delete examples[i].second.svec;
        examples[i].second.svec = NULL;        
      }
      else
      {
        throw ( "no features for LabeledSet" );
      }
    }

  }
  examples.clear();  
#ifdef DEBUG_PRINTS
  cout << "SemSegRegionBased::convertExamplesToLSet finished" << endl;
#endif
}

void SemanticSegmentation::convertExamplesToVVector ( VVector &feats, Examples &examples, vector<int> &label )
{
#ifdef DEBUG_PRINTS
  cout << "SemSegRegionBased::convertExamplesToVVector starts" << endl;
#endif
  feats.clear();
  label.clear();
  for ( int i = 0; i < ( int ) examples.size(); i++ )
  {
    label.push_back ( examples[i].first );
    feats.push_back ( *examples[i].second.vec );
    delete examples[i].second.vec;
    examples[i].second.vec = NULL;
  }
  examples.clear();
#ifdef DEBUG_PRINTS
  cout << "SemSegRegionBased::convertExamplesToVVector finished" << endl;
#endif
}

void SemanticSegmentation::convertVVectorToExamples ( VVector &feats, Examples &examples, vector<int> &label )
{
#ifdef DEBUG_PRINTS
  cout << "SemSegRegionBased::convertVVectorToExamples starts" << endl;
#endif
  for ( int i = 0; i < ( int ) feats.size(); i++ )
  {
    NICE::Vector *v = new NICE::Vector ( feats[i] );
    Example ex ( v );
    ex.position = 0; //TODO: hier mal was besseres überlegen, damit Klassifikator wieder Bildspezifisch lernt
    examples.push_back ( pair<int, Example> ( label[i], ex ) );
    feats[i].clear();
  }
  feats.clear();
  label.clear();
#ifdef DEBUG_PRINTS
  cout << "SemSegRegionBased::convertVVectorToExamples finished" << endl;
#endif
}

SemanticSegmentation::SemanticSegmentation ( const Config *conf,
    const ClassNames *classNames )
{
  this->classNames = classNames;

  Preprocess::Init ( conf );

  std::string imagetype_s = conf->gS ( "main", "imagetype", "rgb" );

  if ( imagetype_s == "rgb" )
    imagetype = IMAGETYPE_RGB;
  else if ( imagetype_s == "gray" )
    imagetype = IMAGETYPE_GRAY;
  else {
    fprintf ( stderr, "SemanticSegmentation:: unknown image type option\n" );
    exit ( -1 );
  }
}

SemanticSegmentation::~SemanticSegmentation()
{
}

void SemanticSegmentation::semanticseg ( const std::string & filename,
    NICE::Image & segresult,
    NICE::MultiChannelImageT<double> & probabilities )
{
  Globals::setCurrentImgFN ( filename );
  CachedExample *ce;
  if ( imagetype == IMAGETYPE_RGB )
  {
    NICE::ColorImage img = Preprocess::ReadImgAdvRGB ( filename );
    ce = new CachedExample ( img );
  } else {

    NICE::Image img = Preprocess::ReadImgAdv ( filename );
    ce = new CachedExample ( img );
  }
  fprintf ( stderr, "Starting Semantic Segmentation !\n" );
  semanticseg ( ce, segresult, probabilities );
  delete ce;
}