#include <list>
#include <iostream>
#include <cstdlib>
#include <ctime>

#include "LinearAlgebra.h"
#include "DataEngine.h"
#include "drand48.h"

using namespace std;
using namespace numeric;

namespace database {

DataEngine::DataEngine(const DataBase & _dataBase,
				               unsigned _index,
				               unsigned K,
				               unsigned sizeOfStorage)
{
	index=_index;
	dataBase=&_dataBase;
	dimension = dataBase->getDimension();
	storage = new numeric::RegressionStorage(K,sizeOfStorage);
	srand48(time(NULL));
}

void DataEngine::computeRegression(list<unsigned> listObs, unsigned K) const
{
	list<unsigned>::iterator iter=listObs.begin();
	Matrix u( listObs.size(), dimension);
	Vector y( listObs.size());
	unsigned n = 0;
	for(;iter!=listObs.end();++iter)
	{
		const double * observation = dataBase->getObservation(*iter);
		unsigned i=0;
		for(i=0;i<index;++i)
		{
      u(n,i) = observation[i];
		}

    u(n,index) = 1.0;
		y(n) = observation[index];

		for(i=index+1;i<dimension;++i)
		{
    	u(n,i) = observation[i];
		}
		++n;
	}

	Matrix ut = u.transpose();
	Vector c = ut*y;
	Matrix a = ut*u;
	Matrix q = decqr(a);
	c = q.transpose()*c;
	Vector b = solveUpperLinSys(a,c,1e-8);
	storage->store(b,K);
}

double DataEngine::error(unsigned obsId, unsigned K) const
{
	const double * observation = dataBase->getObservation(obsId);
	Vector b = storage->getLastHyperplan(K);
	double error=0.0;
	unsigned i=0;
	for(i=0;i<index;++i)
	{
		error-=observation[i]*b(i);
	}

	error += observation[index];

	for(i=index+1;i<dimension;++i)
	{
		error-=observation[i]*b(i);
	}
	return error*error;
}

double DataEngine::rand() const
{
	return drand48();
}

int DataEngine::rand(unsigned inf, unsigned sup) const
{
	return int( inf + (sup-inf)*DataEngine::rand());
}


}
