//----------------------------------------------------------------------------
//	Copyright (C) 2002, 2003, 2004 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.h

 \author Michael Fiedler

 \date created at 2008/11/21

 \brief Declaration of GSLContainer

 \since 3.0
 */

#ifndef ODEMX_GSLCONTAINER_INCLUDED
#define ODEMX_GSLCONTAINER_INCLUDED

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

namespace odemx {
	namespace base {
		namespace continuous {

			//forward declarations
			class Monitor; //really useful? Never used!

			class Continuous;

			class VariableContainer;

			class ODEObject;

			class ODESolver;

			/** \class GSLContainer

				\ingroup base

				\brief Implementation of VariableContainer for GNU Scientific Library

				\sa VariableContainer

				\since 3.0
			 */
			class GSLContainer : public VariableContainer {
			public:
				/** \brief Constructor
					\param size
						initial size of Container
				 */
				GSLContainer(int size);

				/// Destructor
				~GSLContainer();

				/** \brief copy the first container size values of \p y to Values

					\note y has to have at least container size elements or the result is undefined
				 */
				void setValues(const double y[]);

				/** \brief exchange internal array for derivatives by \p f

					\note all further changes will be done on \p f
				 */
				void setDerivativesPointer(double f[]);

				/** \brief exchange internal arrays for jacobian by \p dfdy and \p dfdt

					\note all further changes will be done on \p dfdy and \p dfdt
				 */
				void setJacobiPointer(double * dfdy, double dfdt[]);

				/** \brief adapt the numbers of variables which can be stored in the container
					\param newSize
						new size of container

					\note old content is preserved as long it fits in \p newSize, everything over will be truncated
				 */
				virtual void adaptSizeTo(int newSize);

				/** \name Variables

				 variable are for holding values while derivatives, jacobi and DfDt are for calculating

				 @{
				 */
				/** \brief set all variables to 0.0
				 */
				virtual void nullVariables();

				/** \brief set value of one variable
				 \param num
				 index of variable to set \p value
				 */
				virtual void setVariable(int num, double value);

				/** \brief get value of one variable
				 \param num
				 index of variable to get
				 */
				virtual double getVariable(int num);
				//@}

				/** \name temporary values

				 these values are used will calculating intermediate steps

				 @{
				 */
				/** \brief set all temporary variables to 0.0
				 */
				virtual void nullValues();

				/** \brief set values of temporary variables to these ones of corresponding variables
				 */
				virtual void copyVariablesToValues();

				/** \brief set values of variables to these ones of corresponding temporary variables
				 */
				virtual void copyValuesToVariables();

				/** \brief set value of one temporary variable
				 \param num
				 index of variable to set \p value
				 */
				virtual void setValue(int num, double value);

				/** \brief get value of one temporary variable
				 \param num
				 index of variable to get
				 */
				virtual double getValue(int num);
				//@}

				/** \name derivatives

				 @{
				 */
				/** \brief set all values from the derivatives-array to 0.0
				 */
				virtual void nullDerivatives();

				/** \brief set one value of the derivatives-array, whereas num is the index
				 \param num
				 index of variable to set \p value
				 */
				virtual void setDerivative(int num, double value);

				/** \brief add to value of one derivatives-array variable, whereas num is the index
				 \param num
				 index of variable to add \p value
				 */
				virtual void addToDerivative(int num, double value);

				/** \brief get value from the derivatives-array at the index num
				 \param num
				 index of variable to get
				 */
				virtual double getDerivative(int num);
				//@}

				/** \name jacobi

				 @{
				 */
				/** \brief set all jacobian values to 0.0
				 */
				virtual void nullJacobi();

				/** \brief set value of one jacobian variable

				 set variable(\p i ,\p j ) to \p value
				 */
				virtual void setJacobi(int i, int j, double value);

				/**  \brief set value of one jacobian variable

				 add \p value to variable(\p i ,\p j )
				 */
				virtual void addToJacobi(int i, int j, double value);

				/** \brief get value of one jacobian variable

				 \return variable(\p i ,\p j )
				 */
				virtual double getJacobi(int i, int j);
				//@}

				/** \name DfDt

				 right hand side derived by time

				 @{
				 */
				/** \brief set all derived components to 0.0
				 */
				virtual void nullDfDt();

				/** \brief set value of one derived component
				 \param num
				 index of derived component to set \p value
				 */
				virtual void setDfDt(int num, double value);

				/** \brief add to value of one derived component
				 \param num
				 index of derived component to add \p value
				 */
				virtual void addToDfDt(int num, double value);

				/** \brief get value of one derived component
				 \param num
				 index of derived component to get
				 */
				virtual double getDfDt(int num);
				//@}

			private:
				int size;
				double* values;
				double* variables;
				double* derivates;
				double* jacobi;
				double* dfdt;

				//saves if pointer was set to an array from external
				bool derivatesSet;
				bool jacobiSet;

				friend class GSLSolver;
			};
		}
	}
}
#endif
