/*******************************************************************
*
*  DESCRIPTION: class Transducer (implementation)
*
*  AUTHOR: Amir Barylko & Jorge Beyoglonian 
*
*  EMAIL: mailto://amir@dc.uba.ar
*         mailto://jbeyoglo@dc.uba.ar
*
*  DATE: 27/6/1998
*
*******************************************************************/

/** include files **/
#include "transduc.h"   // base class
#include "message.h"    // class ExternalMessage 
#include "mainsimu.h"       // class MainSimulator

/*******************************************************************
* Function Name: Transducer
* Description: Constructor
********************************************************************/
Transducer::Transducer( const string &name )
: Atomic( name ) 
, arrived( addInputPort( "arrived" ) )
, solved( addInputPort( "solved" ) )
, throughput( addOutputPort( "throughput" ) )
, cpuUsage( addOutputPort( "cpuusage" ) )
{
	frec = "0:1:0:0" ;
	tUnit = "0:1:0:0" ;

	if( MainSimulator::Instance().existsParameter( description(), "frecuence" ) )
		frec = MainSimulator::Instance().getParameter( description(), "frecuence" ) ;

	if( MainSimulator::Instance().existsParameter( description(), "timeUnit" ) )
		tUnit = MainSimulator::Instance().getParameter( description(), "timeUnit" ) ;
}

/*******************************************************************
* Function Name: initFunction
********************************************************************/
Model &Transducer::initFunction()
{
	procCount = 0 ;
	cpuLoad = 0 ;
	unsolved.erase( unsolved.begin(), unsolved.end() ) ;
	holdIn( active, frecuence() ) ;
	return *this ;
}

/*******************************************************************
* Function Name: externalFunction
********************************************************************/
Model &Transducer::externalFunction( const ExternalMessage &msg )
{
	cpuLoad += static_cast< long >( ( msg.time() - lastChange() ).asMsecs() * unsolved.size() );

	if( msg.port() == arrived )
	{
		if( unsolved.find( msg.value() ) != unsolved.end() )
		{
			MException e( string("Unresolved Work Id: ") + msg.value() + " is duplicated." );
			e.addLocation( MEXCEPTION_LOCATION() );
			throw e;
		}

		unsolved[ msg.value() ] = msg.time() ;
	}

	if( msg.port() == solved )
	{
		JobsList::iterator cursor( unsolved.find( msg.value() ) ) ;

		if( cursor == unsolved.end() )
		{
			MException e( string("Resolved Work Id: ") + msg.value() + " Not Found!" );
			e.addLocation( MEXCEPTION_LOCATION() );
			throw e;
		}

		procCount ++ ;
		unsolved.erase( cursor ) ;
	}
	return *this ;
}

/*******************************************************************
* Function Name: internalFunction
********************************************************************/
Model &Transducer::internalFunction( const InternalMessage &)
{
	holdIn( active, frecuence() );
	return *this ;
}

/*******************************************************************
* Function Name: outputFunction
********************************************************************/
Model &Transducer::outputFunction( const InternalMessage &msg )
{
	float time( msg.time().asMsecs() / timeUnit().asMsecs() ) ;

	sendOutput( msg.time(), throughput, procCount / time, NULL ) ;

	cpuLoad += static_cast< long >( ( msg.time() - lastChange() ).asMsecs() * unsolved.size() ) ;

	sendOutput( msg.time(), cpuUsage  , cpuLoad / msg.time().asMsecs(), NULL ) ;

	return *this ;
}
