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

 \author Sascha Qualitz

 \date created at 2010/01/05

 \brief Declaration of CellMonitor

 \since 3.0
 */

#ifndef ODEMX_CELLMONITOR_INCLUDED
#define ODEMX_CELLMONITOR_INCLUDED

#include <odemx/base/Process.h>
#include <odemx/base/cellular_automaton/CellVariablesContainer.h>
#include <odemx/base/continuous/VariableContainer.h>
#include <list>

#define MOORE 0
#define NEUMANN 1

namespace odemx {
	namespace base {

		//forward declaration

		//template <typename T>
		class CellVariablesContainer;

		class Cell;

		/** \class CellMonitor

			\ingroup base

			\brief A CellMonitor is used to control a CellularAutomaton.

			\sa CellularAutomaton, CellVariablesContainer, Process

			\since 3.0
		 */
		class CellMonitor : public Process {
		public:
			/** \brief Construction
				\param variablesArraySize
					initial size of data structs
				\param l
					label of this object
				\param o
					initial observer

				\note If on runtime data structs are to small they will automatically be enlarged at cost of speed
			 */
			//CellMonitor(int variablesInCount, int variablesOutCount, typename T, int cellCount, const Label& l, ProcessObserver* o = 0);
			CellMonitor(Simulation& sim, const data::Label& l, unsigned variablesInCount, unsigned variablesOutCount, unsigned cellRows, unsigned cellColumns, double timestep, Cell* cell, ProcessObserver* o = 0);

			/// destruction
			~CellMonitor();

			/** \brief calculating the evolution of the cellular automaton

				\note this will be called by Simulation
			 */
			int main();

			/** \name stop monitor

				These functions are to set the time limit for the main method to work or give a stop command.

				\note The monitor will only integrate, if there is a time limit set or processes to synchronize with or StateEvents to check.
				\note If there are only StateEvents to check be sure that at least one will evaluate at some point to true or you will have an infinite loop.

				@{
			 */
			/** \brief sets an time limit where the monitor will finish the main method
				\param time
					time to stop monitor
			 */
			void setTimeLimit(SimTime time);

			/** \brief returns the time limit
				\param time
					the set time limit for this instance, which is only valid if returned true
			 */
			bool getTimeLimit(SimTime* time);

			/** \brief forget a set time limit
			 */
			void removeTimeLimit();

			/** \brief forces the monitor to finish the main method when next scheduled
			 */
			void stop();
			//@}

			/** \brief Creates a cellular automaton with the specified row and column numbers
			 */
			void generateCellularAutomaton(unsigned rows, unsigned  columns);

			/** \brief Adds a cell to the monitor, so the monitor can start the calculations
			 * \param cell
			 * 		the user-defined cell-object
			*/
			void addCell(Cell* cell);

			/** \name internal Time

				To make ODEMx time representation independent of the time representation in the solver
				(numerical framework) the Monitor has an internal timing for conversion.
				This means the monitor has an internal reference time and a actual time,
				which is after the reference time.

				@{
			 */
			/** \brief sets internal reference time

				\note this means a change for the calculation and triggers a new initialization for the solver
			 */
			void setInternalTime(SimTime time);

			/** \brief gets internal reference time
			 */
			SimTime getInternalTime();

			/** \brief gets actual time of Monitor
			 */
			SimTime getActualInternalTime();

			/** \brief sets internal reference time to actual time

				sets internal reference time in a way that actual time and internal
				reference time are equal for this monitor at call of this function

				\note this means a change for the calculation and triggers a new initialization for the solver
			 */
			void adaptInternalTime();
			//@}

			/** \brief sets the monitor changed

				If the continuous system has a discrete change, the solver has to be newly initialized
				to guarantee consistency. So it causes solver->init() to be called before next calculation.

				\note As long a user access only objects by supplied functions there is no need to call this.
			 */
			void setChanged();

			/**
			 * returns the size of the used arrays
			 */
			unsigned getArraySize();

			/**
			 * temp function for primtimg values
			 */
			int* getValues();

			/** \brief returns the number of rows that belongs to the cellular automaton
			*/
			unsigned getRowCount();

			/** \brief returns the number of columns that belongs to the cellular automaton
			*/
			unsigned getColumnCount();

			/** \brief this struct saves the settings for the neighborhood to look up
				\param
					radius of the neighborhood (1,....)
				\param neighborhoodType
			   		type of the neighborhood (von Neumann or moore)

			   	\note For now the possible values for neighborhoodType are MOORE and NEUMANN
			 */
			struct neighborhoodSettings
			{
				unsigned neighborhoodType;
				unsigned radius;
			} typeOfNeighborhood;

		protected:

			/** size of the variables in the cells
			 */
			unsigned variablesInCount;

			/** size of the variables in the cells
			 */
			unsigned variablesOutCount;

			/** number of cells in the cellular automaton
			 */
			unsigned cellCount;

			/** CellVariablesContainer used by CellMonitor for managing variables of the cells
			 */
			//CellVariablesContainer<int>* cellVariablesContainer;
			CellVariablesContainer* cellVariablesContainer;

			/** the user-defined cell-object
			 */
			Cell* cell;

			/** List of all cell indices managed by CellMonitor
			 */
			std::list<unsigned> cellIndexList;

			/** Size of every timestep
			 */
			double timestep;

			/** an internal reference time value
			 */
			SimTime internalTime;

			/** the time limit if set
			 */
			SimTime timeLimit;

			/** indicates if a time limit is set
			 */
			bool timeLimitSet;

			/** indicates if stop() was called
			 */
			bool hasToStop;

			/** actual time of Monitor is internalTime + diffTime
			 */
			double diffTime;

			/** \brief integration to \p time

				\note internal function
			 */
			void integrateUntil(SimTime time);

			/** \brief integration till StateEvent
				\note internal function
			 */
			void integrate();

			/** Search the time when a StateEvent occurs for when is known condition is false
			 at internalTime + old_diffTime with values old_variable_values for all
			 StateEvents and in the actual state there is a StateEvent with condition true
			 of the Monitor and then triggers the event
			 */
			void searchStateEvent(double old_diffTime, double *old_variable_values);

			/** evaluates all equations of all continuous processes as one function
			 as sum of partial functions at time internalTime + time
			 */
			void evalF(double time);

			/** evaluates all jacobian of all continuous processes as one matrix
			 as sum of partial matrices at time internalTime + time
			 */
			void evalJacobian(double time);

		};

	}
}

#endif

