//----------------------------------------------------------------------------
//	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 ODEObject.h

 \author Michael Fiedler

 \date created at 2008/11/21

 \brief abstract class to derive a representation of an ordinary differential equation
 \sa Continuous, Monitor, StateEvent
 \since 3.0
 */

#ifndef ODEMX_ODEOBJECT_INCLUDED
#define ODEMX_ODEOBJECT_INCLUDED

#include <odemx/base/SimTime.h>
#include <string>
#include <exception>
#include <vector>
#include <list>

namespace odemx {
	namespace base {
		namespace continuous {

			class Monitor; //TODO: really useful?

			class Continuous;

			class DerivatesElement;

			class JacobiElement;

			class DfDtElement;

			/** Exception for methods which fails, because there is missingObject assigned for this object
			 */
			class NotAssignedException : public std::exception {
			public:
				/// Constructor
				NotAssignedException(const char* missingObject, const char* object);

				/// Destructor
				~NotAssignedException() throw();

				/// give message for exception
				const char* what() const throw();

			private:
				std::string msg;	//saves the Exception message
			};

			/** \class ODEObject

				\ingroup base

				\author Michael Fiedler

				\brief Object for handling an equation

				To describe a ordinary differential equations the user have to implement derivates and jacobi.

				\note In such implementations the user has to use getValueForDerivative to access the variables of
				the corresponding Continuous instance.
			 */
			class ODEObject {
			public:
				/** \brief Construction
				 */
				ODEObject();

				/// destruction
				virtual ~ODEObject();

				/** \name handle corresponding Continuous instance

					These are the functions to set/get the Continuous instance for this equation to work on.
					If the user wants to have an equation which works on more than one Continuous instance he
					has to extend this functionality for the extra instances.

					@{
				 */
				/** \brief Adds this ODEObject-instance to an Continuous-Object
					\param continuous
						pointer to Continuous instance where this equation will be added
				 */
				void setContinuous(Continuous *continuous); //TODO: is never used!

				/** \brief gives the corresponding Continuous instance
					\note if no corresponding Continuous instance is set, the result will be NULL
				 */
				Continuous* getContinuous();
				//@}

				/** \brief implementation of equation in form y' = f(y)

				 the following example is the default implementation:

				 v'[0] = v[1]

				 v'[1] = v[0]

				 in code:

				 continuous->setDerivative(0, continuous->getValueForDerivative(1));

				 continuous->setDerivative(1, continuous->getValueForDerivative(0));

				 //new representation
				 DerivatesElement rate(continuous);

				 DerivatesElement state(continuous);

				 rate[0] = state[1];

				 rate[1] = -1 * state[0];
				 */
				virtual void derivates(SimTime time);

				/** \brief derivates of implemented equation in form y' = f(y)

				 this example is the default implementation (fßx means derive f by x):

				 f[0]ßv[0] = 0

				 f[0]ßv[1] = 1

				 f[1]ßv[0] = 1

				 f[1]ßv[1] = 0

				 f[0]ßt = 0

				 f[1]ßt = 1

				 in code:

				 continuous->setJacobi(0, 0, 0);

				 continuous->setJacobi(0, 1, 1);

				 continuous->setJacobi(1, 0, 1);

				 continuous->setJacobi(1, 1, 0);

				 continuous->setDfDt(0, 0);

				 continuous->setDfDt(1, 0);

				 //new representation
				 JacobiElement jacobi(continuous);

				 DfDtElement dfdt(continuous);

				 jacobi(0,0) = 0;

				 jacobi(0,1) = 1;

				 jacobi(1,0) = -1;

				 jacobi(1,1) = 0;

				 dfdt[0] = 0;

				 dfdt[1] = 0;
				 */
				virtual void jacobi(SimTime time);

			protected:
				/** stores the Continuous-Object where equation belongs to
				 */
				Continuous *continuous;

			protected:

				friend class Continuous;

			};
		}
	}
}
#endif
