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

#pragma once

#include "CommonDefinitions.h"
#include "TransitionMapIterator.h"
#include "DesSelfTransIterator.h"
#include "DesStateIterator.h"
#include "DesStateTransIterator.h"


namespace DESpot
{
	/* The transition iterator works as follows: using the state pool it creates a state iterator which it uses
	   to iterate through every state of DES. For each state of DES it will
			- iterate through the transitions having the state as start state in the transition map (may be none)
			- iterate through the global self-loops and return the self-loop transitions
	*/
	class DesTransitionIterator : public Iterator<DesTransition&, const DesTransition&>
	{
		public:
			//A typedef defined to improve the clarity of the constructor's signature. Although
			//public this typedef will never be used by clients of the iterator but only by its creator
			//- the transition function. The re-declaration of this typedef (as opposed to using the typedef
			//already defined in the DesTransitionFunction class allows the design to keep DesTransitionFunction
			//private to the "Des Model" subsystem
			typedef std::map<const DesState*, 
                             std::map<const DesEvent*, 
									  std::map<const DesState::ID, const DesState*>*
									 >*
						    > TransitionMap;
		public:
			DesTransitionIterator(const TransitionMap& transMap, 
								  const DesSelfTransIterator& selfTransIt, 
								  const DesStateIterator& stateIt):
					m_transMap(transMap),
					m_selfTransIt(selfTransIt),
					m_stateIt(stateIt)
			{
				//the state transition map iterator is a "working" iterator and is created when needed
				m_pCrtStateTransIt = null;
			}

			virtual ~DesTransitionIterator(void)
			{
				if (m_pCrtStateTransIt)
				{
					delete m_pCrtStateTransIt;
					m_pCrtStateTransIt = null;
				}

				delete &m_stateIt;
			}

		public:
			virtual void first() const 
			{
				//start with the first state in Des
				m_stateIt.first();

				//position the transition iterator to this state or to the first state that has transitions
				positionTransIterator();
			}

			virtual void next() const
			{
				if (m_stateIt.isDone() && crtStateTransIt().isDone())
					throw EX("Iteration already at the end. Call isDone before calling next()")
				
				//attempt to go to the next transition of this state
				crtStateTransIt().next();
				
				if (crtStateTransIt().isDone())
				{
					//done with this state -> try to go to the next state
					m_stateIt.next();

					//position the transition iterator to this state or to the first state that has transitions
					positionTransIterator();

					//NOTE: that here the state iterator might have reached the end
				}
			}
			
			virtual bool isDone() const
			{
				if (m_stateIt.isDone())
					return true;

				//the state iterator is not done yet pointing to a state the transition iterator 
				//for this state must not be done such that it points to a transition. 				
				if (crtStateTransIt().isDone())
				{				
					assert(false);
					throw EX("Invalid iterator state")
				}

				//not done yet
				return false;
			}
			
			virtual DesTransition& currentItem()
			{
				if (isDone())
				{				
					assert(false);
					throw EX("Iterator have finished already. Call isDone() before calling currentItem()")
				}

				return crtStateTransIt().currentItem();
			}

			virtual const DesTransition& currentItem() const
			{				
				if (isDone())
				{				
					assert(false);
					throw EX("Iterator have finished already. Call isDone() before calling currentItem()")
				}

				return crtStateTransIt().currentItem();
			}

		//Implementation operations	
		private:
		   DesStateTransMapIterator& crtStateTransIt() const
		   {
			   if (m_pCrtStateTransIt == null)
			   {
				   assert(false);
				   throw EX("Unexpected call to obtain the state transition iterator. It is not initialized.")
			   }
			   
			   return *m_pCrtStateTransIt;
		   }

		   void initTransIterator(const DesState& state) const
		   {
			   if (m_pCrtStateTransIt == null)
			   {
				   //Create a state iterator that can iterator through self-transitions too. Just make sure the
				   //the ownership of the self-transition iterator stays with this iterator
				   m_pCrtStateTransIt = new DesStateTransIterator(state, m_transMap, m_selfTransIt); 
			   }
			   else
			   {
				   m_pCrtStateTransIt->setState(state);
			   }

			   m_pCrtStateTransIt->first();
		   }
		
		   //Initializes the trans-map iteratorto iterate the transitions of the current state in the 
		   //state pool (as pointed by the state iterator)if the current state has no transitions 
		   //it moves to the next state until it either finds one with transitions or it reaches 
		   //the end of the state pool
		   void positionTransIterator() const
		   {
			   //in case the current state has no transitions go to the first state that has a transition 
			   //or to the end of the state pool
			   while((m_stateIt.isDone() == false))
			   {
				   //set the transition-map iterator to this new state
				   initTransIterator(m_stateIt.currentItem());

				   if (crtStateTransIt().isDone() == false)
				   {
					   //the current state has transitions -> no need to look any further
					   break;
				   }

				   //go to the next state; the current one has no transitions
				   m_stateIt.next();				
			   }
		   }
		
		private:
			//disallow copying
			DesTransitionIterator(const DesTransitionIterator& other): 
				m_transMap(other.m_transMap),
				m_selfTransIt(other.m_selfTransIt),
				m_stateIt(other.m_stateIt)
			{}
			
			DesTransitionIterator& operator= (const DesTransitionIterator&) { return *this;}

		private:
			//The iterator used to go through all transitions in the transition map
			const TransitionMap& m_transMap;
			
			//The iterator used to go through self-transitions
			const DesSelfTransIterator& m_selfTransIt;

			//The iterator used to go through all the states
			const DesStateIterator& m_stateIt;

			//The state transition iterator used to iterate through the transitions having 
			//a particular state as its start state
			mutable DesStateTransMapIterator* m_pCrtStateTransIt;
	};

} //end of namespace Despot

