#include <iostream>

#include "vislearning/classifier/vclassifier/VCDTSVM.h"

#include "core/image/ImageT.h"
//#include "core/imagedisplay/ImageDisplay.h"
#include "core/basics/StringTools.h"

#undef WRITE

using namespace OBJREC;

using namespace std;
using namespace NICE;

VCDTSVM::VCDTSVM ( const Config *_conf, const string & section )
    : VecClassifier ( _conf )
{
  binary = _conf->gS ( section, "binary", "./tdsvm" );
  configtrain = _conf->gS ( section, "configtrain", "configtrain.txt" );
  configtest = _conf->gS ( section, "configtest", "configtest.txt" );
  trainfile  = _conf->gS ( section, "traindst", "train.txt" );
  testfile  = _conf->gS ( section, "testdst", "test.txt" );

#ifndef WRITE
  counter = new vector<int> ( 1, 0 );
  if ( results.size() == 0 )
  {

    ifstream fin ( "results.txt" );


    const int bufsize = 1024 * 1024;
    char *buf = new char[bufsize];
    std::string buf_s;
    while ( !fin.eof() )
    {
      int bc;
      vector<string> elements;
      fin >> bc;
      fin.get ( buf, bufsize );
      buf_s = buf;

      if ( buf_s.size() <= 0 )
        break;

      StringTools::split ( buf_s, ' ', elements );

      if ( elements.size() <= 1 )
        break;

      vector<double> tmp;

      size_t l = 0;

      // skip first element because of white space
      for ( vector<string>::const_iterator i  = elements.begin() + 1; i != elements.end(); i++, l++ )
      {
        double val = atof ( i->c_str() );
        tmp.push_back ( val );
      }
      results.push_back ( tmp );
      labels.push_back ( bc );
    }

    fin.close();

    ( *counter ) [0] = 0;
    //counter = 0;
  }
#endif
}

VCDTSVM::VCDTSVM ( const VCDTSVM & classifier ) : VecClassifier()
{
  binary = classifier.binary;
  configtrain = classifier.configtrain;
  configtest = classifier.configtest;
  trainfile = classifier.trainfile;
  testfile = classifier.testfile;
}


VCDTSVM::~VCDTSVM()
{
  int c2 = ( *counter ) [0];
  cout << "c2: " << c2 << " matsize " << results.size() << endl;
}

ClassificationResult VCDTSVM::classify ( const NICE::Vector & x ) const
{


#ifdef WRITE
  ofstream fout ( testfile.c_str(), ios::app );
  fout << 0 << " ";
  int i;
  for ( i = 0; i < x.size() - 1; i++ )
  {
    fout << i + 1 << ":" << x[i] << " ";
  }
  i++;
  fout << i + 1 << ":" << x[i] << endl;
  fout.close();


  FullVector scores ( 10 );

  //scores.read("scores");
  double bval = scores[0];

  int bclass = 0;
  for ( i = 1; i < scores.size(); i++ )
  {
    if ( bval < scores[i] )
    {
      bval = scores[i];
      bclass = i;
    }
  }
  return ClassificationResult ( bclass, scores );
#else
  int c2 = ( *counter ) [0];
  ( *counter ) [0]++;
  FullVector tmp ( results[c2].size() );
  for ( int i = 0; i < results[c2].size(); i++ )
  {
    tmp[i] = results[c2][i];
  }
  return ClassificationResult ( labels[c2], tmp );
#endif

#if 0
  const int buffersize = 65536;
  char *buffer = new char [buffersize];

  string call = binary + " " + configtest;

  FILE *f = popen ( call.c_str(), "r" );

  if ( f == NULL )
  {
    fprintf ( stderr, "VCDTSVM::classify: FATAL ERROR, unable to run the implementation of DTSVM\n" );
    exit ( -1 );
  }

  while ( ! feof ( f ) )
  {
    if ( fgets ( buffer, buffersize, f ) <= 0 )
    {
      break;
    } else
    {
      //fprintf (stderr, "VCDTSVM::classify: [INFO] %s", buffer );
    }
  }
  pclose ( f );
#endif
}

void VCDTSVM::teach ( const LabeledSetVector & _teachSet )
{
  maxClassNo = _teachSet.getMaxClassno();
  //TODO: LabeledSet rausschreiben und classifier anwerfen
#ifdef WRITE
  _teachSet.write ( trainfile, LabeledSetVector::FILEFORMAT_INDEX );
  /*
   string call = binary +" "+configtrain;

   const int buffersize = 65536;
  char *buffer = new char [buffersize];

  FILE *f = popen ( call.c_str(), "r" );

  if ( f == NULL )
  {
  fprintf (stderr, "VCDTSVM::teach: FATAL ERROR, unable to run the implementation of DTSVM\n");
  exit(-1);
  }

  while ( ! feof(f) )
  {
  if ( fgets ( buffer, buffersize, f ) <= 0 )
  {
  break;
  } else
  {
  fprintf (stderr, "VCDTSVM::teach: [INFO] %s", buffer );
  }
  }
  pclose(f);*/
#endif
}

void VCDTSVM::finishTeaching()
{
}

/** clone this object */
VCDTSVM *VCDTSVM::clone ( void ) const
{
  VCDTSVM *classifier = new VCDTSVM ( *this );
  return classifier;
}

void VCDTSVM::clear ()
{
  //TODO wieder freigeben
}

void VCDTSVM::read ( const string& s, int format )
{
  //TODO: Zielverzeichnis eventuell
}

void VCDTSVM::save ( const string& s, int format ) const
{
  //TODO: Zielverzeichnis eventuell
}


void VCDTSVM::store ( std::ostream & os, int format ) const
{
  fprintf ( stderr, "VCDTSVM: unable to write to stream! please use read()\n" );
}

void VCDTSVM::restore ( std::istream & is, int format )
{
  fprintf ( stderr, "VCDTSVM: unable to read from stream! please use save()\n" );
  exit ( -1 );
}
