/*	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
*/

#define _CRT_SECURE_NO_WARNINGS
#include "StateTranslator.h"

namespace DESpot
{

StateTranslator::StateTranslator(int desCount /*= 0*/) : 
	m_desCount(desCount) //when desCount == 0 it will be initialized later
{
}

//_________________________________________________________________________________________________

StateTranslator::~StateTranslator(void)
{
	//destroy all the source tuples created by the translator
	for(SourceStateDictIt srcStateEntryIt = m_srcStateDict.begin(); srcStateEntryIt != m_srcStateDict.end(); ++srcStateEntryIt)
	{
		//delete the tuple of the current entry
		const SrcStateTuple* srcStateTuple = srcStateEntryIt->first;
		delete srcStateTuple;
		srcStateTuple = null;

		//Note that we cannot delete the output state which is the value stored for the tuple key because
		//it belongs to a DES
	}
}

//_________________________________________________________________________________________________

void StateTranslator::setDesCount(int desCount)
{
	m_desCount = desCount;
}

//_________________________________________________________________________________________________

DesState& StateTranslator::beginEntry(std::vector<const DesState*>* srcStateTuple)
{
	std::wstring stateName;	
	bool isMarked = true;
	for(int iDes = 0; iDes < m_desCount; ++iDes)
	{
		const DesState* srcState = (*srcStateTuple)[iDes];
		
		//TODO: make the algorithm work with unnamed states to conserve memory
		//update the properties of the output state based on this source state
		if (iDes > 0)
		{
			stateName += L"-";
		}
		
		//the name of the output state is made like of the source aliases srcAlias1; srcAlias2; srcAlias2...
		//the alias of the output state is empty
		stateName += srcState->getAlias();

		//update the marking; an output state is marked if ALL its source states are marked
		isMarked &= srcState->isMarked();
	}

	m_crtEntryStateTemplate.setName(stateName);
	m_crtEntryStateTemplate.setMarked(isMarked);

	//NOTE: The initial state property is updated by the algoritm because it is a one-time operation
	//so there is no point in testing for initial state for each of the source state of all output states
	//when this is supposed to be done only once

	return m_crtEntryStateTemplate;
}

//_________________________________________________________________________________________________

void StateTranslator::endEntry(std::vector<const DesState*>* srcStateTuple, const DesState& outState)
{
	//Add the current entry to the dictionary. However instead of the output state stored
	//in the current entry (which is only a template) put the given outState which is
	//comming from the output DES. Also make a copy of the source tuple so that the translator can take
	//ownership and create a unique entry for this tuple (the caller (the algorithm) can translate
	//different source tuples which are equal in value (they have the same tuple memembers). The translator
	//must store a unique tuple.
	SrcStateTuple* srcStateTupleEntry = new SrcStateTuple(*srcStateTuple);
	m_srcStateDict[srcStateTupleEntry] = &outState;

	//check to see if the output state dictionary has space for another element
	DesState::ID outStateId = outState.getId();	
	if (outStateId >= m_outStateDict.size())
	{
		//already at the end of the pool. resize the pool
		const int DICTIONARY_RESIZE_FACTOR = 2; //the classic factor is 2 but it maybe too slow
		m_outStateDict.resize((m_outStateDict.size()+1) * DICTIONARY_RESIZE_FACTOR); //+1 ensures it works when state pool is completely empty
	}

	m_outStateDict[outStateId] = ConstEntry(&outState, srcStateTupleEntry);

	m_crtEntryStateTemplate.reset();
}

//_________________________________________________________________________________________________

const std::vector<const DesState*>* StateTranslator::translate(DesState::ID stateId) const
{
	return m_outStateDict[stateId].srcStateTuple;
}

//_________________________________________________________________________________________________

const std::vector<const DesState*>* StateTranslator::translate(const DesState* outState) const
{
	return translate(outState->getId());
}

//_________________________________________________________________________________________________

bool StateTranslator::translate(std::vector<const DesState*>* srcStateTuple, DesState::ID& out_outStateId) const
{
	const DesState* foundOutState = null;
	if (translate(srcStateTuple, foundOutState))
	{
		out_outStateId = foundOutState->getId();
		return true;
	}
	else 
	{
		return false;
	}
}

//_________________________________________________________________________________________________
//This method looks for a tuple of source state trying to match it with any of the exiting entires in the 
//dictionary. The search has linear complexity O(number_of_entries x number_of_des). This search could
//be speed up by using a TRIE structure. The complexity will be come logaritmic. However using  a TRIE structure
//only instead of the current map would make the translation "out state -> to source states" very slow.
bool StateTranslator::translate(std::vector<const DesState*>* srcStateTuple, const DesState*& out_outState) const
{
	SourceStateDictCIt srcStateDictIt = m_srcStateDict.find(srcStateTuple);
	if (srcStateDictIt != m_srcStateDict.end())
	{
		out_outState = srcStateDictIt->second;
		return true;
	}
	else
	{
		return false;
	}
	
	//TODO: remove all lookup code. We are now using a double-map and we will probably be using
	//a proper TRIE structure to optimize both speed and memory consumption.
	/*for(StateDictCIt dictIt = m_outStateDict.begin(); dictIt != m_outStateDict.end(); ++dictIt)
	{
		const SrcStateTuple* crtStateTuple = dictIt->second.srcStateTuple;
		
		//check to see if the given state tuple matches the current one
		bool matchFound = true;
		for(int iDes = 0; (iDes < m_desCount) && matchFound; ++iDes)
		{
			matchFound &= ((*srcStateTuple)[iDes] == (*crtStateTuple)[iDes]);
		}

		//if all source state matched we've found our entry so return it
		if (matchFound)
		{
			out_outState = dictIt->second.outState;
			return true;
		}
	}  */

	return false;
}

//_________________________________________________________________________________________________

bool StateTranslator::SrcStateTupleLess::operator()(const SrcStateTuple* const & leftSrcTuple, const SrcStateTuple* const & rightSrcTuple) const
{
	//go through every source in the tuple and compare left with right. The number of elements in a tuple matches
	//the number of DES to translate
	for(unsigned int iSrcState = 0; iSrcState < leftSrcTuple->size(); ++iSrcState)
	{
		const DesState* leftState = (*leftSrcTuple)[iSrcState];
		const DesState* rightState = (*rightSrcTuple)[iSrcState];
		
		//compare the pointers themselves. Note that this would not work if the pointers are not from the same
		//memory space (in a distributed algorithm). Also note that the IDs cannot be used alone because they don't
		//identify the DES the state belongs to (state 1 in one des has the same id with state 1 from another)
		if (leftState < rightState)
		{
			return true;
		}
		else if (leftState > rightState)
		{
			return false;
		}
		//else leftState = rightState which means we go to the next member in the tuple
	}

	//the two tuples are equal (all the members of each tuple are equal)
	return false;
}

} //end of namespace DESpot
