/*	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

#ifndef __DES_PROJECT_H__
#define __DES_PROJECT_H__


#include <string>
#include <vector>
#include <memory>

#include "NameValidator.h"
#include "DesSubsystem.h"

namespace DESpot
{
	class Des;
	class DesInterface;
	class DesProjectNotifications;
	class ProjectIndex;
	class ProjectEventPool;
	class ProjectEvent;
	class ProjIntegrityAlgo;
	class ControllabilityAlgo;
	class NonBlockingAlgo;
	class ProjectSerializer;
	class MultiNonBlockingAlgo;
	class MultiCtrlAlgo;

	class EventPoolAccess
	{
		public:
			virtual void onProjectEventPoolChanged() = 0;
	};

	class ProjSerializerAccess
	{
		public:
			virtual void setLoadInProgress(bool loadInProgress = true) = 0; 			

			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 setControllableProp(int ctrlProp) = 0; 
			virtual void setCtrlStamp(const std::wstring& ctrlStamp) = 0; 
	
			virtual ProjectEventPool& getEventPool() = 0;
	};

	class DesProject : protected EventPoolAccess, virtual protected ProjSerializerAccess
	{
		//Types
		public:
			typedef DesSubsystem::DesIterator DesIterator;
			typedef DesSubsystem::DesIteratorPtr DesIteratorPtr;
			
			typedef Iterator<ProjectEvent&, const ProjectEvent&> EventIterator;
			typedef std::auto_ptr<EventIterator> EventIteratorPtr;

		public:
			DesProject(const std::wstring& name, ProjectType type);
			virtual ~DesProject(void);

		//Serialization
		public:
			//The loading method is static because it will create the project type depending 
			//on the file contents
			static DesProject* load(const std::wstring& fileName);
			
			//Used by the serializer itself to gain access to the SerializerAccess interface
			void configureSerializer(ProjectSerializer* serializer);
			
			//Save method doesn't need to be static as it saves the contents of a particular object
			//that already exists. You can either save from scratch giving a file name or re-save
			//with the file name project is saved under (if any)
			void save(const std::wstring& fileName);
			void save();

			// added by rjl - remove when bddhisc
			// integrated with despot 
			void exportToBDDhisc(const std::wstring& fileName);
			//  remove to here - RJL

			// added by rjl - remove when bddsd
			// integrated with despot 
			void exportToBDDsd(const std::wstring& fileName);
			//  remove to here - RJL




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

		//Project properties
		public:
			//The name of the project
			std::wstring getName() const;
			void setName(const std::wstring& name);

			bool isNew() const;
			std::wstring getFileName() const;
			//setFileName is protected
			
			//The type of project (can only be read. It is set by the actual type of object created
			ProjectType getType() const;

			//Project's integrity status
			bool		 isValid() const;
			Integrity	 getIntegrity() const;
			std::wstring getIntegrityStamp() const;
			virtual bool checkIntegrity(ProjIntegrityAlgo& integAlgo);

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

			//Controllability
			bool	         isControllable() const;
			ControllableProp getControllableProp() const;
			std::wstring	 getCtrlStamp() const;
			virtual bool	 checkControllable(MultiCtrlAlgo& ctrlAlgo);


			//Resets all properties and all incremental data calculated for them
			//so that they can be rechecked from scratch
			//Deep cleaning will also clean the DES components. Non-deep cleaning will only clean
			//the properties of the project
			virtual void clean(bool deepClean = true);

		//Project Event Pool	
		public:
			EventIteratorPtr createProjEventIterator() const;
			void changeEvent(std::wstring eventName, const DesEvent& newEvent);

		//Des information
		public:
			bool hasRootSubsys() const;
			DesSubsystem& getRootSubsys() const;

			//returns the number of supervisor DES in the project
			int getSupDesCount();

			//returns the number of plant DES in the project
			int getPlantDesCount();

			//Create an iterator that goes through all the internal Des of this project
			virtual DesIteratorPtr createDesIterator() const;
			virtual DesIteratorPtr createDesIterator();

			//Create an iterator that goes through either the plant or the supervisor Des
			virtual DesIteratorPtr createDesIterator(DesLevel desLevel) const;
			virtual DesIteratorPtr createDesIterator(DesLevel desLevel);
		
			//Returns the flat system DES: a sync product of all the DES in the project
			//If the flat system DES needs to be calculated it will be calculated and cached
			virtual Des& getFlatSystemDes() const;

		//Des operations
		public:
			virtual void changeDesName(Des& des, const std::wstring& newDesName) = 0;
			virtual void revertDesToFile(Des& des);
			virtual void deleteDes(const std::wstring& desName) = 0;

		//General operations
		public:
			bool findName(const std::wstring& name) const;
			bool findName(const std::wstring& name, ProjectCompType& out_projCompType) const;

		//Notification management_______________________
		public:
			//The return is a cookied that must be used when unsubscribing
			unsigned int subscribe(DesProjectNotifications* pNotifListner);
			void unsubscribe(unsigned int cookie);

		//Serializer access
		protected:
			virtual void setLoadInProgress(bool loadInProgress = true);
			void setIntegrity(int integStatus); 
			void setIntegrityStamp(const std::wstring& integStamp); 
			void setNonBlockingProp(int nonBlockProp); 
			void setNonBlockingStamp(const std::wstring& nonBlockStamp);
			void setControllableProp(int ctrlProp); 
			void setCtrlStamp(const std::wstring& ctrlStamp); 
			ProjectEventPool& getEventPool();

		//Notification implementation methods
		protected:
			void onProjectNameChanged(const std::wstring& newName, const std::wstring& oldName);
			void onCtrlStatusChanged();
			void onIntegStatusChanged();
			void onNonBlockStatusChanged();
			void onDesAdded(const Des& addedDes, DesLevel desLevel);
			void onRemovingDes(const Des& des, DesLevel desLevel);
			void onDesRemoved(const std::wstring& desName, DesLevel desLevel);
			void onDesNameChanged(const Des& des, const std::wstring& oldName);
			void onProjectEventPoolChanged();
			void onProjectCleaned();

		//Other implementation methods
		protected:
			void setFileName(const std::wstring& fileName);

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

		protected:
			//The name of the project
			std::wstring m_name;

			//The file name where the project was loaded from
			std::wstring m_fileName;

			//The type of the project. Set when the project is created. Cannot be changed
			const ProjectType m_type;

			//Project is or not non-blocking
			NonBlockingProp m_nonBlockProp;

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

			//Project is or not controllable
			ControllableProp m_ctrlProp;

			//The date-time stamp of the controllability check
			std::wstring m_ctrlStamp;

			//the integrity status of the automaton
			Integrity  m_integStatus;

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

			//The root subsystem of the project. All projects have a root subsystems. Flat project
			//only have the root subsystem which has not dependent subsystems. For HISC projects
			//the root subsystem will contain dependencies on lower-level subsystems
			DesSubsystem* m_pRootSubsys;

			//The list of project events
			ProjectEventPool* m_eventPool;

			//the project has been modified since last saved
			bool m_isModified;

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

			//the name index of all project components
			ProjectIndex& m_nameIndex;

			static NameValidator m_nameValidator;

			//true while project is being loaded
			bool m_bLoadInProgress;
	};
} //end of namespace DESpot

#endif //__DES_PROJECT_H__
