/*******************************************************************
*
*  DESCRIPTION: class InertialDelayCell
*
*  AUTHOR:    Amir Barylko & Jorge Beyoglonian 
*  Version 2: Daniel Rodriguez.
*
*  EMAIL: mailto://amir@dc.uba.ar
*         mailto://jbeyoglo@dc.uba.ar
*         mailto://drodrigu@dc.uba.ar
*
*  DATE: 27/6/1998
*  DATE: 17/9/1999 (v2)
*
*******************************************************************/

// ** include files **//
#include "idcell.h"	// header class
#include "message.h"	// ExternalMessage
#include "coupcell.h"	// CoupledCell
#include "realfunc.h"	// calculateWithQuantum

/*******************************************************************
* Method: externalFunction
********************************************************************/
Model &InertialDelayCell::externalFunction( const ExternalMessage &msg )
{
	Time delay( static_cast<const CoupledCell&>( parent() ).defaultDelay() ) ;
	Time actualTime( msg.time() );

	if (actualTime == Time::Zero)
		actualValue = value();

	Real tv ;

	//////////////////////////////////////////////////////////////////////
	// if the message come from an external port we must set the value

	// if come from a neighbor
	if( msg.port() == neighborPort() ){
		VirtualPortList	*vpl = new VirtualPortList;
		getOutPorts(vpl);

		tv = SingleLocalTransAdmin::Instance().evaluate( localFunction(), neighborhood(), NULL, delay, actualTime, vpl, this ) ;

		delete vpl;
	}
	else	// else the message come from an IN port
	{
		string functionName = inputPortFunction()[ msg.port().name() ];
		
		// first we set the new port value in the list of PortValues
		setPortValue( msg.port().name(), msg.value() );

		if (functionName == DEFAULT_FUNCTION_InPort)
			tv = msg.value() ;
		else {	// sino es un PortInTransition valido
			VirtualPortList	*vpl = new VirtualPortList;
			getOutPorts(vpl);

			tv = SingleLocalTransAdmin::Instance().evaluate( functionName, neighborhood(), &(inputPortValues()), delay, actualTime, vpl, this, msg.port().name() ) ;

			delete vpl;
		}
	}
	///////////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////////
        if (UseQuantum().Active())
                tv = valueWithQuantum(tv, Real(UseQuantum().Value()));
        /////////////////////////////////////////////////////////////////////

	if( actualValue != tv )
	{
		actualValue = tv;		/* El nuevo estado es el recien calculado */

		if( state() == passive )
			holdIn( active, delay ) ;
		else
			// the coupled sets sigma to the reminder time until the next internal transition 
			if( nextChange() > Time::Zero && futureValue != tv)
				holdIn( active, delay ) ;

		futureValue = tv;
	}
	return *this ;
}

/*******************************************************************
* Method: outputFunction
********************************************************************/
Model &InertialDelayCell::outputFunction( const InternalMessage &msg )
{
	value( actualValue );
        this->sendOutput( msg.time(), outputPort(), this->value().value(), NULL );
        return *this;
}
