/*	Author: Magdin Stoica
	Supervisor: Dr. Ryan Leduc
	
	Project created in conformity with the requirements for the Degree of Master of Engineering in Software Engineering, 
	Computing and Software Department, 
	McMaster University
	2003 - 2007
*/

#include "EventTranslator.h"
#include "Iterator.h"

namespace DESpot
{

EventTranslator::EventTranslator(bool completeTranslation /*= true*/) : 	
	m_outDes(null),
	m_completeTransl(completeTranslation)
{
}

//_________________________________________________________________________________________________

EventTranslator::EventTranslator(Des* inDes, Des* outDes, bool completeTranslation /*= true*/) :
		m_outDes(outDes),
		m_completeTransl(completeTranslation)
{
	addInputDes(inDes);
}

//_________________________________________________________________________________________________

EventTranslator::EventTranslator(DesProject::DesIteratorPtr& desIterator, Des* outDes, bool completeTranslation /*= true*/) : 
		m_outDes(outDes),
		m_completeTransl(completeTranslation)
{
	for(desIterator->first(); desIterator->notDone(); desIterator->next())
	{
		addInputDes(&desIterator->currentItem());
	}
}


//_________________________________________________________________________________________________

EventTranslator::~EventTranslator(void)
{
}

//_________________________________________________________________________________________________
//adds another DES to the list of input DES to be translated
void EventTranslator::addInputDes(const Des* inDes)
{
	m_inDesSet.push_back(inDes);
}

//_________________________________________________________________________________________________
//sets the output DES that owns the translated events
void EventTranslator::setOutputDes(const Des* outDes)
{
	m_outDes = outDes;
}

//_________________________________________________________________________________________________
//when the given DES set is considered complete the caller can call
//this method to compute the translation. This is can be done automatically
//or later if at creation time the des set is not complete
void EventTranslator::computeTranslation()
{
	if (m_outDes == null || m_inDesSet.size() == 0)
	{
		throw EX("Cannot compute event translation. Either input or output DES are not set");
	}
	
	//fill the event name map of the output DES
	EventNameMap nameMap;
	Des::EventIteratorPtr eventIt = m_outDes->createEventIterator();
	for(eventIt->first(); eventIt->notDone(); eventIt->next())
	{
		const DesEvent& crtEvent = eventIt->currentItem();
		nameMap[crtEvent.getName()] = &crtEvent;
	}
	
	//prepare the dictionary size on the DES dimension
	m_eventDict.resize(m_inDesSet.size());

	//Go through each DES in the set to process their event sets
	for(unsigned int iDes = 0; iDes < m_inDesSet.size(); iDes++)
	{
		const Des* crtDes = m_inDesSet[iDes];
		
		//prepare the dictionary size on the event dimension for the current DES
		m_eventDict[iDes].resize(crtDes->getLastUsedEventId() + 1);

		//go through all the events in this des to translate it 
		Des::EventIteratorPtr eventIt = crtDes->createEventIterator();
		for(eventIt->first(); eventIt->notDone(); eventIt->next())
		{
			const DesEvent& srcDesEvent = eventIt->currentItem();
			
			DesEvent::ID outEventId;
			EventNameIt outDesEventIt = nameMap.find(srcDesEvent.getName());
			if (outDesEventIt != nameMap.end())
			{
				const DesEvent& outDesEvent = *outDesEventIt->second;
				outEventId = outDesEvent.getId();
			}
			else
			{
				if (m_completeTransl)
				{
					std::wstring error = L"DES '" + crtDes->getName() + L"' contains event '" + srcDesEvent.getName() + 
						     L"' but this event is not present in all other input DES. All DES must have the same event set.";
					
					throw error;
				}
				//else --> outEventId is invalid by definition
			}

			
			//add the events to the dictionary
			m_eventDict[iDes][srcDesEvent.getId()] = outEventId;
		}
	}
}

//_________________________________________________________________________________________________
//Translates between an event from a source DES to an event in the output DES
const DesEvent* EventTranslator::translate(const DesEvent* srcDesEvent, unsigned int srcDesId /*= 0*/) const
{
	DesEvent::ID eventId = m_eventDict[srcDesId][srcDesEvent->getId()];
	if (eventId.isValid())
	{
		return &m_outDes->getEvent(eventId);
	}
	else
	{
		//this method should only be used for complete translations. Use the overwrite that
		//return a bool to tell the caller if the translation was successfull or not
		throw EX("There is no translation for the source event");		
	}
}

//_________________________________________________________________________________________________
//Translates between an event from a source DES to an event in the output DES
bool EventTranslator::translate(const DesEvent* srcDesEvent, unsigned int srcDesId, const DesEvent*& o_outEvent) const
{
	DesEvent::ID eventId = m_eventDict[srcDesId][srcDesEvent->getId()];
	if (eventId.isValid())
	{
		o_outEvent = &m_outDes->getEvent(eventId);
		return true;
	}
	else
	{
		return false;
	}
}

//_________________________________________________________________________________________________
//Translates between an event from a source DES to an event in the output DES
bool EventTranslator::translate(const DesEvent* srcDesEvent, const DesEvent*& o_outEvent) const
{
	return translate(srcDesEvent, 0, o_outEvent);
}
} //namespace DESpot

