/*	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 <map>
#include "CommonDefinitions.h"
#include "Iterator.h"
#include "DesTransition.h"
#include "DesEvent.h"


namespace DESpot
{
	class TransitionMapIterator : 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:
			TransitionMapIterator(const TransitionMap& transMap): m_transMap(transMap)			
			{
			}

			virtual ~TransitionMapIterator(void)
			{
			}

		public:
			virtual void first() const 
			{
				//start with the beginning of the transition map
				m_crtFromStateIt = getStartState(); 
				
				if (m_crtFromStateIt != m_transMap.end())
				{
					//there is something in the transition map go to the first event
					m_pCrtEventMap = m_crtFromStateIt->second;

					if (m_pCrtEventMap == null)
					{
						assert(false);
						throw EX("Invalid event map for the first state in the transition map. Cannot be null.")
					}

					m_crtEventIt = m_pCrtEventMap->begin();

					if (m_crtEventIt != m_pCrtEventMap->end())
					{
						//there is a list of events in the map go to the first toState. there maybe more
						//if the transition function allows non-determinism
						m_pCrtStateMap = m_crtEventIt->second;

						if (m_pCrtStateMap == null)
						{
							assert(false);
							throw EX("Invalid state map for the first state and first event in the transion map. Cannot be null")
						}
						
						m_crtToStateIt = m_pCrtStateMap->begin();
					}
				}
			}

			virtual void next() const
			{
				if (m_crtFromStateIt == m_transMap.end())
				{
					assert(false);
					throw EX("Iteration already at the end. Call isDone() before calling next()")
				}

				if (m_crtEventIt == m_pCrtEventMap->end())
				{
					assert(false);
					throw EX("Iteration already at the end of current state. Call isDone() before calling next()")
				}

				if (m_crtToStateIt == m_pCrtStateMap->end())
				{
					assert(false);
					throw EX("Iteration already at the end of the current destination state. Call isDone() before calling newxt()")
				}

				//try to advance to the next "toState" for the current event
				m_crtToStateIt++;

				//test to see if we are not at the end of the state map for this event
				if (m_crtToStateIt == m_pCrtStateMap->end())
				{
					//Try to advance to the next event leaving out of the current state
					m_crtEventIt++;

					//Test to see if we were not at the end of the transition map for this state.
					if (m_crtEventIt != m_pCrtEventMap->end())
					{
						//go to the beginning of the state map of this new event label
						m_pCrtStateMap = m_crtEventIt->second;
						m_crtToStateIt = m_pCrtStateMap->begin();
					}
					else
					{
						//We are at the end of the event map for the current fromState.
						//Must go to the next state and its first transition
						m_crtFromStateIt = getNextFromState();

						//we may have reached the end of the list of states in which case
						//isDone should return false
						if (m_crtFromStateIt != m_transMap.end())
						{
							//we still have a fromState so go to its first transition
							m_pCrtEventMap = m_crtFromStateIt->second;
							assert(m_pCrtEventMap != null);
							m_crtEventIt = m_pCrtEventMap->begin();

							m_pCrtStateMap = m_crtEventIt->second;
							assert(m_pCrtStateMap != null);
							m_crtToStateIt = m_pCrtStateMap->begin();
						}
						//else --> end of the list of states
					}
				}				
				//else --> advancing the state iterator is enough
			}
			
			virtual bool isDone() const
			{
				if (m_crtFromStateIt == m_transMap.end())
					return true;

				if (m_crtEventIt == m_pCrtEventMap->end())
				{
					assert(false);
					throw EX("Invalid iterator state")
				}
				
				if (m_crtToStateIt == m_pCrtStateMap->end())
				{
					assert(false);
					throw EX("Invalid iterator state")
				}
				
				return false;
			}
			
			virtual DesTransition& currentItem()
			{
				if ((m_crtFromStateIt == m_transMap.end()) || (m_crtEventIt == m_pCrtEventMap->end()) || (m_crtToStateIt == m_pCrtStateMap->end()))
				{
					assert(false);
					throw EX("Iterator has reached the end. Cannot return current item")
				}					
				
				m_crtTrans.setFromState(*(m_crtFromStateIt->first));
				m_crtTrans.setEvent(*(m_crtEventIt->first));
				m_crtTrans.setToState(*(m_crtToStateIt->second));
				return m_crtTrans;
			}

			virtual const DesTransition& currentItem() const
			{				
				if ((m_crtFromStateIt == m_transMap.end()) || (m_crtEventIt == m_pCrtEventMap->end()) || (m_crtToStateIt == m_pCrtStateMap->end()))
				{
					assert(false);
					throw EX("Iterator has reached the end. Cannot return current item")
				}					
				
				m_crtTrans.setFromState(*(m_crtFromStateIt->first));
				m_crtTrans.setEvent(*(m_crtEventIt->first));
				m_crtTrans.setToState(*(m_crtToStateIt->second));
				return m_crtTrans;
			}

		//Implementation types
		protected:
			typedef std::map<const DesState::ID, const DesState*> StateMap;
			typedef StateMap::const_iterator StateMapIt;			
			
			//event label to destination state (for each state there is a list of events that leave the state; 
			//each event goes to one and only one state)
			typedef std::map<const DesEvent*, StateMap*>  EventMap;
			typedef EventMap::const_iterator EventMapIt;

			//state to event map (for each state there is a list (implemented as an event map) of events that leave 
			//the states 
			//NOTE: This type is defined at the beginning of the class for readability because it is used 
			//by the constructor
			//typedef std::map<const DesState*, EventMap*> TransitionMap; 
			typedef TransitionMap::const_iterator TransMapIt;

		protected:
			//disallow copying
			TransitionMapIterator(const TransitionMapIterator& other): m_transMap(other.m_transMap) {}
			TransitionMapIterator& operator= (const TransitionMapIterator&) { return *this;}

		//Implementation operations	
		protected:
			//Derived iterators can override this to start the iteration with a different state
			virtual TransMapIt getStartState() const
			{
				return m_transMap.begin();
			}

			virtual TransMapIt getNextFromState() const
			{
				return (++m_crtFromStateIt);
			}

		protected:
			//The transition map of the DesTransitionFunction (given directly by the transition function object
			//when creating the iterator
			const TransitionMap& m_transMap;
			
			//current iterator through the from trans map (fromState -> event map)
			mutable TransMapIt m_crtFromStateIt;
			
			//the event map of the currently iterated state
			mutable const EventMap*  m_pCrtEventMap;

			//current iterartor through the event map (m_pCrtEventMap) of a current iterated state (event -> toState)
			mutable EventMapIt m_crtEventIt;

			//the statem map of the currently iterated event
			mutable StateMap* m_pCrtStateMap;

			//current iterator through the state map (state ID -> state)
			mutable StateMapIt m_crtToStateIt;

			//current returned transition (what currentItem() returns)
			mutable DesTransition m_crtTrans;
	};

} //end of namespace Despot

