#ifdef NICE_USELIB_CPPUNIT

#include <string>
#include <exception>

#include "TestKMedian.h"

#include <core/basics/Config.h>
#include "vislearning/math/distances/genericDistance.h"


const bool verboseStartEnd = true;
const bool verbose = false;
const std::string distanceType = "euclidean";

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

CPPUNIT_TEST_SUITE_REGISTRATION( TestKMedian );

void TestKMedian::setUp() {
}

void TestKMedian::tearDown() {
}

void TestKMedian::testKMedianClustering() 
{
  if (verboseStartEnd)
    std::cerr << "================== TestKMedian::testKMedianClustering ===================== " << std::endl;
  
  Config * conf = new Config;
  std::string section ( "KMedian" );
  conf->sS( section, "distanceType", "euclidean" );
  conf->sI( section, "maxIterations", 200 );
  conf->sI( section, "noClusters", 2 );
   
  OBJREC::KMedian kMedian ( conf, section );
  
  //create some artificial data
  NICE::VVector features;
  NICE::Vector x1 (2); x1[0] = 1;  x1[1] = 1; features.push_back(x1);
  NICE::Vector x2 (2); x2[0] = 4;  x2[1] = 1; features.push_back(x2);
  NICE::Vector x3 (2); x3[0] = 2;  x3[1] = 4; features.push_back(x3);
  NICE::Vector x4 (2); x4[0] = 10; x4[1] = 3; features.push_back(x4);
  NICE::Vector x5 (2); x5[0] = 8;  x5[1] = 3; features.push_back(x5);
  NICE::Vector x6 (2); x6[0] = 4;  x6[1] = 3; features.push_back(x6);
  NICE::Vector x7 (2); x7[0] = 3;  x7[1] = 2; features.push_back(x7);
  NICE::Vector x8 (2); x8[0] = 1;  x8[1] = 3; features.push_back(x8);
  NICE::Vector x9 (2); x9[0] = 9;  x9[1] = 2; features.push_back(x9);
  
  //cluster data
  NICE::VVector prototypes;
  std::vector<double> weights;
  std::vector<int> assignment;
  
  kMedian.cluster ( features, prototypes, weights, assignment );  

  //check whether the results fits the ground truth  
  //NOTE
  // If no random initialization is activated, we initially grab x2 and x8.
  // After 3 iterations, we should have converged and obtain x5 and x7.

  NICE::VectorDistance<double> * distancefunction = GenericDistanceSelection::selectDistance(distanceType);

  if ( verbose )
  {
    std::cerr << " x9: " << x9 << " cl1: " << prototypes[0] << std::endl;
    std::cerr << " x7: " << x7 << " cl2: " << prototypes[1] << std::endl;
  }
  
  double distX9Cl1 ( distancefunction->calculate( x9, prototypes[0] ) );
  double distX7Cl2 ( distancefunction->calculate( x7, prototypes[1] ) );
  
  CPPUNIT_ASSERT_DOUBLES_EQUAL( distX9Cl1, 0.0, 1e-8);
  CPPUNIT_ASSERT_DOUBLES_EQUAL( distX7Cl2, 0.0, 1e-8); 
  
  std::cerr << "                               successfull              " << std::endl;
        
  //don't waste memory
  delete conf;
  
  if (verboseStartEnd)
    std::cerr << "================== TestKMedian::testKMedianClustering done ===================== " << std::endl;
}


void TestKMedian::testKMedianPersistent() 
{
  if (verboseStartEnd)
    std::cerr << "================== TestKMedian::testKMedianPersistent ===================== " << std::endl;
  
  Config * conf = new Config;
  std::string section ( "KMedian" );
  conf->sS( section, "distanceType", "euclidean" );
  conf->sI( section, "maxIterations", 200 );
  conf->sI( section, "noClusters", 2 );
   
  OBJREC::KMedian kMedian;
  kMedian.initFromConfig( conf, section );
  
  // TEST STORING ABILITIES
  if ( verbose )
    std::cerr << " TEST STORING ABILITIES FOR KMEDIAN" << std::endl;
  
  std::string s_destination_save ( "myKMedian.txt" );
  
  std::filebuf fbOut;
  fbOut.open ( s_destination_save.c_str(), ios::out );
  std::ostream os (&fbOut);
  //
  kMedian.store( os );
  //   
  fbOut.close();
  
  // TEST RESTORING ABILITIES
  if ( verbose )
    std::cerr << " TEST RESTORING ABILITIES FOR KMEDIAN" << std::endl;
    
  OBJREC::KMedian kMedianRestore;  
      
  std::string s_destination_load ( "myKMedian.txt" );
  
  std::filebuf fbIn;
  fbIn.open ( s_destination_load.c_str(), ios::in );
  std::istream is (&fbIn);
  //
  kMedianRestore.restore( is );
  //   
  fbIn.close(); 
  
  // currently, we have no possibility to actually verify that the restore-operation was successfull, i.e.,
  // it returned an object identical to the stored one.
  // However, if we reached this point, at least something went right, so we should be happy...  
  
  //don't waste memory
  delete conf;
  
  if (verboseStartEnd)
    std::cerr << "================== TestKMedian::testKMedianPersistent done ===================== " << std::endl;
}


#endif