/**
  * Unit test for Extremely randomized clustering forest (ERC).
  *
  * @author Johannes Ruehle
  * @date 01/05/2014
  */
#ifdef NICE_USELIB_CPPUNIT

#include <string>
#include <exception>
#include <iostream>
#include <fstream>

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

#include "TestCodebookRandomForest.h"

#include "vislearning/features/simplefeatures/CodebookRandomForest.h"
#include "vislearning/features/fpfeatures/VectorFeature.h"

#include "vislearning/cbaselib/FeaturePool.h"

const bool verbose = false;
const bool verboseStartEnd = true;

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

CPPUNIT_TEST_SUITE_REGISTRATION( TestCodebookRandomForest );

void TestCodebookRandomForest::setUp() {
}

void TestCodebookRandomForest::tearDown() {
}
void TestCodebookRandomForest::testCodebookRandomForest()
{
    if (verboseStartEnd)
        std::cerr << "================== TestCodebookRandomForest::TestCodebookRandomForest ===================== " << std::endl;
    try
        {
        Matrix mX;
        Vector vY;
        Vector vY_multi;

        //ifstream ifs ("toyExample1.data", ios::in);
        //   ifstream ifs ("toyExampleLargeScale.data", ios::in);
        ifstream ifs ("toyExampleLargeLargeScale.data", ios::in);
        CPPUNIT_ASSERT ( ifs.good() );
        ifs >> mX;
        ifs >> vY;
        ifs >> vY_multi;
        ifs.close();

        if (verbose)
        {
            std::cerr << "data loaded: mX" << std::endl;
            std::cerr << mX << std::endl;
            std::cerr << "vY: " << std::endl;
            std::cerr << vY << std::endl;
            std::cerr << "vY_multi: " << std::endl;
            std::cerr << vY_multi << std::endl;
        }

        int iNumFeatureDimension = mX.cols();

        // memory layout needs to be transposed into rows x column: features x samples
        // features must lay next to each other in memory, so that each feature vector can
        // be adressed by a starting pointer and the number of feature dimensions to come.
        Matrix mX_transposed = mX.transpose();

        Examples examples;

        bool bSuccess = Examples::wrapExamplesAroundFeatureMatrix(mX_transposed, vY_multi, examples);
        CPPUNIT_ASSERT( bSuccess );

        CPPUNIT_ASSERT( examples.size() == mX.rows() );

        //----------------- create raw feature mapping -------------
        OBJREC::FeaturePool fp;
        OBJREC::VectorFeature *pVecFeature = new OBJREC::VectorFeature(iNumFeatureDimension);
        pVecFeature->explode(fp);

        //----------------- debug features -------------
        OBJREC::Example t_Exp = examples[0].second;
        NICE::Vector t_FeatVector;
        fp.calcFeatureVector(t_Exp, t_FeatVector);
        std::cerr << "first full Feature Vec: " <<t_FeatVector << std::endl;

        //----------------- train our random Forest -------------
        NICE::Config conf("config.conf");
        OBJREC::FPCRandomForests *pRandForest = new OBJREC::FPCRandomForests(&conf,"RandomForest");
        pRandForest->train(fp, examples);

        //----------------- create codebook ERC clusterer -------------
        int nMaxDepth        = conf.gI("CodebookRandomForest", "maxDepthTree",10);
        int nMaxCodebookSize = conf.gI("CodebookRandomForest", "maxCodebookSize",100);

        std::cerr << "maxDepthTree " << nMaxDepth << std::endl;

        OBJREC::CodebookRandomForest *pCodebookRandomForest = new OBJREC::CodebookRandomForest(pRandForest, nMaxDepth, nMaxCodebookSize);




        //----------------- quantize samples into histogram -------------
        size_t iNumCodewords        = pCodebookRandomForest->getCodebookSize();
        NICE::Vector histogram(iNumCodewords, 0.0f);

        int t_iCodebookEntry; double t_fWeight; double t_fDistance;

        for (size_t i = 0; i < examples.size(); i++ )
        {
            Example &t_Ex = examples[i].second;
            pCodebookRandomForest->voteVQ( *t_Ex.vec, histogram, t_iCodebookEntry, t_fWeight, t_fDistance );
            std::cerr << i << ": " << "CBEntry " << t_iCodebookEntry << " Weight: " << t_fWeight << " Distance: " << t_fDistance << std::endl;
        }
        std::cerr << "histogram: " << histogram << std::endl;




        // test of store and restore
        std::string t_sDestinationSave = "codebookRF.save.txt";
        std::ofstream ofs;
        ofs.open (t_sDestinationSave.c_str(), std::ofstream::out);
        pCodebookRandomForest->store( ofs );
        ofs.close();
        // restore
        OBJREC::CodebookRandomForest *pTestCRF = new OBJREC::CodebookRandomForest(-1, -1);
        std::ifstream ifs2;
        ifs2.open (t_sDestinationSave.c_str() );
        pTestCRF->restore( ifs2 );
        ifs2.close();
        CPPUNIT_ASSERT_EQUAL(iNumCodewords,     pTestCRF->getCodebookSize() );
        CPPUNIT_ASSERT_EQUAL(nMaxDepth,         pTestCRF->getMaxDepth() );
        CPPUNIT_ASSERT_EQUAL(nMaxCodebookSize,  pTestCRF->getRestrictedCodebookSize() );

        NICE::Vector histogramCompare(iNumCodewords, 0.0f);

        for (size_t i = 0; i < examples.size(); i++ )
        {
            Example &t_Ex = examples[i].second;
            pTestCRF->voteVQ( *t_Ex.vec, histogramCompare, t_iCodebookEntry, t_fWeight, t_fDistance );

        }
        std::cerr << "histogram of restored CodebookRandomForest: " << histogramCompare << std::endl;
        std::cerr << "comparing histograms...";
        for (size_t i = 0; i < iNumCodewords; i++ )
        {
            CPPUNIT_ASSERT_DOUBLES_EQUAL(histogram[i], histogramCompare[i], 1e-5 );
        }
        std::cerr << "equal..." << std::endl;

        // clean up
        delete pTestCRF;
        delete pCodebookRandomForest;

        examples.clean();
        delete pVecFeature;

        if (verboseStartEnd)
            std::cerr << "================== TestCodebookRandomForest::TestCodebookRandomForest done ===================== " << std::endl;
    }
    catch(std::exception &e)
    {
        std::cerr << "exception occured: " << e.what() << std::endl;
    }
}


#endif
