/*
    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 "utils.h"

std::vector<double> initWithZeros(size_t len)
{
	std::vector<double> ret;
	for (size_t i=0; i<len; i++)
	{
		ret.push_back(0);
	}
	return ret;
}

Matrices::SuperMatrixPtr buildSuperMatrix(std::vector<std::vector<double> > rows)
{
	size_t numOfRows=rows.size();
	size_t numOfColumns = 0;
	if(numOfRows>0)
		numOfColumns=rows[0].size();

	std::vector<double> row_nz = initWithZeros(numOfRows);
	std::vector<double> row_tf = initWithZeros(numOfRows);

	std::vector<double> column_nz = initWithZeros(numOfColumns);
	std::vector<double> column_tf = initWithZeros(numOfColumns);

	Matrices::CCSMatrixPtr ccsM(new Matrices::CCSMatrix("ccs",numOfRows,numOfColumns));

	Matrices::CRSMatrixPtr crsM(new Matrices::CRSMatrix("crs",numOfRows,numOfColumns));

	std::vector<std::vector<double> > columns;
	for(size_t i=0;i<numOfRows;i++)
	{
		crsM->SetRow(rows[i],i);
		ccsM->SetRow(rows[i],i);
	}
	Matrices::FeatureVectorPtr columnFeatures(new Matrices::FeatureVector());
	Matrices::FeatureVectorPtr rowFeatures(new Matrices::FeatureVector());
	for(size_t i=0; i<rows.size();i++)
	{
		Matrices::CompressedVectorPtr row(crsM->GetCompressedRow(i));
		size_t tf = size_t(Measures::CountVectorSum(row));
		size_t nz = row->GetValues()->size();
		rowFeatures->push_back(Matrices::Feature("foobar",nz, tf,42,Measures::CountVectorEntropy(row)));
	}

	for(size_t i=0; i<ccsM->NumberOfColumns();i++)
	{
		Matrices::CompressedVectorPtr column(ccsM->GetCompressedColumn(i));//UWAGA! To nie sa cechy kolumn, a wierszy - do poprawienia
		size_t tf = size_t(Measures::CountVectorSum(column));
		size_t nz = column->GetValues()->size();
		columnFeatures->push_back(Matrices::Feature("hnngh",nz,tf,42,Measures::CountVectorEntropy(column)));
	}
	std::map<size_t,std::string> boundaries;
	boundaries[columns.size()-1] = "foobar";
	Matrices::SuperMatrixPtr superM(new Matrices::SuperMatrix("supermatrix",ccsM,crsM,rowFeatures,columnFeatures,1000,"opis",boundaries));
	superM->SyncCRSToCCS();
	return superM;
}

void matrixCompareCRS(Matrices::SuperMatrixPtr m1, Matrices::SuperMatrixPtr m2, double precision)
{
	BOOST_CHECK(m1->NumberOfRows() == m2->NumberOfRows() && m1->NumberOfColumns() == m2->NumberOfColumns());
	for (size_t i = 0; i<m1->NumberOfRows(); i++)
	{
		Matrices::CompressedVectorPtr row1 = m1->GetCRS()->GetCompressedRow(i);
		Matrices::CompressedVectorPtr row2 = m2->GetCRS()->GetCompressedRow(i);
		for (size_t j = 0; j<m1->NumberOfColumns(); j++)
		{
			BOOST_CHECK_CLOSE((*row1)[j],(*row2)[j],precision);
		}
	}
}

void matrixCompareCCS(Matrices::SuperMatrixPtr m1, Matrices::SuperMatrixPtr m2, double precision)
{
	BOOST_CHECK(m1->NumberOfRows() == m2->NumberOfRows() && m1->NumberOfColumns() == m2->NumberOfColumns());
	for (size_t i = 0; i<m1->NumberOfColumns(); i++)
	{
		Matrices::CompressedVectorPtr row1 = m1->GetCCS()->GetCompressedColumn(i);
		Matrices::CompressedVectorPtr row2 = m2->GetCCS()->GetCompressedColumn(i);
		for (size_t j = 0; j<m1->NumberOfRows(); j++)
		{
			BOOST_CHECK_CLOSE((*row1)[j],(*row2)[j],precision);
		}
	}
}

template <class C> std::vector<C> initVector(C e1, C e2, C e3, C e4, C e5, C e6, C e7, C e8, C e9)
{
	std::vector<C> retvector;
	retvector.push_back(e1);
	retvector.push_back(e2);
	retvector.push_back(e3);
	retvector.push_back(e4);
	retvector.push_back(e5);
	retvector.push_back(e6);
	retvector.push_back(e7);
	retvector.push_back(e8);
	retvector.push_back(e9);
	return retvector;
}

template <class C> std::vector<C> initVector(C e1, C e2, C e3, C e4, C e5, C e6, C e7)
{
	std::vector<C> retvector;
	retvector.push_back(e1);
	retvector.push_back(e2);
	retvector.push_back(e3);
	retvector.push_back(e4);
	retvector.push_back(e5);
	retvector.push_back(e6);
	retvector.push_back(e7);
	return retvector;
}

Matrices::SuperMatrixPtr getTestMatrix()
{
	std::vector<std::vector<double> > rows;
	rows.push_back(initVector(1.,0.,0.,1.,0.,0.,0.,0.,0.)); //human
	rows.push_back(initVector(1.,0.,1.,0.,0.,0.,0.,0.,0.)); //interface
	rows.push_back(initVector(1.,1.,0.,0.,0.,0.,0.,0.,0.)); //computer
	rows.push_back(initVector(0.,1.,1.,0.,1.,0.,0.,0.,0.)); //user
	rows.push_back(initVector(0.,1.,1.,2.,0.,0.,0.,0.,0.)); //system
	rows.push_back(initVector(0.,1.,0.,0.,1.,0.,0.,0.,0.)); //response
	rows.push_back(initVector(0.,1.,0.,0.,1.,0.,0.,0.,0.)); //time
	rows.push_back(initVector(0.,0.,1.,1.,0.,0.,0.,0.,0.)); //EPS
	rows.push_back(initVector(0.,1.,0.,0.,0.,0.,0.,0.,1.)); //survey
	rows.push_back(initVector(0.,0.,0.,0.,0.,1.,1.,1.,0.)); //trees
	rows.push_back(initVector(0.,0.,0.,0.,0.,0.,1.,1.,1.)); //graph
	rows.push_back(initVector(0.,0.,0.,0.,0.,0.,0.,1.,1.)); //minors
	return buildSuperMatrix(rows);
}

Matrices::SuperMatrixPtr getTestMatrixFilteredRow()
{
	std::vector<std::vector<double> > rows;
	rows.push_back(initVector(1.,0.,0.,1.,0.,0.,0.,0.,0.)); //human
	//rows.push_back(initVector(1.,0.,1.,0.,0.,0.,0.,0.,0.)); //interface
	rows.push_back(initVector(1.,1.,0.,0.,0.,0.,0.,0.,0.)); //computer
	rows.push_back(initVector(0.,1.,1.,0.,1.,0.,0.,0.,0.)); //user
	rows.push_back(initVector(0.,1.,1.,2.,0.,0.,0.,0.,0.)); //system
	rows.push_back(initVector(0.,1.,0.,0.,1.,0.,0.,0.,0.)); //response
	rows.push_back(initVector(0.,1.,0.,0.,1.,0.,0.,0.,0.)); //time
	rows.push_back(initVector(0.,0.,1.,1.,0.,0.,0.,0.,0.)); //EPS
	rows.push_back(initVector(0.,1.,0.,0.,0.,0.,0.,0.,1.)); //survey
	rows.push_back(initVector(0.,0.,0.,0.,0.,1.,1.,1.,0.)); //trees
	//rows.push_back(initVector(0.,0.,0.,0.,0.,0.,1.,1.,1.)); //graph
	rows.push_back(initVector(0.,0.,0.,0.,0.,0.,0.,1.,1.)); //minors
	return buildSuperMatrix(rows);
}

Matrices::SuperMatrixPtr getTestMatrixFilteredCol()
{
	std::vector<std::vector<double> > rows;
	rows.push_back(initVector(1.,0.,1.,0.,0.,0.,0.)); //human
	rows.push_back(initVector(1.,1.,0.,0.,0.,0.,0.)); //interface
	rows.push_back(initVector(1.,0.,0.,0.,0.,0.,0.)); //computer
	rows.push_back(initVector(0.,1.,0.,1.,0.,0.,0.)); //user
	rows.push_back(initVector(0.,1.,2.,0.,0.,0.,0.)); //system
	rows.push_back(initVector(0.,0.,0.,1.,0.,0.,0.)); //response
	rows.push_back(initVector(0.,0.,0.,1.,0.,0.,0.)); //time
	rows.push_back(initVector(0.,1.,1.,0.,0.,0.,0.)); //EPS
	rows.push_back(initVector(0.,0.,0.,0.,0.,0.,0.)); //survey
	rows.push_back(initVector(0.,0.,0.,0.,1.,1.,1.)); //trees
	rows.push_back(initVector(0.,0.,0.,0.,0.,1.,1.)); //graph
	rows.push_back(initVector(0.,0.,0.,0.,0.,0.,1.)); //minors
	return buildSuperMatrix(rows);
}

std::set<size_t> getTestIndices(Matrices::SuperMatrixPtr m)
{
	std::set<size_t> fullIndices;
	for (size_t i = 0; i<m->NumberOfColumns(); i++)
	{
		fullIndices.insert(i);
	}
	return fullIndices;
}

std::string* getTupleLines()
{
	size_t size =26;
	std::string *line = new std::string[size];

	line[0]="subst:okres;adjp;subst:demografia;1";
	line[1]="subst:2d;coord;adj:pierwotny;1";
	line[2]="subst:31poseł;coord;pact:wstrzymywać;1";
	line[3]="subst:36l;coord;pact:stanowić;1";
	line[4]="subst:3r;adjp;pact:stanowić;1";
	line[5]="subst:40097gospodarstwo;coord;adj:pomocniczy;1";
	line[6]="subst:403wynagrodzenie;coord;adj:osobowy;1";
	line[7]="subst:41poseł;coord;pact:wstrzymywać;2";
	line[8]="subst:43d;coord;adj:który;1";
	line[9]="subst:4l;adjp;ppas:skreślić;1";
	line[10]="subst:5l;coord;pact:stanowić;1";
	line[11]="subst:41poseł;coord;pact:głosować;1";
	line[12]="subst:5l;coord;pact:stanowić;1";
	line[13]="subst:aborcja;coord;adj:nieograniczony;1";
	line[14]="subst:aborcja;coord;adj:sam;3";
	line[15]="subst:aborcja;coord;adj:ów;1";
	line[16]="subst:abraham;coord;adj:wielki;1";
	line[17]="subst:2ba;coord;ppas:ogłosić;1";
	line[18]="subst:kolumna;adjp;subst:pgr;1";
	line[19]="subst:2ba;coord;ppas:ogłosić;1";
	line[20]="subst:pgr;adjp;subst:kolumna;1";
	line[21]="subst:implementacja;adjp;subst:system;1";
	line[22]="subst:metoda;adjp;subst:lonworks;1";
	line[23]="subst:stan;adjp;subst:represja;1";
	line[24]="subst:demografia;adjp;subst:okres;1";

	return line;
}
