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

	\author Sascha Qualitz

	\date created at 2010/01/05

	\brief Implementation of class CellMonitor

	\sa CellMonitor.h

	\since 3.0
*/

#include <odemx/base/cellular_automaton/CellMonitor.h>
#include <odemx/base/Scheduler.h>
#include <odemx/base/Simulation.h>
#include <typeinfo>
#include <odemx/base/cellular_automaton/Cell.h>

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

//----------------------------------------------------------------------------------construction/destruction
//CellMonitor::CellMonitor(int variablesInCount, int variablesOutCount, typename T, int cellCount, const Label& l, ProcessObserver* o)
CellMonitor::CellMonitor(Simulation& sim, const data::Label& l, unsigned variablesInCount, unsigned variablesOutCount, unsigned cellRows, unsigned cellColumns, double timestep, Cell* cell, ProcessObserver* o)
:	Process(sim, l, o),
	variablesInCount(variablesInCount),
	variablesOutCount(variablesOutCount),
	cellCount(cellColumns*cellRows),
	cell(cell),
	timestep(timestep),
	internalTime(0),
	timeLimit(0),
	timeLimitSet(false),
	hasToStop(false),
	diffTime(0.0)
{
	typeOfNeighborhood.neighborhoodType = MOORE;
	typeOfNeighborhood.radius = 1;
	//cellVariablesContainer = new CellVariablesContainer<int>(cellRows, cellColumns, variablesInCount);
	cellVariablesContainer = new CellVariablesContainer(cellRows, cellColumns, variablesInCount);
	generateCellularAutomaton(cellRows,cellColumns);
	cell->setVariableContainer(cellVariablesContainer);
	cell->setMonitor(this);
}

CellMonitor::~CellMonitor(){
	if (cellVariablesContainer) {
		delete cellVariablesContainer;
	}
}

//------------------------------------------------------------------------------stop CellMonitor
void CellMonitor::setTimeLimit(SimTime time) {
	//cout << "CellMonitor::setTimeLimit(*continuousList.begin())->equations.size()" << (*continuousList.begin())->equations.size() << endl;
	timeLimitSet = true;
	timeLimit = time;
}

bool CellMonitor::getTimeLimit(SimTime* time) {
	if (timeLimitSet) {
		*time = timeLimit;
		return true;
	} else {
		return false;
	}
}

void CellMonitor::removeTimeLimit() {
	timeLimitSet = false;
}

void CellMonitor::stop() {
	hasToStop = true;
}

//-----------------------------------------------------------generate cellular automaton
void CellMonitor::generateCellularAutomaton(unsigned rows, unsigned  columns){

	//generate list of base indices
	for(int i = 0; i < rows*columns; i++){
		cellIndexList.push_back(i);
	}

	/*kann weg!!!!for (std::list<int>::iterator iter = cellIndexList.begin(); iter != cellIndexList.end(); iter++) {
		cout << "cellIndices: " << cellIndexList.size() << endl;
		cout << *iter << endl;
	}*/
}

//----------------------------------------------------------- temp function for printing values
int* CellMonitor::getValues() {
	return this->cellVariablesContainer->getOutputValues();
}

void CellMonitor::addCell(Cell* cell) {
	this->cell = cell;
}

//-----------------------------------------------------------------------------manage internal time
void CellMonitor::setInternalTime(SimTime time) {

}

SimTime CellMonitor::getInternalTime() {
	return internalTime;
}

SimTime CellMonitor::getActualInternalTime() {
	return (SimTime)(internalTime + diffTime);
}

void CellMonitor::adaptInternalTime() {
	setChanged();
	//changed = true;
	internalTime = (SimTime)(internalTime + diffTime);
	diffTime = 0.0;
}

//----------------------------------------------------------------------------main and integration
int CellMonitor::main() {

	timeLimitSet = true;

	cellVariablesContainer->initializeArrays();

	//while (getTime() < timeLimit) {
	while (true) {
		for(std::list<unsigned>::iterator iter = cellIndexList.begin(); iter != cellIndexList.end(); iter++){
			//cell- fehlt noch ne methode in cell?;
			//cout << "CellMonitor::main() calls setCellIndex(" << *iter << ")" << endl;
			cell->setCellIndex(*iter);
			//cout << "CellMonitor::main() calls transitionFunction(" << getTime() << ")" << endl;
			cell->transitionFunction(getTime());
		}

		cellVariablesContainer->copyValues();

		holdFor(timestep);
	}
	return 0;
}

void CellMonitor::setChanged() {

}

unsigned CellMonitor::getArraySize() {
	return cellCount*variablesInCount;
}

unsigned CellMonitor::getRowCount() {
	return cellVariablesContainer->getNumberOfRows();
}

unsigned CellMonitor::getColumnCount() {
	return cellVariablesContainer->getNumberOfColumns();
}
