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

 \author Sascha Qualitz

 \date created at 2010/01/05

 \brief abstract class to derive a representation of one cell of a cellular automaton
 \sa CoordinateContainer, CellMonitor
 \since 3.0
 */

#ifndef ODEMX_CELL_INCLUDED
#define ODEMX_CELL_INCLUDED

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

/**
 * Macros
 */
#define FUNC(FUNC_NAME, CELLINDEX, RADIUS) FUNC_NAME(CELLINDEX, RADIUS)

//#include <odemx/base/continuous/Monitor.h> //edited by Sascha

namespace odemx {
	namespace base {

	//forward declaration
	//template <typename T>
	class CellVariablesContainer;

	class CellMonitor;

	struct typeOfNeighborhood;

		/** \class Cell

			\ingroup base

			\author Sascha Qualitz

			\brief Object for handling cellular automaton

			\sa CellMonitor, CellVariablesContainer
		 */
		class Cell {
		public:
			/** \brief Construction
			 */
			Cell(unsigned dimension);

			/// destruction
			virtual ~Cell();

			/** \brief calculates the transition function based on the own values and influences from the other cells
				\param time
					the set time limit for this instance, which is only valid if returned true
			 */
			virtual void transitionFunction(SimTime time);

			/**
			   \brief Calculates the cells in the neighborhood of one cell characterized by the baseIndex (the moore neighborhood is used)
         \f[
			  		  N_{(i,j)}=\{(k,l) \in L | |k-i| <= r and |l-j| <= r \}
          \f]
			   \param cellIndex
			   		the number of cell (range 0...(number of rows * number of columns -1))
			   \param neighborhoodType
			   		type of the neighborhood (von Neumann or moore)
			   \param radius
			   		radius of the neighborhood

			   	\note For now the possible values for neighborhoodType are MOORE and NEUMANN
			 */
			std::list<int> calculateNeighborhood(unsigned cellIndex, unsigned neighborhoodType, unsigned radius);

			/**
			   \brief Calculates the cells in the neighborhood of one cell characterized by the baseIndex (the moore neighborhood is used)
				 \f[
						 N_{(i,j)}=\{(k,l) \in L | |k-i| <= r and |l-j| <= r \}
				 \f]
			   \param cellIndex
					the number of cell (range 0...(number of rows * number of columns -1))
			   \param radius
			   		radius of the neighborhood
			 */
			std::list<int> calculateMooreNeighborhood(unsigned cellIndex, unsigned radius);

			/**
			   \brief Calculates the cells in the neighborhood of one cell characterized by the baseIndex (the von Neumann neighborhood is used)
				 \f[
						 N_{(i,j)}=\{(k,l) \in L | |k-i| + |l-j| <= r \}
				 \f]
			   \param cellIndex
					the number of cell (range 0...(number of rows * number of columns -1))
			   \param radius
			   		radius of the neighborhood
			 */
			std::list<int> calculateVonNeumannNeighborhood(unsigned cellIndex, unsigned radius);

			/**
			   \brief pushes the values for neighbor cells
			   \param variableIndex
					index of the variable (range 0...(dimension-1))
			   \param value
			   		value to set
			 */
			void pushValue(unsigned variableIndex, int value);

			/**
			   \brief gets the values from neighbor cells
			   \param variableIndex
					index of the variable (range 0...(dimension-1))
			 */
			std::vector<int> pullValue(unsigned variableIndex);

			/**
			   \brief Sets the cellIndex
			   \param cellIndex
					the number of cell (range 0...(number of rows * number of columns -1))
			 */
			void setCellIndex(unsigned cellIndex);

			/**
			   \brief Sets the VariableContainer.
			   \param container
				   Variable container used by CellMonitor for managing values
			 */
			//void setVariableContainer(CellVariablesContainer<int>* container);
			void setVariableContainer(CellVariablesContainer* container);

			/**
			 * \brief Get VariableContainer.
			 * \note To be deleted later.
			 */
			CellVariablesContainer* getVariableContainer();
			//CellVariablesContainer<int>* getVariableContainer();

			/**
				\brief Overrides the index operator to set the internal variable index_
				\param index
					index of the variable to get/set (range 0..(Dimension-1))
			*/
			Cell& operator [](const unsigned i);

			/** \brief set value of one variable
				\param cellIndex
					index of the cell to set \p value
				\param variableIndex
					index of the variable to set \p value
			 */
			void setValue(unsigned cellIndex, unsigned variableIndex, int value);

			/** \brief set value of one variable
				\param cellIndex
					index of the cell to set \p value

				\note variableIndex is set to 0
			 */
			void setValue(unsigned cellIndex, int value);

			/** \brief set monitor of the cellular automaton
				\param monitor
					monitor of the cellular automaton
			 */
			void setMonitor(CellMonitor* monitor);

		protected:

			/**
			 * Monitor, where the cell belongs to
			 */
			CellMonitor* monitor;

			/**
			 * values of the cell
			 */
			//CellVariablesContainer<int>* container;
			CellVariablesContainer* container;

			/*
			 * current cell index of the cell
			 */
			unsigned int cellIndex;

			/*
			 * baseindex of the cell
			 */
			unsigned int baseIndex;

			/*
			 * row number of the Cell
			 */
			unsigned int row;

			/*
			 * column number of the Cell
			 */
			unsigned int column;

			/*
			 * dimension is the number of values used by the transition function simultaneously
			 */
			unsigned int dimension;

			/**
			 * baseindiceslist of the cells in the neighborhood
			 */
			std::list<int> neighborhoodCellIndexList;
		};
	}
}
#endif
