/*	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"
#include "TemplateNameParser.h"
//#include "InstantiateTemplate.h"

//for debug
// #include <iostream>

namespace DESpot
{
	//class TemplateNameParser;
	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;

//add by bini
			bool m_isTemplate;
			bool m_isInstantiation;
			bool m_isInstantiated;
                        // added to keep count of number of
			// instantations added to a template DES.
			// Used with setInstantiated fcn to
			// increment or decrement
                        unsigned long m_instantiationCount; 
			std::wstring m_parentsystemname; 

			bool isTemplate() const { return m_isTemplate;}
			void setTemplate(bool is_Template)
			{m_isTemplate=is_Template;}

			bool isInstantiated() const {return m_isInstantiated;}
                        // this function also keeps track of the
                        // number of instantations. m_instantiationCount is
                        // incremented when called with "true" and
                        // decremented (min 0) when called with false
			// it would be good to make this more robust
			void setInstantiated(bool is_Instantiated)
			{ 
			  //for debug
			  //std::cout << "m_instantiationCount is:"<< m_instantiationCount <<  ".\n";
			  if (is_Instantiated) {
			    m_instantiationCount++;
			    m_isInstantiated = true;
			  } else if (m_instantiationCount <= 1){
                            m_instantiationCount = 0;
			    m_isInstantiated = false;
			  } else {
			    m_instantiationCount--;
			    m_isInstantiated = true;
			  }
			  //for debug
			  //std::cout << "m_instantiationCount is now:"<< m_instantiationCount <<  ".\n";
			}			
			bool isInstantiation() const {return m_isInstantiation;}
			void setInstantiation(bool is_Instantiation)
			{m_isInstantiation=is_Instantiation;}
			Des* getInstantiatedTemplate() const
			{if(m_isInstantiation&&m_isTemplate==false){return m_template;}return null;}
			void setInstantiatedTemplate(Des* const temp){m_template=temp;}
//? delete const zuihou
			Des* instantiateDesfromTemplate(const TemplateNameParser::TemplateParameter* temp) ;
			TemplateNameParser::TemplateParameter* getParameter() const{return m_parameter;}
			void setParameter(TemplateNameParser::TemplateParameter* parameter){m_parameter=parameter;}
			void setDlgName(std::wstring& dlgname){m_instinfodlgname=dlgname;}
			std::wstring getDlgName() const {return m_instinfodlgname;}
 			void setParentSystemName(std::wstring name){m_parentsystemname=name;}
			std::wstring getParentSystemName() const {return m_parentsystemname;} 
			DesLevel getLevel()const {return m_level;}
			void setLevel(DesLevel level)
			{ 
				m_level=level;
				if (m_level==eTemplateDes)
				{
					m_isTemplate=true;
				}
			}
			


			
//bini

			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);
//modified by bini

			void revertGedToDes(Des& des);
			
			//Extraction system method to load clone des
			void loadCloneDes(const Des& existingDes,std::map<std::wstring, bool> &tmp_changedEventsMap,const bool isChildInterf, const bool isInterfAboveHigh);
		//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,bool is_temp=false);

			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(); }

//add by bini
			const DesEvent& onRecordEvent(const DesEvent& event);
		//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;
			
//add by bini
			

		//Data__________________________________________
		private:
			DesType m_type;
	
//add by bini
			Des* m_template;

			TemplateNameParser::TemplateParameter* m_parameter;
			
			DesLevel m_level;
			
			static std::wstring m_instinfodlgname;
			

			//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;
			
//add by bini
			static NameValidator m_nameValidator2;

			GedInfo m_gedInfo;
};


} //end of namespace DESpot
