/** 
* @file testImageNetBinary.cpp
* @brief perform ImageNet tests with binary classification
* @author Erik Rodner
* @date 01/04/2012

*/
#include <core/basics/Config.h>

#ifdef NICE_USELIB_MATIO

#include <core/matlabAccess/MatFileIO.h>

//----------

#include <vislearning/cbaselib/ClassificationResults.h>
#include <vislearning/baselib/ProgressBar.h>
#include <vislearning/matlabAccessHighLevel/ImageNetData.h>

//----------

#include <gp-hik-core/FeatureMatrixT.h>
#include <gp-hik-core/tools.h>

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


/** 
    test the basic functionality of fast-hik hyperparameter optimization 
*/
int main (int argc, char **argv)
{   
  std::set_terminate(__gnu_cxx::__verbose_terminate_handler);

  Config conf ( argc, argv );
  string resultsfile = conf.gS("main", "results", "results.txt" );
  int positiveClass = conf.gI("main", "positive_class");

  cerr << "Positive class is " << positiveClass << endl;
  
  sparse_t data;
  NICE::Vector yl;
  cerr << "Reading ImageNet data ..." << endl;
  bool imageNetLocal = conf.gB("main", "imageNetLocal" , false);
  string imageNetPath;
  if (imageNetLocal)
    imageNetPath = "/users2/rodner/data/imagenet/devkit-1.0/";
  else
    imageNetPath = "/home/dbv/bilder/imagenet/devkit-1.0/";

  ImageNetData imageNet ( imageNetPath + "demo/" );

  imageNet.getBatchData ( data, yl, "train", "training" );

  uint n = yl.size();
  
  cerr << "Performing hyperparameter optimization ... " << endl;
  set<int> positives;
  set<int> negatives;

  map< int, set<int> > mysets;
  for ( uint i = 0 ; i < n; i++ )
    mysets[ yl[i] ].insert ( i );

  if ( mysets[ positiveClass ].size() == 0 ) 
    fthrow(Exception, "Class " << positiveClass << " is not available.");

  // add our positive examples
  for ( set<int>::const_iterator i = mysets[positiveClass].begin(); i != mysets[positiveClass].end(); i++ )
    positives.insert ( *i );

  int Nneg = conf.gI("main", "nneg", 1 );
  for ( map<int, set<int> >::const_iterator k = mysets.begin(); k != mysets.end(); k++ )
  {
    int classno = k->first;
    if ( classno == positiveClass )
      continue;
    const set<int> & s = k->second;
    uint ind = 0;
    for ( set<int>::const_iterator i = s.begin(); (i != s.end() && ind < Nneg); i++,ind++  )
      negatives.insert ( *i );
  }
  cerr << "Number of positive examples: " << positives.size() << endl;
  cerr << "Number of negative examples: " << negatives.size() << endl;
  
  map<int, int> examples;
  Vector y ( yl.size() );
  int ind = 0;
  for ( uint i = 0 ; i < yl.size(); i++ )
  {
    if (positives.find(i) != positives.end()) {
      y[ examples.size() ] = 1.0;
      examples.insert( pair<int, int> ( i, ind ) );
      ind++;
    } else if ( negatives.find(i) != negatives.end() ) {
      y[ examples.size() ] = -1.0;
      examples.insert( pair<int, int> ( i, ind ) );
      ind++;
    }
  }
  y.resize( examples.size() );
  cerr << "Examples: " << examples.size() << endl; 

  cerr << "Putting everything in a feature matrix structure ..." << endl;
  FeatureMatrixT<double> fm ( data, examples, 1000 );
  
  cerr << "Writing file ..." << endl;
  ofstream ofs ( "train.txt", ios::out );
  if ( !ofs.good() )
    fthrow(Exception, "Unable to write to train.txt" );
  // writing features
  for ( uint i = 0 ; i < fm.get_n(); i++ )
  {
    ofs << (y[i] == 1.0) ? 1 : 0;
    for ( uint k = 0 ; k < fm.get_d(); k++ )
    {
      double val = fm(k,i);
      if ( val != 0 ) 
      {
        ofs << " " << k+1 << ":" << val;
      }
    }
    ofs << endl;
  }
  ofs.close();

  // ------------------------------ TESTING ------------------------------
  cerr << "Reading ImageNet test data files (takes some seconds)..." << endl;
  imageNet.preloadData ( "val", "testing" );
  imageNet.loadExternalLabels ( imageNetPath + "data/ILSVRC2010_validation_ground_truth.txt" );

  ofstream ofs_test ( "test.txt", ios::out );
  if ( !ofs_test.good() )
    fthrow(Exception, "Unable to write to test.txt" );

  for ( uint i = 0 ; i < (uint)imageNet.getNumPreloadedExamples(); i++ )
  {
    const SparseVector & svec = imageNet.getPreloadedExample ( i );
    int classno_groundtruth = (((int)imageNet.getPreloadedLabel ( i )) == positiveClass) ? 1 : 0;

    ofs_test << ( classno_groundtruth );
    for ( SparseVector::const_iterator k = svec.begin(); k != svec.end(); k++ )
      ofs_test << " " << k->first+1 << ":" << k->second;
    ofs_test << endl;
  }

  ofs_test.close();

  return 0;
}
#else
int main (int argc, char **argv)
{
  std::cerr << "MatIO library is missing in your system - this program will have no effect. " << std::endl;  
}

#endif