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


namespace DESpot
{
	//Models a transition into a DES that has a starting state (fromState), and event label (event) and a end state (toState)
	//This is in contranst to a Transition objects which only holds the IDs
	class DesTransition
	{
		//typedef
		public:
			typedef unsigned long long Count;

		public:
			DesTransition() : m_pFromState(null), m_pEvent(null), m_pToState(null)
			{
			}
			
			DesTransition(const DesState& fromState, const DesEvent& event, const DesState& toState)
				: m_pFromState(&fromState), m_pEvent(&event), m_pToState(&toState)
			{
			}

			DesTransition(const DesTransition& other)
				: m_pFromState(other.m_pFromState), m_pEvent(other.m_pEvent), m_pToState(other.m_pToState)
			{
			}
			
			~DesTransition(void){}
			
			//assignment
			DesTransition& operator= (const DesTransition& other)
			{
				if (this != &other)
				{
					m_pFromState = other.m_pFromState;
					m_pEvent = other.m_pEvent;
					m_pToState = other.m_pToState;
				}

				return *this;
			}
			
			DesTransition& inverse(DesTransition& inverseTrans)	const
			{
				inverseTrans.m_pFromState = m_pToState;
				inverseTrans.m_pEvent = m_pEvent;
				inverseTrans.m_pToState = m_pFromState;

				return inverseTrans;
			}

			//comparing
			bool operator == (const DesTransition& other) const
			{
				return (fromState() == other.fromState()) && (event() == other.event()) && (toState() == other.toState());
			}

			bool operator != (const DesTransition& other) const
			{
				return !(*this == other);
			}


		public:
			const DesState& fromState() const
			{
				if (m_pFromState == null)
				{
					throw EX("Transition from state not initialized. Cannot return it.")
				}

				return *m_pFromState;
			}

			void setFromState(const DesState& fromState)
			{
				m_pFromState = &fromState;
			}
			
			const DesEvent& event() const
			{
				if (m_pEvent == null)
				{
					throw EX("Transition event label not initialized. Cannot return it.")
				}

				return *m_pEvent;
			}

			void setEvent(const DesEvent& event)
			{
				m_pEvent = &event;
			}

			const DesState& toState() const
			{
				if (m_pToState == null)
				{
					throw EX("Transition to state not initialized. Cannot return it.")
				}

				return *m_pToState;
			}

			void setToState(const DesState& toState)
			{
				m_pToState = &toState;
			}

			bool isValid() const
			{
				if ((m_pFromState == null) || (m_pEvent == null) || (m_pToState == null) )
					return false;

				return fromState().getId().isValid() && event().getId().isValid() && toState().getId().isValid();
			}

			bool nonDeterministic(const DesTransition& other) const
			{
				if ((fromState() == other.fromState()) && (event() == other.event()) && (toState() != other.toState()))
					return true;
				else
					return false;
			}
					
		private:
			const DesState* m_pFromState;
			const DesEvent* m_pEvent;
			const DesState* m_pToState;
	};
} //end of namespace DESpot
