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

#include "CommonDefinitions.h"
#include "Iterator.h"
#include "DesNotifications.h"
#include "DesTypes.h"

namespace DESpot
{
	class Des;
	class ProjectEventPool;

	class DesInterface
	{
		//Types____________________________________________________
		public:
			//Des iterator
			typedef Iterator<Des&, const Des&> DesIterator; 
			typedef std::auto_ptr<DesIterator> DesIteratorPtr;

		public:
			DesInterface(const std::wstring& name, ProjectEventPool& eventPool);
			virtual ~DesInterface(void);

		//Interface properties________________________________________	
		public:
			//The name of the subsystem
			std::wstring getName() const;
			void setName(const std::wstring& name);

			bool isValid() const;
			void setValid(bool setValid = true) const;
			void clearValid() const;
			Integrity getValidProp() const;


			//Read/write the interface consistency property of this interface
			bool isInterfConsist() const;
			void setInterfConsist(bool isIConsist = true) const;
			void clearInterfConsist() const;
			IConsistProp getIConsistProp() const;

		public:
			//Returns the sync product of the all the DES components. If it needs to be 
			//calculated it calculates it
			Des& getSyncDes() const;

			//Invalidates the sync product if it was computed already such that next time
			//a client asks for it a new one is produced. Used primarly when the interface is modified
			//Deep cleaning will also clean the DES components. Non-deep cleaning will only clean
			//the properties of the interface
			void clean(bool deepClean = true);

		//Access to DES components _________________________________________
		public:		
			Des& getDes(const std::wstring& desName);
			const Des& getDes(const std::wstring& desName) const;			
			
			//Create an iterator that goes through all the internal DES of this interface
			DesIteratorPtr createDesIterator() const;

			int getDesCount() const;

		//Editing the DES components______________________________________
		public:
			void addDes(Des* pDes);

			void changeDesName(Des& des, const std::wstring& newDesName);

			//Event sync from when a name of a DES that is part of this interface is changed using
			//the DES itself instead of the changeDesName(...) method. In this case the name  of 
			//the DES has already been changed but the interface's internal maps reference it by the old name
			//It is these internal maps that need to be updated
			void onDesNameChanged(Des* des, const std::wstring& oldName, const std::wstring& newName); 

			void deleteDes(const std::wstring& desName);

			bool findDes(const std::wstring& desName, Des** out_pDes = null);
			bool findDes(const std::wstring& desName, const Des** out_pDes = null) const;

			
		//serializer access
		public:
			void setLoadInProgress(bool loadInProgress = true);

		//Implementation types	
		private:
			typedef std::map<std::wstring, Des*> DesMap;
			typedef DesMap::iterator DesMapIt;
			typedef DesMap::const_iterator DesMapCIt;

		//Implementaiton methods
		private:
			void sinkDesEvents(Des* des);
			void removeDesSink(Des* des);

		private:
			//The name of the interface
			std::wstring m_name;

			//True if the subsystem is valid (all integrity checks for this subsystem are successful)
			mutable Integrity m_isValid;

			//The consistency of the interface: true if this is was verified to be an LD interface
			mutable IConsistProp m_isInterfConsist;

			//The list (actually a map) of DES that make up this interface
			DesMap m_desMap;

			//The synchronized product of all the DES components
			mutable Des* m_syncDes;

			//The event pool of the project this subsystem belong to
			ProjectEventPool& m_eventPool;	

			//True when the serializer is loading the interface
			bool m_bLoadInProgress;

			//the list of sinks from all DES of the interface
			class DesNotificationSink;
			std::vector<DesNotificationSink*> m_desNotifSinks;

		//__________________________________________________________________________________________________________
	
		private: class DesNotificationSink : private DesNotifications
		{
			public:
				DesNotificationSink(DesInterface* interf, Des* source) : 
                                        m_interf(*interf), m_des(source)
				{
					m_desListenerId = m_des->subscribe(this);
				}
					
                                virtual ~DesNotificationSink()
				{
					//can't unsubscribe here because all DES could be already destroyed if the project was closed
				}
				
				Des* des() { return m_des; }

				void unsubscribe()
				{
					m_des->unsubscribe(m_desListenerId);
				}

			private:
				virtual void onNameChanged(const std::wstring& oldName, const std::wstring& newName) {m_interf.onDesNameChanged(m_des, oldName, newName);}
				virtual void onStateAdded(const DesState& /*addedState*/) { m_interf.clean();}
				virtual void onStateChanged(const DesState& /*changedState*/) { m_interf.clean();}
				virtual void onRemovingState(const DesState& /*state*/) { m_interf.clean();}
				virtual void onEventAdded(const DesEvent& /*addedEvent*/) { m_interf.clean();}
				virtual void onEventChanged(const DesEvent& /*changedEvent*/){ m_interf.clean();}
				virtual void onEventRemoved(const DesEvent::ID& /*eventId*/) { m_interf.clean();}
				virtual void onTransitionAdded(const DesTransition& /*addedTrans*/) { m_interf.clean();}
				virtual void onGlobalSelfTransitionAdded(const DesEvent& /*selfTransEvent*/) { m_interf.clean();}
				virtual void onTransitionChanged(const DesTransition& /*trans*/, const DesTransition& /*change*/) { m_interf.clean();}
				virtual void onTransitionRemoved(const DesTransition& /*removedTrans*/) { m_interf.clean();}
				virtual void onSelfTransitionRemoved(const DesEvent& /*selfTransEvent*/) { m_interf.clean();}

			private:
				DesInterface& m_interf;

				Des* m_des;
				
				unsigned int m_desListenerId;
		};

	};

}; //end of namespace DESpot
