/*	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 <QString>
#include <QtXml/QXmlDefaultHandler>
#include "DesProject.h"
#include "DesFlatProject.h"
#include "DesHierProject.h"
#include "DesSubsystem.h"
#include "DesInterface.h"


class XmlWriter;


namespace DESpot
{
	class SerializerAccess;
	class HierSerializerAccess;

	//This class is used to save projects to XML files and load them from files.
	class ProjectSerializer : private QXmlDefaultHandler
	{
		public:
			ProjectSerializer();
			ProjectSerializer(DesProject& project);
			virtual ~ProjectSerializer(void);

		public:
			DesProject* load(const std::wstring& fileName);
			void save(const std::wstring& fileName);

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


			void configure(ProjSerializerAccess* projAccess);

		//Implementationt types
		private:		
			enum DesType
			{
				eNone,
				eSubsysSupDes,
				eSubsysPlantDes,
				eInterfaceDes
			};

			enum InterfRefType 
			{
				eImplInterface,
				eUsesInterface
			};

			struct SubsysDependency
			{
				SubsysDependency(DesSubsystem* subsys, const DesSubsystem::DependencyRef& dependRef):
					dependRef(dependRef)
				{
					this->subsys = subsys;
					//this->dependRef = dependRef;
				}

				DesSubsystem* subsys;
				DesSubsystem::DependencyRef dependRef;
			};

			struct InterfImpl
			{				
				DesSubsystem* subsys;
				std::wstring  interfName;

				InterfImpl(DesSubsystem* subsys, const std::wstring& interfName)
				{
					this->subsys = subsys;
					this->interfName = interfName;
				}
			};

		//Parsing (loading) overridables from QXmlDefaultContentHandler
		private:
			//the parsing is starting
			virtual bool startDocument();
			virtual bool endDocument();

			//element and attribute parsing
			virtual bool startElement(const QString& namespaceURI, const QString& localName, 
									  const QString& qName, const QXmlAttributes& atts);

			virtual bool endElement(const QString& namespaceURI, const QString& localName, 
									  const QString& qName);

			//error handling
			virtual bool warning(const QXmlParseException& exception);
			virtual bool error(const QXmlParseException& exception);
			virtual bool fatalError(const QXmlParseException& exception);

		//Implementation methods
		private:
			void createProject(ProjectType projType, QString projName);

			DesFlatProject* flatProject();
			DesHierProject* hierProject();
			HierSerializerAccess* hierProjAccess();

			bool isHeaderTag(const QString& tagName);
			bool isSubsystemTag(const QString& tagName);
			bool isInterfaceTag(const QString& tagName);
			bool isDesTag(const QString& tagName);

			//reading methods
			bool readProjectRoot(const QString& tagName, const QXmlAttributes& atts);
			bool readProjectDefinition(const QString& tagName, const QXmlAttributes& atts);
			bool readProjectHeader(const QString& tagName, const QXmlAttributes& atts);
			bool readSubsystem(const QString& tagName, const QXmlAttributes& atts);
			bool readInterface(const QString& tagName, const QXmlAttributes& atts);
			bool readDes(const QString& tagName, const QXmlAttributes& atts);

			//writing methods
			void writeProjDefinition(XmlWriter& xw);
			void writeProjHeader(XmlWriter& xw);
			void writeProjSubsystems(XmlWriter& xw, bool includeRoot = true);
			void writeSubsystem(XmlWriter& xw, const DesSubsystem& subsys);
			void writeProjInterfaces(XmlWriter& xw);
			void writeInterface(XmlWriter& xw, const DesInterface& interf);

			//helper methods
			ProjectType getProjectType(const QString& projTypeName);
			QString			 getProjectType();

			Integrity getProjIntegrity(const QString& integStatusName);
			QString				  getProjIntegrity();

			ControllableProp getCtrlProp(const QString& ctrlPropName);
			QString						 getCtrlProp();
			
			NonBlockingProp getNonBlockProp(const QString& nonBlockPropName);
			QString						getNonBlockProp();

			IConsistProp getProjIConsist(const QString& iConsName);
			QString					     getProjIConsist();

			LwNonBlockProp getLwNonBlockProp(const QString& lwNonBlockPropName);
			QString			  		   getLwNonBlockProp();

			LwCtrlProp getLwCtrlProp(const QString& lwCtrlPropName);
			QString				   getLwCtrlProp();

			QString getLevelValue(const DesSubsystem& subsys);

			bool getSubsysLwCtrlProp(const QString& lwCtrlPropName);
			QString getSubsysLwCtrlProp(const DesSubsystem& subsys);

			bool getSubsysLwNonBlockProp(const QString& lwNonBlockPropName);
			QString getSubsysLwNonBlockProp(const DesSubsystem& subsys);
			
			bool getSubsysIConsistProp(const QString& iConsistPropName);
			QString getSubsysIConsistProp(const DesSubsystem& subsys);

			bool getInterfIConsistProp(const QString& iConsistPropName);
			QString getInterfIConsistProp(const DesInterface& interf);

			bool getSubsysValidStatus(const QString& validStatusName);
			QString getSubsysValidStatus(const DesSubsystem& subsys);

			bool getInterfValidStatus(const QString& validStatusName);
			QString getInterfValidStatus(const DesInterface& interf);

			void setProjectProperties();
			
			void resolveInterfImplementations();
			void resolveSubsysDependencies();

			QString toString(int intVal);
			QString toString(const std::wstring stdStr);

			QString convertToRelative(const QString& desFileName);
			QString convertToAbsolute(const QString& desRelativeFileName);

		private:
			//The file name from / to where we read / write
			QString m_fileName;

			//The project being loaded or saved. 
			DesProject* m_project;
			ProjSerializerAccess* m_projectAccess;

			//The subsystem curently being loaded
			DesSubsystem* m_crtSubsys;

			//The interface currently being loaded
			DesInterface* m_crtInterf;

			//The type of DES currently being read
			DesType m_readingDesType;

			//The type of interface references currently being read: implemented or used by subsystems
			InterfRefType m_readingInterfRefType;

			//Data parsed with SAX
			QString	   m_projFileVer;
			
			//if an error occurred while parsing this object will contain the error information
			QXmlParseException* m_pError;

		//The properties of the project being loaded. They are stored here when parsing
		//because they need to be set after the project has been fully created and initialized;
		//when things are added to the project in the process of loading it the properties are being
		//reset since the project is changing; Thus they are saved here at the beginning of the parsing
		//and then when everything is loaded they are set in the project
		private:
				Integrity   m_integStatus;
				std::wstring			m_integDateStamp;

				NonBlockingProp m_nonBlockStatus;
				std::wstring			    m_nonBlockDateStamp;

				ControllableProp m_ctrlStatus;
				std::wstring				 m_ctrlDateStamp;

				IConsistProp m_iConsStatus;
				std::wstring			     m_iConsDateStamp;

				LwNonBlockProp m_lwNonBlockStatus;
				std::wstring				   m_lwNonBlockDateStamp;

				LwCtrlProp m_lwCtrlStatus;
				std::wstring			   m_lwCtrlDateStamp;

		//Subsystems and interfaces are interdpendent hierarhically and thus
		//they cannot be set at loading time since the loading is sequencial
		//(when reading the subsystems we don't have the interfaces yet). Thus
		//all dependencies must be set at end of the loading when all subsystems
		//and interfaces have been created and added to the project
		private:
			//A list of unresolved dependencies between subsystems
			std::vector<SubsysDependency> m_unresDepends;

			//A list of unresolved interface implementations
			std::vector<InterfImpl> m_unresImpls;

			

		//Tags, Attribute and values used in the XML file
		private:
			static const QString cProjRootTag;
			static const QString cProjFileVerAttr;
			static const QString cProjFileVerVal;

			static const QString cProjHeaderTag;
			static const QString cProjNameAttr;
			static const QString cProjTypeAttr;
			static const QString cProjTypeFlatVal;
			static const QString cProjTypeHierVal;
			static const QString cProjDegreeAttr;

			static const QString cProjIntegrityTag;
			static const QString cProjIntegStatusAttr;
			static const QString cProjIntegStatusYesVal;
			static const QString cProjIntegStatusNoVal;
			static const QString cProjIntegStatusNotVerifVal;
			static const QString cProjIntegStampAttr;
			
			static const QString cProjNonBlockTag;
			static const QString cProjNonBlockStatusAttr;
			static const QString cProjNonBlockPropYesVal;
			static const QString cProjNonBlockPropNoVal;
			static const QString cProjNonBlockPropNotVerifVal;
			static const QString cProjNonBlockStampAttr;

			static const QString cProjCtrlTag;
			static const QString cProjCtrlStatusAttr;
			static const QString cProjCtrlPropYesVal;
			static const QString cProjCtrlPropNoVal;
			static const QString cProjCtrlPropNotVerifVal;
			static const QString cProjCtrlStampAttr;

			static const QString cProjIConsTag;
			static const QString cProjIConsStatusAttr;
			static const QString cProjIConsPropYesVal;
			static const QString cProjIConsPropNoVal;
			static const QString cProjIConsPropNotVerifVal;
			static const QString cProjIConsStampAttr;

			static const QString cProjLwNonBlockTag;
			static const QString cProjLwNonBlockStatusAttr;
			static const QString cProjLwNonBlockPropYesVal;
			static const QString cProjLwNonBlockPropNoVal;
			static const QString cProjLwNonBlockPropNotVerifVal;
			static const QString cProjLwNonBlockStampAttr;

			static const QString cProjLwCtrlTag;
			static const QString cProjLwCtrlStatusAttr;
			static const QString cProjLwCtrlPropYesVal;
			static const QString cProjLwCtrlPropNoVal;
			static const QString cProjLwCtrlPropNotVerifVal;
			static const QString cProjLwCtrlStampAttr;

			static const QString cSubsysTag;
			static const QString cSubsysNameAttr;
			static const QString cSubsysLevelAttr;
			static const QString cSubsysValidStatusAttr;
			static const QString cSubsysValidStatusYesVal;
			static const QString cSubsysValidStatusNoVal;
			static const QString cSubsysLwCtrlProp;
			static const QString cSubsysLwCtrlYesVal;
			static const QString cSubsysLwCtrlNoVal;
			static const QString cSubsysLwNonBlockProp;
			static const QString cSubsysLwNonBlockYesVal;
			static const QString cSubsysLwNonBlockNoVal;
			static const QString cSubsysIConsistProp;
			static const QString cSubsysIConsistYesVal;
			static const QString cSubsysIConsistNoVal;
			
			static const QString cSubsysImplTag;
			
			static const QString cInterfaceTag;
			static const QString cInterfRefTag;
			static const QString cInterfNameAttr;
			static const QString cInterfProviderAttr;
			static const QString cInterfValidStatusAttr;
			static const QString cInterfValidStatusYesVal;
			static const QString cInterfValidStatusNoVal;
			static const QString cInterfIConsistProp;
			static const QString cInterfIConsistYesVal;
			static const QString cInterfIConsistNoVal;

			static const QString cSubsysSupDesTag;
			static const QString cSubsysPlantDesTag;
			
			static const QString cSubsysUsesTag;
			

			static const QString cDesTag;
			static const QString cDesNameAttr;
			static const QString cDesLocationAttr;
	};

} //namespace DESpot
