#include "PartwiseLinFunc.h"

PartwiseLinFunc::PartwiseLinFunc(mexCellItem * cell)
{
	if (!(cell->checkStructFieldExists("breaks") && cell->checkStructFieldExists("coefs")))
		mexErrMsgTxt("Partwise func creation failed.");

	//This code creates some new Mex Cells:
	mexCellItem * breaks = cell->getStructField("breaks");
	const int breakAmount = breaks->getElemCount();
	mexCellItem * coefs = cell->getStructField("coefs");


	funcProps.parts = breakAmount;
	funcProps.breaks = new double[breakAmount];
	funcProps.funcs = new LinFunc[breakAmount - 1];

	for (int i = 0; i < breakAmount; i++)
	{
		funcProps.breaks[i] = breaks->getDouble(i);
		if (i == breakAmount - 1) continue;
		funcProps.funcs[i].a0 = coefs->getDouble(i, 0);
		funcProps.funcs[i].a1 = coefs->getDouble(i, 1);
	}

	funcProps.isSet = true;

	//This code clears the newly created mex cells.
	delete(breaks);
	delete(coefs);
}

double PartwiseLinFunc::Evaluate(double X, int isLogged)
{
	int lastUpper = 1;
	int lastLower = 0;
	if (!funcProps.isSet)
		mexErrMsgTxt("Attempted evaluation before setting the function.");

	int funcIndex = 0;
	
	if (X > funcProps.breaks[0])
	{
		for (int upper = 1, lower = 0; upper < funcProps.parts && funcProps.breaks[lower] < X; upper++, lower++)
		{
			funcIndex = lower;
			lastLower = lower;
			lastUpper = upper;
		}
	}
	
	double distFromLow = X - funcProps.breaks[lastLower];
	double result = funcProps.funcs[funcIndex].a1 + funcProps.funcs[funcIndex].a0*distFromLow;
	
	if (isLogged)
	{
		mexPrintf("EV/EF(%i,%i) [lower: %f, X: %f upper: %f]: %f = %f + %f * %f\n", 
			lastLower+1, lastUpper+1, //To MATLAB index
			funcProps.breaks[lastLower], X, funcProps.breaks[lastUpper],
			result, funcProps.funcs[funcIndex].a1, funcProps.funcs[funcIndex].a0, distFromLow);
	}

	return result;
}

PartwiseLinFunc::~PartwiseLinFunc()
{
	if (funcProps.breaks != NULL)
		delete(funcProps.breaks);
	if (funcProps.funcs != NULL)
		delete(funcProps.funcs);
}
