/*
    Copyright (C) 2012 Bartosz Broda, Jacek Bochenek, Łukasz Biłeńkij, 
    Damian Jaworski, Wojciech Mazur, Dominik Piasecki, Maciej Piasecki, 
    Radosław Ramocki
    
    This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option)
any later version.

    This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. 

    See the LICENSE and COPYING files for more details.
*/

#include "Evaluator.h"
#include "Options.h"
#include <iomanip>

using namespace std;
using namespace smartcomparator::compare;

Matrices::SuperMatrixPtr ReadMatrixSilent(const string& matrix_dir, const string& matrix_name)
{
	if (matrix_dir == "" || matrix_name == "")
		throw runtime_error("Matrix dir and matrix name required");
	streambuf* oldbuff = cout.rdbuf();
	stringstream s;
	cout.rdbuf(s.rdbuf());
	Matrices::SuperMatrixPtr matrix = Matrices::IO::LoadSuperMatrix(matrix_dir, matrix_name, false, true);
	cout.rdbuf(oldbuff);
	return matrix;
}

CompareFunctionPtr CreateFunctionSilent(const string& sim_function, Matrices::SuperMatrixPtr matrix)
{
	if (sim_function == "")
		throw runtime_error("Sim function required");
	streambuf* oldbuff = cout.rdbuf();
	stringstream s;
	cout.rdbuf(s.rdbuf());
	CompareFunctionPtr cmp_fun = smartcomparator::compare::FunctionFactory::CreateFunction(sim_function, matrix);
	cout.rdbuf(oldbuff);
	return cmp_fun;
}

int main(int argc, char **argv)
{
	Matrices::init_logging();

	using namespace evaluator;	

	Options opt(argc, argv);

	Params param = opt.GetParams();

	Evaluator ev;

	ev.InitEvaluator(param.cluto_file, param.class_file, param.silent);

	if (param.method == "bcubed")
	{
		double precision, recall;
		double bcubed = ev.CountBCubed(0.5, precision, recall);
		cout << bcubed << endl;
	}
	else if (param.method == "purity")
	{
		double purity = ev.CountPurity();
		cout << fixed << setprecision(4) << purity << endl;
	}
	else if (param.method == "nmi")
	{
		double nmi = ev.CountNMI();
		cout << fixed << setprecision(3) << nmi << endl;
	}
	else if (param.method == "rand")
	{
		double ri = ev.CountRandIndex();
		cout << fixed << setprecision(3) << ri << endl;
	}
	else if (param.method == "fmeas1")
	{
		double fmeasure1 = ev.CountFmeasure(1);
		cout << fixed << setprecision(4) << fmeasure1 << endl;
	}
	else if (param.method == "fmeas5")
	{
		double fmeasure5 = ev.CountFmeasure(5);
		cout << fixed << setprecision(4) << fmeasure5 << endl;
	}
	else if (param.method == "dunn")
	{
		Matrices::SuperMatrixPtr matrix = ReadMatrixSilent(param.matrix_dir, param.matrix_name);
		CompareFunctionPtr cmp_fun = CreateFunctionSilent(param.sim_function, matrix);
		ev.SetCompareFunction(cmp_fun);
		if (param.sim_matrix_dir != "" && param.sim_matrix_name != "")
		{
			Matrices::SuperMatrixPtr sim_matrix = ReadMatrixSilent(param.sim_matrix_dir, param.sim_matrix_name);
			ev.SetSimilarityMatrix(sim_matrix);
		}
		double dunn = ev.CountDunnIndex(cmp_fun, false);
		cout << dunn << endl;
	}
	else if (param.method == "dunn2")
	{
		Matrices::SuperMatrixPtr matrix = ReadMatrixSilent(param.matrix_dir, param.matrix_name);
		CompareFunctionPtr cmp_fun = CreateFunctionSilent(param.sim_function, matrix);
		ev.SetCompareFunction(cmp_fun);
		if (param.sim_matrix_dir != "" && param.sim_matrix_name != "")
		{
			Matrices::SuperMatrixPtr sim_matrix = ReadMatrixSilent(param.sim_matrix_dir, param.sim_matrix_name);
			ev.SetSimilarityMatrix(sim_matrix);
		}
		double dunn = ev.CountDunnIndex(cmp_fun, true);
		cout << dunn << endl;
	}
	else if (param.method == "density")
	{
		Matrices::SuperMatrixPtr matrix = ReadMatrixSilent(param.matrix_dir, param.matrix_name);
		CompareFunctionPtr cmp_fun = CreateFunctionSilent(param.sim_function, matrix);
		ev.SetCompareFunction(cmp_fun);
		if (param.sim_matrix_dir != "" && param.sim_matrix_name != "")
		{
			Matrices::SuperMatrixPtr sim_matrix = ReadMatrixSilent(param.sim_matrix_dir, param.sim_matrix_name);
			ev.SetSimilarityMatrix(sim_matrix);
		}
		double density = ev.CountExpectedDensity();
		cout << density << endl;
	}
	else
		throw std::runtime_error("Unknown evaluation method");


//	cout << "Clustered: " << ev.GetClusteredRows() << "/" << ev.GetRows() << endl;
//	cout << "Clusters found: " << ev.GetFoundClusters() << endl;

	return 0;
}
