//----------------------------------------------------------------------------
//	Copyright (C) 2002, 2004, 2007 Humboldt-Universitaet zu Berlin
//
//	This library 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 2.1 of the License, or (at your option) any later version.
//
//	This library 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 GNU
//	Lesser General Public License for more details.
//
//	You should have received a copy of the GNU Lesser General Public
//	License along with this library; if not, write to the Free Software
//	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//----------------------------------------------------------------------------
/**	\file GSLContainer.cpp

 \author Michael Fiedler

 \date created at 2009/01/02

 \brief Implementation of class GSLContainer

 \sa GSLContainer.h

 \since 3.0
 */

#include <odemx/base/continuous/GSLContainer.h>

#include <iostream>

using namespace odemx::base;
using namespace odemx::base::continuous;
using namespace std;

//------------------------------------------------------------------------construction/desctruction
GSLContainer::GSLContainer(int size)
:	size(size),
	values(new double[ size ]),
	variables(new double[ size ]),
	derivates(new double[ size ]),
	jacobi(new double[ size * size ]),
	dfdt(new double[ size ]),
	derivatesSet(false),
	jacobiSet(false)
	{}

GSLContainer::~GSLContainer() {
	delete[] this->values;
	delete[] this->variables;
	//only take care of own objects
	if (!derivatesSet) {
		delete[] this->derivates;
	}
	if (!jacobiSet) {
		delete[] this->dfdt;
		delete[] this->jacobi;
	}
}

//-----------------------------------------------------------------------adapt size
void GSLContainer::adaptSizeTo(int newSize) {
	int lv; //loop variable
	//values
	double* newValues = new double[ newSize ];
	for (lv = 0; lv < size && lv < newSize; lv++)
		newValues[ lv ] = this->values[ lv ];
	delete[] this->values;
	this->values = newValues;
	//variables
	newValues = new double[ newSize ];
	for (lv = 0; lv < size && lv < newSize; lv++)
		newValues[ lv ] = this->variables[ lv ];
	delete[] this->variables;
	this->variables = newValues;
	//derivates
	newValues = new double[ newSize ];
	for (lv = 0; lv < size && lv < newSize; lv++)
		newValues[ lv ] = this->derivates[ lv ];
	if (!derivatesSet) {
		delete[] this->derivates;
	}
	this->derivates = newValues;
	//dfdt
	newValues = new double[ newSize ];
	for (lv = 0; lv < size && lv < newSize; lv++)
		newValues[ lv ] = this->dfdt[ lv ];
	if (!jacobiSet) {
		delete[] this->dfdt;
	}
	this->dfdt = newValues;
	//jacobi
	double* newJacobi = new double[ newSize * newSize ];
	for (lv = 0; lv < newSize * newSize && lv < size * size; lv++) {
		newJacobi[ lv ] = this->jacobi[ lv ];
	}
	if (!jacobiSet) {
		delete[] this->jacobi;
	}
	this->jacobi = newJacobi;
	this->size = newSize;
	derivatesSet = false;
	jacobiSet = false;
}

//-----------------------------------------------------------------------------variables
void GSLContainer::nullVariables() {
	for (int lv = 0; lv < size; lv++)
		this->variables[ lv ] = 0;
}

void GSLContainer::setVariable(int num, double value) {
	this->variables[ num ] = value;
}

double GSLContainer::getVariable(int num) {
	return this->variables[ num ];
}

//-------------------------------------------------------------------------------values
void GSLContainer::nullValues() {
	for (int lv = 0; lv < size; lv++)
		this->values[ lv ] = 0;
}

void GSLContainer::copyVariablesToValues() {
	for (int lv = 0; lv < size; lv++)
		this->values[ lv ] = this->variables[ lv ];
}

void GSLContainer::copyValuesToVariables() {
	for (int lv = 0; lv < size; lv++)
		this->variables[ lv ] = this->values[ lv ];
}

void GSLContainer::setValue(int num, double value) {
	this->values[ num ] = value;
}

double GSLContainer::getValue(int num) {
	return this->values[ num ];
}

//----------------------------------------------------------------------------derivates
void GSLContainer::nullDerivatives() {
	for (int lv = 0; lv < size; lv++)
		this->derivates[ lv ] = 0;
}

void GSLContainer::setDerivative(int num, double value) {
	this->derivates[ num ] = value;
}

void GSLContainer::addToDerivative(int num, double value) {
	this->derivates[ num ] += value;
}

double GSLContainer::getDerivative(int num) {
	return this->derivates[ num ];
}

//------------------------------------------------------------------------------jacobi
void GSLContainer::nullJacobi() {
	for (int lv = 0; lv < size * size; lv++)
		this->jacobi[ lv ] = 0;
}

void GSLContainer::setJacobi(int i, int j, double value) {
	this->jacobi[ i * size + j ] = value;
}

void GSLContainer::addToJacobi(int i, int j, double value) {
	this->jacobi[ i * size + j ] += value;
}

double GSLContainer::getJacobi(int i, int j) {
	return this->jacobi[ i * size + j ];
}

//------------------------------------------------------------------------------DfDt
void GSLContainer::nullDfDt() {
	for (int lv = 0; lv < size; lv++)
		this->dfdt[ lv ] = 0;
}

void GSLContainer::setDfDt(int num, double value) {
	this->dfdt[ num ] = value;
}

void GSLContainer::addToDfDt(int num, double value) {
	this->dfdt[ num ] += value;
}

double GSLContainer::getDfDt(int num) {
	return this->dfdt[ num ];
}

//---------------------------------------------------------------------------others
void GSLContainer::setValues(const double y[]) {
	for (int lv = 0; lv < size; lv++)
		this->values[ lv ] = y[ lv ];
}

void GSLContainer::setDerivativesPointer(double f[]) {
	if (derivates && !derivatesSet)
		delete[] derivates;
	derivates = f;
	derivatesSet = true;
}

void GSLContainer::setJacobiPointer(double * dfdy, double dfdt[]) {
	if (jacobi && !jacobiSet)
		delete[] this->jacobi;
	jacobi = dfdy;
	if (this->dfdt && !jacobiSet)
		delete[] this->dfdt;
	this->dfdt = dfdt;
	jacobiSet = true;
	std::cout << "GSLContainer::setJacobiPointer(double * dfdy, double dfdt[])" << std::endl;
}
