/*	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 <string>
#include <memory>
#include <vector>

#include <QMap>

#include "Iterator.h"
#include "DesState.h"
#include "DesEvent.h"
#include "DesTransition.h"
#include "NameValidator.h"
#include "DesTypes.h"

namespace DESpot
{

	class StatePool;
	class EventPool;
	class DesNotifications;
	class DesTransitionFunction;
	class ReachabilityAlgo;
	class DesIntegrityAlgo;
	class DesInterface;
	class DesSubsystem;
	class NonBlockingAlgo;

	class GedDesState;

	class DesSerializerAccess
	{
		public:
			virtual void setIntegrity(int integStatus) = 0;
			virtual void setIntegrityStamp(const std::wstring& integStamp) = 0;

			virtual void setNonBlockingProp(int nonBlockProp) = 0;
			virtual void setNonBlockingStamp(const std::wstring& nonBlockStamp) = 0;

			virtual void setReachableProp(int reachProp) = 0;
			virtual void setReachableStamp(const std::wstring& reachStamp) = 0;

			virtual StatePool* getStatePool() = 0;
			virtual EventPool* getEventPool() = 0;
			virtual DesTransitionFunction* getTransFunction() = 0;
	};

	//class Des : private DesSerializerAccess
	//xma: change private to public as we need to load graphic info later in scene
	//     may revisit this change later on
	class Des : public DesSerializerAccess
	{
		//Types_________________________________________
		public:
			typedef Iterator<DesState&, const DesState&> StateIterator;
			typedef std::auto_ptr<const StateIterator> StateIteratorPtr;

			typedef Iterator<DesEvent&, const DesEvent&> EventIterator;
			typedef std::auto_ptr<const EventIterator> EventIteratorPtr;

			typedef Iterator<DesTransition&, const DesTransition&> TransIterator;
			typedef std::auto_ptr<const TransIterator> TransIteratorPtr;

			typedef Iterator<DesEvent&, const DesEvent&> SelfTransIterator;
			typedef std::auto_ptr<const SelfTransIterator> SelfTransIteratorPtr;

			typedef QMap<const DesState*, const GedDesState*> GedInfo;

			//Construction___________________________________
		public:
			Des(void);
			Des(const std::wstring& name, DesType type = eRegularDes);
			Des(const std::wstring& name, const std::wstring& fileName, bool delayLoad = false);
			virtual ~Des(void);

		//Des Operations________________________________
		public:
			DesType getType(void) const;
			void setType(const DesType& desType);

			std::wstring getName() const;
			void setName(const std::wstring newName);

			Integrity getIntegrity() const;
			std::wstring getIntegrityStamp() const;
			bool checkIntegrity(DesIntegrityAlgo& integAlgo) const;

			//Reachability
			bool		    isReachable() const;
			ReachableProp getReachableProp() const;
			std::wstring	getReachableStamp() const;
			virtual bool	checkReachability(ReachabilityAlgo& nonBlockAlgo) const;
			void			resetReachability();

			//Non-blocking
			bool		    isNonBlocking() const;
			NonBlockingProp getNonBlockingProp() const;
			std::wstring	getNonBlockingStamp() const;
			virtual bool	checkNonBlocking(NonBlockingAlgo& nonBlockAlgo) const;

			//returns true if this DES has an owner (when it is part of HISC project)
			bool   hasOwner() const;

			//returns the owner when the type of DES is an Interface DES. Calling this
			//method for incorrect typed DES will result in an exception
			const DesInterface* getInterfaceOwner() const;

			//returns the owner when the type of DES is subsystem DES. Calling this
			//method for incorrect typed DES will result in an exception
			const DesSubsystem* getSubsystemOwner() const;

			//Sets the owner of this DES when it is part of a project. Subsystem DES accept a subsystem owner
			//while interface DES accept an interface owner. Setting the incorrect type of owner results in an exception
			void setOwner(const DesSubsystem* subsysOwner);
			void setOwner(const DesInterface* interfOwner);

			//returns the name of the file the DEs was loaded from if it comes from a file
			bool isNew() const;
			std::wstring getFileName() const;

			bool delayedLoad() const;

			bool isModified() const;
			void setModified(bool isModified = true) const;

			bool isNonDeterministic() const;

			void clean() const;

		//Serialization
		public:
			void load();
			void load(const std::wstring& fileName);

			//saves this DES to whatever file it has been loaded from
			void save();

			//saves this DES into the given file. Used for
			//new Des only, des that have never been saved
			void save(const std::wstring& fileName);

			// added by rjl - remove when bddhisc and bddsd
			// integrated with despot 

			void exportToBDDhiscORsd(const std::wstring& fileName, bool isHigh, bool isHISC);
			//  remove to here - RJL

			//reverts the content of the DES to the file the DES was loaded from. Works only for DES loaded
			//from file
			void revertToFile();
			void revertToDes(Des& des);
			void revertGedToDes(Des& des);
			
		//Notification management_______________________
		public:
			//The return is a cookied that must be used when unsubscribing
			unsigned int subscribe(DesNotifications* pNotifListner);
			void unsubscribe(unsigned int cookie);

		//State operations_____________________________
		public:
 			//obtaining states
			const DesState& getState(const DesState::ID& stateId) const;
			bool findState(std::wstring stateName, const DesState*& foundState) const;

			//returns the last used state ID
			DesState::ID getLastUsedStateId() const;

			//Iterating through states and finding out the number of states
			DesState::Count getStateCount() const;
			StateIteratorPtr createStateIterator() const;

			DesState::Count getMarkedStateCount() const;
			StateIteratorPtr createMarkedStateIterator() const;

			//Initial state
			bool hasInitialState() const;
			const DesState& getInitialState() const;
			void setInitialState(const DesState& initState);

			//modifing the list of states by adding, removing or changing states
			const DesState& addState(const DesState& stateTemplate);

			void deleteState(const DesState::ID& stateId);

			void changeState(const DesState::ID& stateId, const DesState& newState);
			void changeStateName(const DesState::ID& stateId, const std::wstring& newName);
			void changeStateAlias(const DesState::ID& stateId, const std::wstring& newAlias);
			void changeStateInit(const DesState::ID& stateId, bool isInit);
			void changeStateMarking(const DesState::ID& stateId, bool isMarked);
			void changeStateReachable(const DesState::ID& stateId, bool isReachable);

		//Event operations_____________________________
		public:
 			//obtaining events
			const DesEvent& getEvent(const DesEvent::ID& eventId) const;
			bool findEvent(std::wstring eventName, const DesEvent*& foundEvent) const;

			//returns the last used event ID
			DesEvent::ID getLastUsedEventId() const;

			//iterating through events
			DesEvent::Count getEventCount() const;
			DesEvent::Count getEventCountByCtrl(bool isControllable) const;
			DesEvent::Count getEventCountByType(EventType type) const;

			EventIteratorPtr createEventIterator() const;

			//tests if the given event is eligible to be added to this DES
			bool isEligible(const DesEvent& event) const;

			//Modifying events by adding, deleting or changing
			const DesEvent& addEvent(const DesEvent& eventTemplate);

			void deleteEvent(const DesEvent::ID& eventId);

			void changeEvent(const DesEvent::ID& eventId, const DesEvent& newEvent);
			void changeEventName(const DesEvent::ID& eventId, const std::wstring& newName);
			void changeEventAlias(const DesEvent::ID& eventId, const std::wstring& newAlias);
			void changeEventType(const DesEvent::ID& eventId, EventType newType);
			void changeEventCtrl(const DesEvent::ID& eventId, bool isControllable);

		//Transition operations_____________________
		public:
			//Return the number of transitions
			DesTransition::Count getTransCount(bool includeSelfTrans = true) const;
			DesTransition::Count getSelfTransCount() const;

            TransOpRes addTransition(const DesTransition& trans);

			//Adds a globa self-loop transition - a self-loop with the given even for all current and future
			//states of Des
			TransOpRes addSelfTransition(const DesEvent& selfTransEvent);

			void deleteTransition(const DesTransition& trans);

			void deleteSelfTransition(const DesEvent& selfTransEvent);

			TransOpRes changeTransition(const DesTransition& trans, const DesTransition& change);

			TransIteratorPtr createTransIterator(bool excludeSelfTrans = false) const;

			SelfTransIteratorPtr createSelfTransIterator() const;

			TransIteratorPtr createStateTransIterator(const DesState& state, bool excludeSelfTrans = false) const;

			TransIteratorPtr createInvTransIterator(bool excludeSelfTrans = false) const;

			TransIteratorPtr createStateInvTransIterator(const DesState& state, bool excludeSelfTrans = false) const;

			bool findTransition(const DesTransition& trans);

			//Checks if a transition with the label "event" leaves "fromState". If there is it returns true
			//and returns the destination state in the out parameter o_toState
			bool transExists(const DesState* fromState, const DesEvent* event, const DesState*& o_toState);

		// GedInfo methods
		public:
			Des::GedInfo& getGedInfo() { return m_gedInfo; }
			bool hasGedInfo() const { return !m_gedInfo.isEmpty(); }

		//Implementation methods
		private:
			TransOpRes verifyTransition(const DesTransition& trans);
			TransOpRes verifyTransition(const DesEvent& selfLoopEvent);

			//Records the initial state in DES. If the given state is set to the be the inital the change in initial state
			//is done and the listenrs are notified. If the given state used to be the initial one and it is not than
			//the initial state record is reset
			void recordInitialState(const DesState* pState);

			//Return the current date and time
			std::wstring now() const;

		//Serializer access
		private:
			void setIntegrity(int integStatus);
			void setIntegrityStamp(const std::wstring& integStamp);

			void setNonBlockingProp(int nonBlockProp);
			void setNonBlockingStamp(const std::wstring& nonBlockStamp);

			void setReachableProp(int reachProp);
			void setReachableStamp(const std::wstring& reachStamp);

			StatePool* getStatePool();
			EventPool* getEventPool();
			DesTransitionFunction* getTransFunction();


		//Notifications
		private:
			//General operation notifications
			void onNameChanged(const std::wstring& oldName, const std::wstring& newName) const;
			void onFileNameChanged(const std::wstring& oldFileName, const std::wstring& newFileName) const;
			void onTypeChanged(DesType oldType, DesType& newType) const;
			void onIntegrityChanged() const;
			void onReachabilityChanged() const;
			void onNonBlockingChanged() const;

			//State related notifications
			void onStateAdded(const DesState& addedState) const;
			void onRemovingState(const DesState& state) const;
			void onStateRemoved(const DesState::ID& stateId) const;
			void onStateChanged(const DesState& changedState) const;

			//Event related notifications
			void onEventAdded(const DesEvent& addedEvent) const;
			void onRemovingEvent(const DesEvent& event) const;
			void onEventRemoved(const DesEvent::ID& eventId) const;
			void onEventChanged(const DesEvent& changedEvent) const;

			//Transition related notifications
			void onTransAdded(const DesTransition& addedTrans) const;
			void onGlobalSelfTransAdded(const DesEvent& selfTransEvent) const;
			void onRemovingTrans(const DesTransition& removedTrans) const;
			void onTransRemoved(const DesTransition& removedTrans) const;
			void onRemovingSelfTrans(const DesEvent& selfTransEvent) const;
			void onSelfTransRemoved(const DesEvent& selfTransEvent) const;
			void onTransChanged(const DesTransition& trans, const DesTransition& change) const;

		//Data__________________________________________
		private:
			DesType m_type;

			//the name of the automaton
			std::wstring	  m_name;

			//the integrity status of the automaton
			mutable Integrity  m_integStatus;

			//The date-time stamp of the integrity check
			mutable std::wstring m_integStamp;

			//DES is or not non-blocking
			mutable NonBlockingProp m_nonBlockProp;

			//The date-time stamp of the non-blocking check
			mutable std::wstring m_nonBlockStamp;

			//DES is or not reachable
			mutable ReachableProp m_reachableProp;

			//The date-time stamp of the reachability check
			mutable std::wstring m_reachableStamp;

			//the pool of states
			StatePool* m_pStatePool;

			//initial state of the automaton
			const DesState* m_pInitialState;

			//the pool of events
			EventPool* m_pEventPool;

			//the transition function
			DesTransitionFunction* m_pTransFunc;

			//The owner of this DES (could be a subsystem, an interface or null)
			union Owner
			{
				const DesSubsystem*  subsys;
				const DesInterface* interf;
			};

			Owner m_owner;

			//the name of the file the DES is comming from (if it was loaded from a file);
			std::wstring m_fileName;

			//true when the DES is loaded with delay meaning m_fileName points to the file
			//where DES is to be loaded from but the load has not been perfomed yet
			bool m_delayLoad;

			//the des has been modified since last saved
			mutable bool m_isModified;

			//the list of listners interested in receiving notifications from DES
			std::vector<DesNotifications*> m_desListeners;

			static NameValidator m_nameValidator;

			GedInfo m_gedInfo;
};

} //end of namespace DESpot
