/*	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 "DesStateTransMapIterator.h"


namespace DESpot
{
	class DesStateTransIterator : public DesStateTransMapIterator
	{
		public:
			DesStateTransIterator(const DesState& state,
								  const std::map<const DesState*, 
				                                 std::map<const DesEvent*, 
														  std::map<const DesState::ID, const DesState*>*
														 >*
											    >& transMap, 
								  const DesSelfTransIterator& selfTransIt,
								  bool  ownSelfTransIt = true) 
				: DesStateTransMapIterator(state, transMap),
				  m_selfTransIt(selfTransIt),
				  m_ownSelfTransIt(ownSelfTransIt)
			{
			}

			virtual ~DesStateTransIterator(void)
			{
				if (m_ownSelfTransIt)
				{
					//The client has been given ownership over this self-transitions iterator and it must
					//destory it once is itself destroyed
					delete &m_selfTransIt;
				}
			}

		//Iterator Overridables
		public:
			virtual void first() const
			{
				DesStateTransMapIterator::first();
				m_selfTransIt.first();
			}

			virtual void next() const
			{									
				if (DesStateTransMapIterator::isDone() && m_selfTransIt.isDone())
					throw EX("The iterator is already done. Call isDone() before calling next()")

				if (DesStateTransMapIterator::isDone() == false)
				{
					//attempt to advance the default state transition map iterator
					DesStateTransMapIterator::next();
					
					//test to make sure the iterator is not done now (it was at the last position before calling next())
					if (DesStateTransMapIterator::isDone())
					{
						//the state transition map iterator is done; continue with the self-transition iterator
						m_selfTransIt.first();
					}				
				}
				else
				{
					//advance the self-trans iterator since the transition map one is done
					m_selfTransIt.next();
				}
			}
			
			virtual bool isDone() const
			{
				return (DesStateTransMapIterator::isDone() && m_selfTransIt.isDone());
			}
			
			virtual DesTransition& currentItem()
			{
				if (isDone())
					throw EX("The iterator is already done. Call isDone() before calling currentItem()")

				if (DesStateTransMapIterator::isDone())
				{
					m_crtTrans.setFromState(*m_state);
					m_crtTrans.setEvent(m_selfTransIt.currentItem());
					m_crtTrans.setToState(*m_state);

					return m_crtTrans;
				}
				else
				{
					return DesStateTransMapIterator::currentItem();
				}
			}
			
			virtual const DesTransition& currentItem() const
			{
				if (isDone())
					throw EX("The iterator is already done. Call isDone() before calling currentItem()")

				if (DesStateTransMapIterator::isDone())
				{
					m_crtTrans.setFromState(*m_state);
					m_crtTrans.setEvent(m_selfTransIt.currentItem());
					m_crtTrans.setToState(*m_state);

					return m_crtTrans;
				}
				else
				{
					return DesStateTransMapIterator::currentItem();
				}
			}

		protected:
			//disallow copying
			DesStateTransIterator(const DesStateTransIterator& other): 
				 DesStateTransMapIterator(other), 
				 m_selfTransIt(other.m_selfTransIt),
				 m_ownSelfTransIt(other.m_ownSelfTransIt)
			{}
			
			DesStateTransIterator& operator= (const DesStateTransIterator&) { return *this;}

		protected:
			//the iterator for global self-transitions. If provided these must be considered in the iteration
			const DesSelfTransIterator& m_selfTransIt;

			//If true this iterator owns the given self transition iterator and it must destroy it
			const bool m_ownSelfTransIt;
	};

} //end of namespace Despot

