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

#include "BddSdChkInfo.h"
//#include "ProjectEditor.h"
#include "ProjectEvent.h"
//#include "InstantiateTemplate.h"
//#include "Instantiation.h"


namespace DESpot
{
	class Des;
	class Instantiation;
	class DesState;
	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 QMultiMap<unsigned long, const ProjectEvent*> ProjectEventSet;

			typedef DesSubsystem::InstIterator InstIterator;
			typedef DesSubsystem::InstIteratorPtr InstIteratorPtr;
			
			typedef Iterator<ProjectEvent&, const ProjectEvent&> EventIterator;
			typedef std::auto_ptr<EventIterator> EventIteratorPtr;
			typedef std::map<Des*,DesState*> SimStateTuple;

			enum DebugModes
			{
				Uninitialized,
				CounterExample,
				ErrorTuple,
				Reset
			};

		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

			//extractionSystem method calledfrom HierProjEditor
			DesProject* extractionSystem(const DesSubsystem* node);



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

#ifdef __ENABLE_BDD__
			void              procBddNonBlockProp(BDDSD::SD_ChkInfo& checkInfo); 
#endif

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

#ifdef __ENABLE_BDD__
			void              procBddCtrlProp(BDDSD::SD_ChkInfo& checkInfo); 
#endif

			//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);
			void setSuccessful(bool flag);
			bool isSuccessful();

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

			int getTemplateDesCount();

			//  added so that code that does not support
			//  DES templates can detect projects with
			//  them
			bool hasDesInstantiations() const;

			//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);

			virtual InstIteratorPtr createInstIterator() const;
			virtual InstIteratorPtr createInstIterator();
		
			//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;
			virtual void deleteInstantiation(const std::wstring& instName)=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
		public:
			void onProjectNameChanged(const std::wstring& newName, const std::wstring& oldName);
			void onCtrlStatusChanged();
			void onIntegStatusChanged();
			void onNonBlockStatusChanged();
			void onDesAdded(const Des& addedDes, DesLevel desLevel);
//add by bini
			void onInstAdded(Instantiation& addedInst,const Des& template_crt);
			void onRemovingDes(const Des& des, DesLevel desLevel);
//add by bini
			void onRemovingInstantiation(const Instantiation& inst);
			void onDesRemoved(const std::wstring& desName, DesLevel desLevel);
//add by bini
			void onInstantiationRemoved(const std::wstring& instName);
			void onDesNameChanged(const Des& des, const std::wstring& oldName);
			void onProjectEventPoolChanged();
			void onProjectCleaned();

		//Other implementation methods
		//
			public:
			void setFileName(const std::wstring& fileName);
			protected:
			//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;

			bool inst_successful;

			// Added by zain for Counter example generation
			private:
				SimStateTuple m_SimulationErrorTuple;
				ProjectEventSet m_CounterExample;
				DesProject* m_DummyProject;
				DesProject* m_SubSystemDummyProject;
				bool isProjectCHK;	
				DebugModes m_SimulationType;
			public:
				inline SimStateTuple& getSimulationErrorTuple(){return m_SimulationErrorTuple;}
				void setSimulationErrorTuple(SimStateTuple& in_tuple);

				inline ProjectEventSet& getCounterExample(){return m_CounterExample;}
				void setCounterExample(const ProjectEventSet& in_CounterExample);

				inline DesProject* getDummyProject(){return m_DummyProject;}
				void setDummyProject(DesProject*);

				void delete_prev_dummy_project();
				
				inline DesProject* getSubsysDummyProject(){return m_SubSystemDummyProject;}
				inline void setSubsysDummyProject(DesProject* in_DummyProject){ m_SubSystemDummyProject = in_DummyProject;}

				inline void setProjectChkFlag(bool in_flag){isProjectCHK=in_flag;}
				inline bool getProjectChkFlag(){return isProjectCHK;}

				inline void setDebugMode(DebugModes in_type){m_SimulationType=in_type;}
				inline DebugModes getDebugMode(){return m_SimulationType;}
	};
} //end of namespace DESpot

#endif //__DES_PROJECT_H__
