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

#include <QVariant>
#include <QFileInfo>
#include <QDir>

#include "ProjectSerializer.h"
#include "DesFlatProject.h"
#include "DesHierProject.h"
#include "Des.h"
#include "xmlwriter.h"

// added by rjl - remove when bddhisc
// integrated with despot 

#include "ProjectEvent.h"



namespace DESpot
{

const QString ProjectSerializer::cProjRootTag = "Project";
const QString ProjectSerializer::cProjFileVerAttr = "projVer";
const QString ProjectSerializer::cProjFileVerVal = "1.0.0";

const QString ProjectSerializer::cProjHeaderTag = "Header";
const QString ProjectSerializer::cProjNameAttr = "name";
const QString ProjectSerializer::cProjTypeAttr = "type";
const QString ProjectSerializer::cProjTypeFlatVal = "flat";
const QString ProjectSerializer::cProjTypeHierVal = "HISC";
const QString ProjectSerializer::cProjDegreeAttr = "degree";

const QString ProjectSerializer::cProjIntegrityTag = "Integrity";
const QString ProjectSerializer::cProjIntegStatusAttr = "status";
const QString ProjectSerializer::cProjIntegStatusYesVal = "yes";
const QString ProjectSerializer::cProjIntegStatusNoVal = "no";
const QString ProjectSerializer::cProjIntegStatusNotVerifVal = "not-verified";
const QString ProjectSerializer::cProjIntegStampAttr =  "date-stamp";

const QString ProjectSerializer::cProjNonBlockTag = "Nonblocking";
const QString ProjectSerializer::cProjNonBlockStatusAttr = "status";
const QString ProjectSerializer::cProjNonBlockPropYesVal = "yes";
const QString ProjectSerializer::cProjNonBlockPropNoVal = "no";
const QString ProjectSerializer::cProjNonBlockPropNotVerifVal = "not-verified";
const QString ProjectSerializer::cProjNonBlockStampAttr = "date-stamp";

const QString ProjectSerializer::cProjCtrlTag = "Controllable";
const QString ProjectSerializer::cProjCtrlStatusAttr = "status";
const QString ProjectSerializer::cProjCtrlPropYesVal = "yes";
const QString ProjectSerializer::cProjCtrlPropNoVal = "no";
const QString ProjectSerializer::cProjCtrlPropNotVerifVal = "not-verified";
const QString ProjectSerializer::cProjCtrlStampAttr = "date-stamp";

const QString ProjectSerializer::cProjIConsTag = "I-Consistent";
const QString ProjectSerializer::cProjIConsStatusAttr = "status";
const QString ProjectSerializer::cProjIConsPropYesVal = "yes";
const QString ProjectSerializer::cProjIConsPropNoVal = "no";
const QString ProjectSerializer::cProjIConsPropNotVerifVal = "not-verified";
const QString ProjectSerializer::cProjIConsStampAttr = "date-stamp";

const QString ProjectSerializer::cProjLwNonBlockTag = "LW-Nonblocking";
const QString ProjectSerializer::cProjLwNonBlockStatusAttr = "status";
const QString ProjectSerializer::cProjLwNonBlockPropYesVal = "yes";
const QString ProjectSerializer::cProjLwNonBlockPropNoVal = "no";
const QString ProjectSerializer::cProjLwNonBlockPropNotVerifVal = "not-verified";
const QString ProjectSerializer::cProjLwNonBlockStampAttr = "date-stamp";

const QString ProjectSerializer::cProjLwCtrlTag = "LW-Controllable";
const QString ProjectSerializer::cProjLwCtrlStatusAttr = "status";
const QString ProjectSerializer::cProjLwCtrlPropYesVal = "yes";
const QString ProjectSerializer::cProjLwCtrlPropNoVal = "no";
const QString ProjectSerializer::cProjLwCtrlPropNotVerifVal = "not-verified";
const QString ProjectSerializer::cProjLwCtrlStampAttr = "date-stamp";

const QString ProjectSerializer::cSubsysTag = "Subsystem";
const QString ProjectSerializer::cSubsysNameAttr = "name";
const QString ProjectSerializer::cSubsysLevelAttr = "level";
const QString ProjectSerializer::cSubsysValidStatusAttr = "valid";
const QString ProjectSerializer::cSubsysValidStatusYesVal = "yes";
const QString ProjectSerializer::cSubsysValidStatusNoVal = "no";
const QString ProjectSerializer::cSubsysLwCtrlProp = "lw-ctrl";
const QString ProjectSerializer::cSubsysLwCtrlYesVal = "yes";
const QString ProjectSerializer::cSubsysLwCtrlNoVal = "no";
const QString ProjectSerializer::cSubsysLwNonBlockProp = "lw-non-blocking";
const QString ProjectSerializer::cSubsysLwNonBlockYesVal = "yes";
const QString ProjectSerializer::cSubsysLwNonBlockNoVal = "no";
const QString ProjectSerializer::cSubsysIConsistProp = "i-consist";
const QString ProjectSerializer::cSubsysIConsistYesVal = "yes";
const QString ProjectSerializer::cSubsysIConsistNoVal = "no";

const QString ProjectSerializer::cSubsysImplTag = "Implements";

const QString ProjectSerializer::cInterfaceTag = "Interface";
const QString ProjectSerializer::cInterfRefTag = "InterfaceRef";
const QString ProjectSerializer::cInterfNameAttr = "name";
const QString ProjectSerializer::cInterfProviderAttr = "provider";
const QString ProjectSerializer::cInterfValidStatusAttr = "valid";
const QString ProjectSerializer::cInterfValidStatusYesVal = "yes";
const QString ProjectSerializer::cInterfValidStatusNoVal = "no";
const QString ProjectSerializer::cInterfIConsistProp = "i-consist";
const QString ProjectSerializer::cInterfIConsistYesVal = "yes";
const QString ProjectSerializer::cInterfIConsistNoVal = "no";

const QString ProjectSerializer::cSubsysSupDesTag = "Supervisor";
const QString ProjectSerializer::cSubsysPlantDesTag = "Plant";

const QString ProjectSerializer::cSubsysUsesTag = "Uses";


const QString ProjectSerializer::cDesTag = "Des";
const QString ProjectSerializer::cDesNameAttr = "name";
const QString ProjectSerializer::cDesLocationAttr = "location";


//_________________________________________________________________________________________________

ProjectSerializer::ProjectSerializer() : 
		m_project(null), 
		m_crtSubsys(null),
		m_crtInterf(null),
		m_readingDesType(eNone),
		m_pError(null),
		m_integStatus(eIntegNotVerified),
		m_nonBlockStatus(eNonBlockNotVerified),
		m_ctrlStatus(eCtrlNotVerified),
		m_iConsStatus(eIConsNotVerified),
		m_lwNonBlockStatus(eLwNonBlockNotVerified),
		m_lwCtrlStatus(eLwCtrlNotVerified)
{
}

//_________________________________________________________________________________________________

ProjectSerializer::ProjectSerializer(DesProject& project) : 
		m_project(&project), 
		m_crtSubsys(null),
		m_crtInterf(null),
		m_readingDesType(eNone),
		m_pError(null)
{
}

//_________________________________________________________________________________________________

ProjectSerializer::~ProjectSerializer(void)
{
	if (m_pError)
	{
		delete m_pError;
		m_pError = null;
	}
}

//_________________________________________________________________________________________________

DesProject* ProjectSerializer::load(const std::wstring& fileName)
{
	m_fileName = QString::fromStdWString(fileName);

	//open the file with the given file name
	QFile file(QString::fromStdWString(fileName));
	if (file.open(QIODevice::ReadOnly|QIODevice::Text) == false)
		throw EX("Cannot open file in read-only mode. Cannot load project.")

	//create and configure an XML Reader
	QXmlSimpleReader xmlReader;
	xmlReader.setContentHandler(this);
	xmlReader.setErrorHandler(this);

	//...and have it parse the opened file
	QXmlInputSource* xmlSource = new QXmlInputSource(&file);
	bool sourceParsed = xmlReader.parse(xmlSource);

	if (sourceParsed == false)
	{
		throw new QXmlParseException(m_pError->message(), m_pError->columnNumber(), m_pError->lineNumber());
	}

	//the project was created and loaded
	return m_project;
}


// added by rjl - remove when bddhisc
// integrated with despot 
//_________________________________________________________________________________________________

void ProjectSerializer::exportToBDDhisc(const std::wstring& fileName)
{

  //  this must never be called for a non hierarchical project.
  if(!(m_project->getType() == eHierProject))
    {
      throw EX("Can only export HISC projects to BDDhisc format.");
    }

 
  // bddhisc has a bug that it requires all uncontrollable events to
  // belong to at least one plant component. We need to ensure this.

  {
    DesProject::EventIteratorPtr  PeventIt = m_project->createProjEventIterator();
    DesSubsystem::DesIteratorPtr PdesIt = m_project->createDesIterator(ePlantDes);
    bool uevFound = false;

      for(PeventIt->first(); PeventIt->isDone() == false; PeventIt->next())
	{
	  const ProjectEvent& event = PeventIt->currentItem();

	  // add check to exclude low  data events for now as BddHisc
	  // does not support this for verification.  
	  if (event.getType() == eLDataEvent)
	    {
	      std::wstring message = L"Bddhisc does not currently support projects with Low Data events.";
	      throw message;
	    }


	  if (!(event.isControllable()))
	    {
	      std::wstring eName = event.getName();
	      uevFound = false;

	      // check if in a plant DES
	      for(PdesIt->first(); PdesIt->notDone(); PdesIt->next())
		{
		  Des& des = PdesIt->currentItem();
		  const DesEvent* event;
		  if (des.findEvent(eName,event))
		    {
		      uevFound = true;
		      break;
		    }
		}

	      if(!uevFound) 
		{
		  std::wstring message = L"Bddhisc requires that all uncontrollable events belong to at least one plant component.  Event \"";
		  message += eName;
		  message += L"\" does not.";
		  throw message;
		}
	    }

	}
  }


  //open the project file with the given file name
  QFile projFile(QString::fromStdWString(fileName));
  if (projFile.open(QIODevice::WriteOnly|QIODevice::Text) == false) {
    throw EX("Cannot open file in write-only mode. Cannot export project.");
  }

  //need to find out how many low-levels we have
  int numLow = hierProject()->getSubsystemCount() -1;

//first, get the highlevel
  const DesSubsystem& highSubsys = m_project->getRootSubsys();

  QString highName = QString::fromStdWString(highSubsys.getName());
  //  seems VC++ doesn't like: QString lowNames[numLow];
  QString * lowNames = new QString[numLow];

  // remove spaces from high name
  while (highName.contains(" "))
    {
      highName.remove(' ');
    }

  //write out project file
   QTextStream projOut(&projFile);

   //start writing the BDDhisc project file
   projOut << "[SYSTEM]\n";  
   projOut << QString::fromStdWString(m_project->getName()) << "\n\n";
   projOut << "[LOW]\n";
   projOut << numLow << "\n";

   // write out names of subsystems and record
   // add check for spaces
   int tmpNumLow = 0;
   DesHierProject::SubsysIteratorPtr subsysIt = hierProject()->createSubsysIterator();
   for(subsysIt->first(); subsysIt->notDone(); subsysIt->next())
     {
       const DesSubsystem& lowSubsys = subsysIt->currentItem();
			
       if (lowSubsys.isRoot() == false)
	 {
	   
           if (tmpNumLow >=numLow)
	     {
	       throw EX("Error: more subsystems present than recorded in subsystem count..");
	     }

	   lowNames[tmpNumLow] = QString::fromStdWString(lowSubsys.getName());
	   // remove spaces from name
	   while ((lowNames[tmpNumLow]).contains(" "))
	     {
	       (lowNames[tmpNumLow]).remove(' ');
	     }
	  projOut << lowNames[tmpNumLow] << "\n";
	  tmpNumLow++;
	 }
     }
   projOut << "\n";
   projOut << "[HIGH]\n";
   projOut << highName <<"\n";

   // project file complete. Export high subsystem
   QString absPath = QFileInfo(projFile).absolutePath();
   QString highPath = absPath + QDir::separator() + highName;
   QString highSubsysFileName = highPath  + QDir::separator()  + highName  + ".sub";

  QDir projDir(absPath);
  projDir.mkdir(highName);
  QFile highFile(highSubsysFileName);
  if (highFile.open(QIODevice::WriteOnly|QIODevice::Text) == false) {
    throw EX("Cannot open high subsystem file in write-only mode. Cannot export project.");
  }

  QTextStream highOut(&highFile);

  highOut << "[SYSTEM]"  << "\n";

  int numPlants = 0;
  int numSups = 0;

  // count number of plants
  {
    DesSubsystem::DesIteratorPtr desIt = highSubsys.createDesIterator(ePlantDes);
    for(desIt->first(); desIt->notDone(); desIt->next())
      {
	numPlants++;
      }
  }
  highOut << numPlants  << "\n";

  // count number of Sups
  {
    DesSubsystem::DesIteratorPtr desIt = highSubsys.createDesIterator(eSupervisorDes);
    for(desIt->first(); desIt->notDone(); desIt->next())
      {
	numSups++;
      }
  }
  highOut << numSups  << "\n\n";

  highOut << "[PLANT]"  << "\n";

  //list the plant DES
  {
    DesSubsystem::DesIteratorPtr desIt = highSubsys.createDesIterator(ePlantDes);
    for(desIt->first(); desIt->notDone(); desIt->next())
      {
	Des& des = desIt->currentItem();
	QString highDESName = QString::fromStdWString(des.getName()) + ".hsc";
	highOut <<  highDESName  <<"\n";
	QString highDESFileName = highPath  + QDir::separator() + highDESName;
	std::wstring tmpFileName = highDESFileName.toStdWString();
	des.exportToBDDhiscORsd(tmpFileName,true,true);
      }
  }
  highOut << "\n[SPEC]"  << "\n";

  //list the sup DES
  {
    DesSubsystem::DesIteratorPtr desIt = highSubsys.createDesIterator(eSupervisorDes);
    for(desIt->first(); desIt->notDone(); desIt->next())
      {
	Des& des = desIt->currentItem();
	QString highDESName = QString::fromStdWString(des.getName()) + ".hsc";
	highOut << highDESName  <<"\n";
	QString highDESFileName = highPath  + QDir::separator() + highDESName;
	std::wstring tmpFileName = highDESFileName.toStdWString();
	des.exportToBDDhiscORsd(tmpFileName,true,true);
      }
  }

  //  the high subsystem file is now complete


   // export low level subsystems
  //  seems VC++ doesn't like: QString lowPaths[numLow];
   QString * lowPaths =  new QString[numLow];
   // seems VC++ doesn't like: QString lowSubsysFileNames[numLow];
   QString * lowSubsysFileNames =  new QString[numLow];

   for (int i = 0; i < numLow;i++) 
     {
        lowPaths[i] =  absPath + QDir::separator() + lowNames[i];
        lowSubsysFileNames[i] = lowPaths[i] + QDir::separator() +   lowNames[i] +  ".sub";
	projDir.mkdir(lowNames[i]);
     }

   // need to loop through the low subystems and export them.
   tmpNumLow = 0;
   for(subsysIt->first(); subsysIt->notDone(); subsysIt->next())
     {
       const DesSubsystem& lowSubsys = subsysIt->currentItem();
			
       if (lowSubsys.isRoot() == false)
	 {
	   QFile lowFile(lowSubsysFileNames[tmpNumLow]);
	   if (lowFile.open(QIODevice::WriteOnly|QIODevice::Text) == false) {
	     throw EX("Cannot open low subsystem file in write-only mode. Cannot export project.");
	   }

	   QTextStream lowOut(&lowFile);
	   lowOut << "[SYSTEM]"  << "\n";

	   numPlants = 0;
	   numSups = 0;
	   // count number of plants
	   {
	     DesSubsystem::DesIteratorPtr desIt = lowSubsys.createDesIterator(ePlantDes);
	     for(desIt->first(); desIt->notDone(); desIt->next())
	       {
		 numPlants++;
	       }
	   }
	   lowOut << numPlants  << "\n";

	   // count number of Sups
	   {
	     DesSubsystem::DesIteratorPtr desIt = lowSubsys.createDesIterator(eSupervisorDes);
	     for(desIt->first(); desIt->notDone(); desIt->next())
	       {
		 numSups++;
	       }
	   }
	   lowOut << numSups  << "\n\n";

	   lowOut << "[INTERFACE]"  << "\n";

	   if (lowSubsys.implementsInterface())
	     {
	       const DesInterface& interf = lowSubsys.getInterface();
	       
	       int numIntfDes = 0;
	       {
		 //  count number of intf DES
		 DesInterface::DesIteratorPtr desIt = interf.createDesIterator();
		 for(desIt->first(); desIt->notDone(); desIt->next())
		   {
		     numIntfDes++;
		   }
	       }

	       if ( numIntfDes >1) 
		 {
		   // BDDhisc only allows one intf des, so we need to
		   // first sync them together.
		   Des& intfDes = interf.getSyncDes();
		   QString intfDESName = QString::fromStdWString(intfDes.getName()) + ".hsc";
		   lowOut << intfDESName  <<"\n";
		   QString intfDESFileName = lowPaths[tmpNumLow]  + QDir::separator() + intfDESName;
		   std::wstring tmpIntfFileName = intfDESFileName.toStdWString();
		   intfDes.exportToBDDhiscORsd(tmpIntfFileName,false,true);
		 }
	       else
		 {
		   // loop through interface des. bddhisc only allows one.
		   DesInterface::DesIteratorPtr desIt = interf.createDesIterator();
		   for(desIt->first(); desIt->notDone(); desIt->next())
		     {
		       Des& intfDes = desIt->currentItem();
		       QString intfDESName = QString::fromStdWString(intfDes.getName()) + ".hsc";
		       lowOut << intfDESName  <<"\n";
		       QString intfDESFileName = lowPaths[tmpNumLow]  + QDir::separator() + intfDESName;
		       std::wstring tmpIntfFileName = intfDESFileName.toStdWString();
		       intfDes.exportToBDDhiscORsd(tmpIntfFileName,false,true);
		     }
		 }
	     }
	  

	   lowOut << "\n[PLANT]"  << "\n";

	   //list the plant DES
	   {
	     DesSubsystem::DesIteratorPtr desIt = lowSubsys.createDesIterator(ePlantDes);
	     for(desIt->first(); desIt->notDone(); desIt->next())
	       {
		 Des& des = desIt->currentItem();
		 QString lowDESName = QString::fromStdWString(des.getName()) + ".hsc";
		 lowOut << lowDESName  <<"\n";
		 QString lowDESFileName = lowPaths[tmpNumLow]  + QDir::separator() + lowDESName;
		 std::wstring tmpFileName = lowDESFileName.toStdWString();
		 des.exportToBDDhiscORsd(tmpFileName,false,true);
	       }
	   }
	   lowOut << "\n[SPEC]"  << "\n";

	   //list the sup DES
	   {
	     DesSubsystem::DesIteratorPtr desIt = lowSubsys.createDesIterator(eSupervisorDes);
	     for(desIt->first(); desIt->notDone(); desIt->next())
	       {
		 Des& des = desIt->currentItem();
		 QString lowDESName = QString::fromStdWString(des.getName()) + ".hsc";
		 lowOut << lowDESName  <<"\n";
		 QString lowDESFileName = lowPaths[tmpNumLow]  + QDir::separator() + lowDESName;
		 std::wstring tmpFileName = lowDESFileName.toStdWString();
		 des.exportToBDDhiscORsd(tmpFileName,false,true);
	       }
	   }

	   tmpNumLow++;
	 }
     }

   //that should do it.

}

//  remove to here - RJL


// added by rjl - remove when bddsd
// integrated with despot 
//_________________________________________________________________________________________________

void ProjectSerializer::exportToBDDsd(const std::wstring& fileName)
{

  //  this must never be called for a non flat project.
  if(!(m_project->getType() == eFlatProject))
    {
      throw EX("Can only export flat projects to BDDsd format.");
    }

  // need to add here a check that all DES contain a controllable
  // event with name "tick" and alias "t"

  {
    DesSubsystem::DesIteratorPtr PdesIt = m_project->createDesIterator();
    std::wstring tName = L"tick";
    std::wstring tAlias = L"t";
    bool fndEvent = false;


    for(PdesIt->first(); PdesIt->notDone(); PdesIt->next())
      {
	Des& des = PdesIt->currentItem();
	const DesEvent* event;
        fndEvent = false;

	if (des.findEvent(tName,event))
	  {
	    std::wstring tmpAlias = event->getAlias();
	    if ((tAlias == tmpAlias) && (event->isControllable()))
	      {
		fndEvent = true;
	      }
	  } 

	if (!fndEvent)
	  {
	    std::wstring message = L"Bddsd requires that every DES\
 contain a controllable event named \"tick\" with alias\
 \"t\". DES \"";
	    message += des.getName();
	    message += L"\" does not.";
	    throw message;
	  }

      }

  }



  
  //open the project file with the given file name
  QFile projFile(QString::fromStdWString(fileName));
  if (projFile.open(QIODevice::WriteOnly|QIODevice::Text) == false) {
    throw EX("Cannot open file in write-only mode. Cannot export project.");
  }

  //write out project file
   QTextStream projOut(&projFile);

   // Determ directory path to put DES files in
   QString absPath = QFileInfo(projFile).absolutePath();

   projOut << "[SYSTEM]"  << "\n";

   int numPlants = 0;
   int numSups = 0;

   // count number of plants
   {
     DesSubsystem::DesIteratorPtr desIt = m_project->createDesIterator(ePlantDes);
     for(desIt->first(); desIt->notDone(); desIt->next())
       {
	 numPlants++;
       }
   }
   projOut  << numPlants  << "\n";

   // count number of Sups
   {
     DesSubsystem::DesIteratorPtr desIt = m_project->createDesIterator(eSupervisorDes);
     for(desIt->first(); desIt->notDone(); desIt->next())
       {
	 numSups++;
       }
   }
   projOut  << numSups  << "\n\n";

   projOut  << "[PLANT]"  << "\n";

   //list the plant DES
   {
     DesSubsystem::DesIteratorPtr desIt = m_project->createDesIterator(ePlantDes);
     for(desIt->first(); desIt->notDone(); desIt->next())
       {
	 Des& des = desIt->currentItem();
	 QString DESName = QString::fromStdWString(des.getName()) + ".hsc";
	 projOut  <<  DESName  <<"\n";
	 QString DESFileName = absPath  + QDir::separator() + DESName;
	 std::wstring tmpFileName = DESFileName.toStdWString();
	 des.exportToBDDhiscORsd(tmpFileName,false,false);
       }
   }
   projOut  << "\n[SPEC]"  << "\n";

   //list the sup DES
   {
     DesSubsystem::DesIteratorPtr desIt = m_project->createDesIterator(eSupervisorDes);
     for(desIt->first(); desIt->notDone(); desIt->next())
       {
	 Des& des = desIt->currentItem();
	 QString DESName = QString::fromStdWString(des.getName()) + ".hsc";
	 projOut  << DESName  <<"\n";
	 QString DESFileName = absPath  + QDir::separator() + DESName;
	 std::wstring tmpFileName = DESFileName.toStdWString();
	 des.exportToBDDhiscORsd(tmpFileName,false,false);
       }
   }

   //that should do it.

}

//  remove to here - RJL


//_________________________________________________________________________________________________

void ProjectSerializer::save(const std::wstring& fileName)
{
	m_fileName = QString::fromStdWString(fileName);

	//open the file with the given file name
	QFile file(QString::fromStdWString(fileName));
	if (file.open(QIODevice::WriteOnly|QIODevice::Text) == false)
		throw EX("Cannot open file in write-only mode. Cannot save DES.")

	//create an XML serializer
	XmlWriter xw(file);
	xw.setAutoNewLine(true);

	//start writing the file
	xw.writeOpenTag(cProjRootTag, AttrMap(cProjFileVerAttr, cProjFileVerVal));

	//write the definition of the project
	writeProjDefinition(xw);
	
	//write the end of the file
	xw.writeCloseTag(cProjRootTag);
}

//_________________________________________________________________________________________________

void ProjectSerializer::configure(ProjSerializerAccess* projAccess)
{
	m_projectAccess = projAccess;
}

//_________________________________________________________________________________________________

//the parsing is starting
bool ProjectSerializer::startDocument()
{
	//clean any errors from previous parses
	if (m_pError)
	{
		delete m_pError;
		m_pError = null;
	}

	//clear any information that may have been previously loaded
	m_projFileVer.clear();

	return true;
}

//_________________________________________________________________________________________________

bool ProjectSerializer::endDocument()
{
	if (m_project == null)
	{
		throw EX("Invalid project file. Cannot load project");
	}
	
	//set project properties
	setProjectProperties();

	if (m_project->getType() == eHierProject)
	{
		resolveInterfImplementations();
		resolveSubsysDependencies();
	}

	//tell the project we're done loading it
	m_projectAccess->setLoadInProgress(false);

	return true;
}

//_________________________________________________________________________________________________

//element and attribute parsing
bool ProjectSerializer::startElement(const QString& /*namespaceURI*/, const QString& localName, 
									 const QString& /*qName*/, const QXmlAttributes& atts)
{
	if (localName == cProjRootTag)
	{
		return readProjectRoot(localName, atts);
	}
	else 
	{
		return readProjectDefinition(localName, atts);
	}
}

//_________________________________________________________________________________________________

bool ProjectSerializer::endElement(const QString& /*namespaceURI*/, const QString& localName, 
								   const QString& /*qName*/)
{
	if (localName == cSubsysTag)
	{
		m_crtSubsys->setLoadInProgress(false);
	}
	else if (localName == cInterfaceTag)
	{
		m_crtInterf->setLoadInProgress(false);
	}

	return true;
}

//_________________________________________________________________________________________________

//error handling
bool ProjectSerializer::warning(const QXmlParseException& exception)
{
	qWarning(exception.message().toAscii().data());
	return true; //continue
}

//_________________________________________________________________________________________________

bool ProjectSerializer::error(const QXmlParseException& exception)
{
	assert(m_pError == null);
	m_pError = new QXmlParseException(exception.message(), exception.columnNumber(), exception.lineNumber());
	
	qWarning(exception.message().toAscii().data());
	
	return false; //stop parsing
}

//_________________________________________________________________________________________________

bool ProjectSerializer::fatalError(const QXmlParseException& exception)
{
	assert(m_pError == null);
	m_pError = new QXmlParseException(exception.message(), exception.columnNumber(), exception.lineNumber());	

	qWarning(exception.message().toAscii().data());
	
	return false; //stop parsing
}

//_________________________________________________________________________________________________

void ProjectSerializer::createProject(ProjectType projType, QString projName)
{
	switch(projType)
	{
		case eFlatProject:
			m_project = new DesFlatProject(projName.toStdWString());
			break;

		case eHierProject:
			m_project = new DesHierProject(projName.toStdWString());
			break;
	}

	m_project->configureSerializer(this);
	m_projectAccess->setLoadInProgress();
}

//_________________________________________________________________________________________________

DesFlatProject* ProjectSerializer::flatProject()
{
	assert(m_project != null);
	assert(m_project->getType() == eFlatProject);
	DesFlatProject* flatProject = dynamic_cast<DesFlatProject*>(m_project);
	
	if (flatProject == null)
	{		  
		throw EX("The project beeing loaded is not a flat project");
	}

	return flatProject;
}

//_________________________________________________________________________________________________

DesHierProject* ProjectSerializer::hierProject()
{
	assert(m_project != null);
	assert(m_project->getType() == eHierProject);
	DesHierProject* hierProject = dynamic_cast<DesHierProject*>(m_project);
	
	if (hierProject == null)
	{		  
		throw EX("The project beeing loaded is not a HISC project");
	}

	return hierProject;
}

//_________________________________________________________________________________________________

HierSerializerAccess* ProjectSerializer::hierProjAccess()
{
	assert(m_projectAccess != null);
	assert(m_project->getType() == eHierProject);
	
	HierSerializerAccess* hierAccess = dynamic_cast<HierSerializerAccess*>(m_projectAccess);	
	if (hierAccess == null)
	{
		throw EX("The project being loaded does not provide serializer with HISC access");
	}
	
	return hierAccess;
}

//_________________________________________________________________________________________________

bool ProjectSerializer::isHeaderTag(const QString& tagName)
{
	return ((tagName == cProjHeaderTag) || (tagName == cProjIntegrityTag) || (tagName == cProjNonBlockTag) ||
		    (tagName == cProjCtrlTag) || (tagName == cProjIConsTag) || (tagName == cProjLwNonBlockTag) ||
			(tagName == cProjLwCtrlTag));
}

//_________________________________________________________________________________________________

bool ProjectSerializer::isSubsystemTag(const QString& tagName)
{
	return ((tagName == cSubsysTag) || (tagName == cSubsysImplTag) || (tagName == cSubsysSupDesTag) ||
		(tagName == cSubsysPlantDesTag) || (tagName == cSubsysUsesTag) || (tagName == cInterfRefTag));
}

//_________________________________________________________________________________________________

bool ProjectSerializer::isInterfaceTag(const QString& tagName)
{
	return (tagName == cInterfaceTag);
}

//_________________________________________________________________________________________________

bool ProjectSerializer::isDesTag(const QString& tagName)
{
	return (tagName == cDesTag);
}

//_________________________________________________________________________________________________

bool ProjectSerializer::readProjectRoot(const QString& /*tagName*/, const QXmlAttributes& atts)
{
	m_projFileVer = atts.value(cProjFileVerAttr);
	if (m_projFileVer > cProjFileVerVal)
	{
		//the file version is greater than the one supported by this serializer
		qWarning("Des file version (%s) is greater than the one supported (%s). The loading may fail.",
                                 m_projFileVer.toAscii().data(), cProjFileVerVal.toAscii().data());
	}

	return true;
}

//_________________________________________________________________________________________________

bool ProjectSerializer::readProjectDefinition(const QString& tagName, const QXmlAttributes& atts)
{
	if (isHeaderTag(tagName))
	{
		return readProjectHeader(tagName, atts);
	}
	else if (isSubsystemTag(tagName))
	{
		return readSubsystem(tagName, atts);
	}
	else if (isInterfaceTag(tagName))
	{
		return readInterface(tagName, atts);
	}
	else if (isDesTag(tagName))
	{
		return readDes(tagName, atts);
	}
	else
	{
		assert(true);
		qWarning("Unknown tag \"%s\". Tag will be ingored", tagName.toAscii().data());	
		return true;
	}
}

//_________________________________________________________________________________________________

bool ProjectSerializer::readProjectHeader(const QString& tagName, const QXmlAttributes& atts)
{
	if (tagName == cProjHeaderTag)
	{
		//read the name of the project
		QString projName = atts.value(cProjNameAttr);

		//read the type of the project
		QString projTypeName = atts.value(cProjTypeAttr);
		ProjectType projType = getProjectType(projTypeName);
		
		createProject(projType, projName);
	}
	else if (tagName == cProjIntegrityTag)
	{
		//read the integrity status ...
		QString integStatusName = atts.value(cProjIntegStatusAttr);
		m_integStatus = getProjIntegrity(integStatusName);

		//... and the time stamp for the integrity check
		QString integTimeStamp = atts.value(cProjIntegStampAttr);
		m_integDateStamp = integTimeStamp.toStdWString();
	}
	else if (tagName == cProjNonBlockTag)
	{
		//read the non-blocking property and date stamp
		QString nonBlockPropName = atts.value(cProjNonBlockStatusAttr);
		m_nonBlockStatus = getNonBlockProp(nonBlockPropName);

		QString nonBlockStamp = atts.value(cProjNonBlockStampAttr);
		m_nonBlockDateStamp = nonBlockStamp.toStdWString();
	}
	else if (tagName == cProjCtrlTag)
	{
		//read the controllable property and date stamp
		QString ctrlPropName = atts.value(cProjCtrlStatusAttr);
		m_ctrlStatus = getCtrlProp(ctrlPropName);

		QString ctrlStamp = atts.value(cProjCtrlStampAttr);
		m_ctrlDateStamp = ctrlStamp.toStdWString();
	}
	else if (tagName == cProjIConsTag)
	{
		//read the controllable property and date stamp
		QString iConsPropName = atts.value(cProjIConsStatusAttr);
		m_iConsStatus = getProjIConsist(iConsPropName);

		QString iConsStamp = atts.value(cProjIConsStampAttr);
		m_iConsDateStamp = iConsStamp.toStdWString();
	}
	else if (tagName == cProjLwNonBlockTag)
	{
		//read the non-blocking property and date stamp
		QString lwNonBlockPropName = atts.value(cProjLwNonBlockStatusAttr);
		m_lwNonBlockStatus = getLwNonBlockProp(lwNonBlockPropName);

		QString lwNonBlockStamp = atts.value(cProjLwNonBlockStampAttr);
		m_lwNonBlockDateStamp = lwNonBlockStamp.toStdWString();
	}
	else if (tagName == cProjLwCtrlTag)
	{
		//read the controllable property and date stamp
		QString lwCtrlPropName = atts.value(cProjLwCtrlStatusAttr);
		m_lwCtrlStatus = getLwCtrlProp(lwCtrlPropName);

		QString lwCtrlStamp = atts.value(cProjLwCtrlStampAttr);
		m_lwCtrlDateStamp = lwCtrlStamp.toStdWString();
	}
	else
	{
		assert(true);
		qWarning("Unknown tag \"%s\". Tag will be ingored", tagName.toAscii().data());		
	}

	return true;
}

//_________________________________________________________________________________________________

bool ProjectSerializer::readSubsystem(const QString& tagName, const QXmlAttributes& atts)
{
	if (tagName == cSubsysTag) 
	{
		if (m_project->getType() == eHierProject)
		{
			//create the subsystem and read its properties
			QString subsysName = atts.value(cSubsysNameAttr);
			m_crtSubsys = new DesSubsystem(subsysName.toStdWString(), m_projectAccess->getEventPool());
			m_crtSubsys->setLoadInProgress();

			int level = atts.value(cSubsysLevelAttr).toInt();
			m_crtSubsys->setLevel(level);

			QString validName = atts.value(cSubsysValidStatusAttr);
			m_crtSubsys->setValid(getSubsysValidStatus(validName));

			QString lwNonBlockName = atts.value(cSubsysLwNonBlockProp);
			m_crtSubsys->setNonBlocking(getSubsysLwNonBlockProp(lwNonBlockName));

			QString lwCtrlName = atts.value(cSubsysLwCtrlProp);
			m_crtSubsys->setControllable(getSubsysLwCtrlProp(lwCtrlName));

			QString lwIConsistName = atts.value(cSubsysIConsistProp);
			m_crtSubsys->setInterfConsist(getSubsysIConsistProp(lwIConsistName));

			if (m_crtSubsys->isRoot())
			{
				hierProjAccess()->addHighLevelSubsys(m_crtSubsys);
			}
			else
			{
				hierProjAccess()->addLowLevelSubsys(m_crtSubsys);
			}
		}
		else
		{
			//flat project the subsystem has already been created just access it
			m_crtSubsys = &(m_project->getRootSubsys());
			m_crtSubsys->setLoadInProgress();
		}
	}
	else if (tagName == cSubsysSupDesTag)
	{
		m_readingDesType = eSubsysSupDes;
	}
	else if (tagName == cSubsysPlantDesTag)
	{
		m_readingDesType = eSubsysPlantDes;
	}
	else if (tagName == cSubsysImplTag) 
	{
		assert(m_project->getType() == eHierProject);
		m_readingInterfRefType = eImplInterface;
	}
	else if (tagName == cSubsysUsesTag)
	{
		assert(m_project->getType() == eHierProject);
		m_readingInterfRefType = eUsesInterface;
	}
	else if (tagName == cInterfRefTag)
	{
		assert(m_project->getType() == eHierProject);
		
		std::wstring interfName = atts.value(cInterfNameAttr).toStdWString();
		
		switch(m_readingInterfRefType)
		{
			case eImplInterface:
				m_unresImpls.push_back(InterfImpl(m_crtSubsys, interfName));
				break;

			case eUsesInterface:
			{	
				std::wstring interfProvider = atts.value(cInterfProviderAttr).toStdWString();
				m_unresDepends.push_back(SubsysDependency(m_crtSubsys, DesSubsystem::DependencyRef(interfName, interfProvider)));
				break;
			}

			default:
				assert(false); //unknown
				qWarning("Unknown interface reference type for tag \"%s\". Tag will be ingored", tagName.toAscii().data());		
		}
	}
	else
	{
		assert(true);
		qWarning("Unknown tag \"%s\". Tag will be ingored", tagName.toAscii().data());		
	}

	return true;
}

//_________________________________________________________________________________________________

bool ProjectSerializer::readInterface(const QString& tagName, const QXmlAttributes& atts)
{
	assert(m_project->getType() == eHierProject);
	
	if (tagName == cInterfaceTag)
	{
		QString interfName = atts.value(cInterfNameAttr);		
		m_crtInterf = new DesInterface(interfName.toStdWString(), m_projectAccess->getEventPool());
		m_crtInterf->setLoadInProgress();

		QString validName = atts.value(cInterfValidStatusAttr);
		m_crtInterf->setValid(getInterfValidStatus(validName));

		QString lwIConsistName = atts.value(cInterfIConsistProp);
		m_crtInterf->setInterfConsist(getInterfIConsistProp(lwIConsistName));

		hierProjAccess()->addInterface(m_crtInterf);

		m_readingDesType = ProjectSerializer::eInterfaceDes;
	}
	else
	{
		assert(true);
		qWarning("Unknown tag \"%s\". Tag will be ingored", tagName.toAscii().data());		
	}
	
	return true;
}

//_________________________________________________________________________________________________

bool ProjectSerializer::readDes(const QString& tagName, const QXmlAttributes& atts)
{
	if (tagName == cDesTag)
	{
		//obtain the DES information and create a DES
		QString desName = atts.value(cDesNameAttr);
		QString desFileName = convertToAbsolute(atts.value(cDesLocationAttr));
		Des* des = new Des(desName.toStdWString(), desFileName.toStdWString(), true/*delay load*/); 

		//TODO: Before adding the des to the project we need to load it since the project will need
		//to update the project event pool. Delay loading needs a background thread mechanism that
		//loads DES in the background and updates the project event pool synchronized with the projec UI
		//such as not to allow any action until all DES have been loaded
		try
		{
			//make sure this is not a new DES. If you save the project with new DES but don't save DES
			//you get a name but not a file. No point in trying to load nothing
			if (desFileName.isEmpty() == false)
			{
				des->load();
			}
		}
		catch(...)
		{
			qWarning("Errors loading DES \"%s\" from file \"%s\". DES will be ignored.", desName.toAscii().data(), desFileName.toAscii().data());		
			return true; //continue loading
		}

		//add it to the proper container
		switch(m_readingDesType)
		{
			case eSubsysSupDes:
				if (des->isNew())
				{
					//this DES is not comming from a file so we can assume the right type
					des->setType(DESpot::eSubsystemDes);
				}
				
				//add the DES to the project; depending on the type of project this is done a differently. It is
				//important to go through the project and not directly to the subsystem because the project will index
				//the names and will fire notifications
				if (m_project->getType() == eFlatProject)
				{
					flatProject()->addSupDes(des);
				}
				else
				{
					hierProject()->addDes(des, *m_crtSubsys, DESpot::eSupervisorDes);
				}
				break;

			case eSubsysPlantDes:
				if (des->isNew())
				{
					//this DES is not comming from a file so we can assume the right type
					des->setType(DESpot::eSubsystemDes);
				}

				//add the DES to the project; depending on the type of project this is done a differently. It is
				//important to go through the project and not directly to the subsystem because the project will index
				//the names and will fire notifications
				if (m_project->getType() == eFlatProject)
				{
					flatProject()->addPlantDes(des);
				}
				else
				{
					hierProject()->addDes(des, *m_crtSubsys, ePlantDes);
				}
				break;

			case ProjectSerializer::eInterfaceDes:
				if (des->isNew())
				{
					//this DES is not comming from a file so we can assume the right type
					des->setType(DESpot::eInterfaceDes);
				}

				//add the DES to the project. It is important to go through the project and not directly to 
				//the interface because the project will index the names and will fire notifications
				hierProject()->addDes(des, *m_crtInterf);
				break;

                        case ProjectSerializer::eNone:
                                assert(true);
                                qWarning("Reading des without a type");
                                break;

		}
	}
	else
	{
		assert(true);
		qWarning("Unknown tag \"%s\". Tag will be ingored", tagName.toAscii().data());		
	}

	return true;
}

//_________________________________________________________________________________________________

void ProjectSerializer::writeProjDefinition(XmlWriter& xw)
{
	//The definition contains the project structure: header, subsystems and interfaces
	writeProjHeader(xw);
	
	//write the root subsystem first
	writeSubsystem(xw, m_project->getRootSubsys());
	
	if (m_project->getType() == eHierProject)
	{
		writeProjInterfaces(xw);
	}

	writeProjSubsystems(xw, false /*exclude root subsystem*/);
}

//_________________________________________________________________________________________________

void ProjectSerializer::writeProjHeader(XmlWriter& xw)
{
	AttrMap headerAttrs(cProjNameAttr, toString(m_project->getName()),
						cProjTypeAttr, getProjectType());
	
	if (m_project->getType() == eHierProject)
	{
		headerAttrs.add(cProjDegreeAttr, toString(hierProject()->getDegree()));
	}
	
	xw.writeOpenTag(cProjHeaderTag, headerAttrs);

	xw.writeAtomTag(cProjIntegrityTag, AttrMap(cProjIntegStatusAttr, getProjIntegrity(), 
											   cProjIntegStampAttr, toString(m_project->getIntegrityStamp())));
	
	xw.writeAtomTag(cProjNonBlockTag, AttrMap(cProjNonBlockStatusAttr, getNonBlockProp(), 
											  cProjNonBlockStampAttr, toString(m_project->getNonBlockingStamp())));

	xw.writeAtomTag(cProjCtrlTag, AttrMap(cProjCtrlStatusAttr, getCtrlProp(), 
									      cProjCtrlStampAttr, toString(m_project->getCtrlStamp())));

	if (m_project->getType() == eHierProject)
	{
		xw.writeAtomTag(cProjIConsTag, AttrMap(cProjIConsStatusAttr, getProjIConsist(), 
											   cProjIConsStampAttr, toString(hierProject()->getIConsistStamp())));
		
		xw.writeAtomTag(cProjLwNonBlockTag, AttrMap(cProjLwNonBlockStatusAttr, getLwNonBlockProp(), 
												  cProjLwNonBlockStampAttr, toString(hierProject()->getLwNonBlockStamp())));

		xw.writeAtomTag(cProjLwCtrlTag, AttrMap(cProjLwCtrlStatusAttr, getLwCtrlProp(), 
											  cProjLwCtrlStampAttr, toString(hierProject()->getLwCtrlStamp())));
	}

	xw.writeCloseTag(cProjHeaderTag);
}

//_________________________________________________________________________________________________

void ProjectSerializer::writeProjSubsystems(XmlWriter& xw, bool includeRoot)
{
	if (includeRoot)
	{
		//save the root subsystem
		DesSubsystem& rootSubsys = m_project->getRootSubsys();
		writeSubsystem(xw, rootSubsys);
	}

	//if the project is HISC save all other subsystems
	if (m_project->getType() == eHierProject)
	{
		DesHierProject::SubsysIteratorPtr subsysIt = hierProject()->createSubsysIterator();
		for(subsysIt->first(); subsysIt->notDone(); subsysIt->next())
		{
			const DesSubsystem& subsys = subsysIt->currentItem();
			
			if (subsys.isRoot() == false)
			{
				writeSubsystem(xw, subsys);
			}
		}
	}
}

//_________________________________________________________________________________________________

void ProjectSerializer::writeSubsystem(XmlWriter& xw, const DesSubsystem& subsys)
{
	//Write the opening subsystem tag: 
	//e.g. <Subsystem name = "High Level Subsystem" level="0" lw-ctrl ="yes" lw-non-blocking ="yes" i-consist ="yes">
	AttrMap subsysAttrMap(cSubsysNameAttr, toString(subsys.getName()));
	if (m_project->getType() == eHierProject)
	{
		subsysAttrMap.add(cSubsysLevelAttr, getLevelValue(subsys));
		subsysAttrMap.add(cSubsysValidStatusAttr, getSubsysValidStatus(subsys));
		subsysAttrMap.add(cSubsysLwCtrlProp, getSubsysLwCtrlProp(subsys));
		subsysAttrMap.add(cSubsysLwNonBlockProp, getSubsysLwNonBlockProp(subsys));
		subsysAttrMap.add(cSubsysIConsistProp, getSubsysIConsistProp(subsys));
	}
	xw.writeOpenTag(cSubsysTag, subsysAttrMap);
	{		                                
		if (m_project->getType() == eHierProject)
		{
			//write the implements tag with the interface the subsystem implements
			//the root subsystem doesn't implement any interface
			{	
				if (subsys.implementsInterface())
				{
					xw.writeOpenTag(cSubsysImplTag);
					{
						const DesInterface& interf = subsys.getInterface();
						xw.writeAtomTag(cInterfRefTag, AttrMap(cInterfNameAttr, toString(interf.getName())));
					}
					xw.writeCloseTag(cSubsysImplTag);
				}
				else
				{
					//write an empty implementation tag
					xw.writeAtomTag(cSubsysImplTag);
				}
			}
		}

		//write the list of supervisor DES
		xw.writeOpenTag(cSubsysSupDesTag);
		{
			DesSubsystem::DesIteratorPtr desIt = subsys.createDesIterator(eSupervisorDes);
			for(desIt->first(); desIt->notDone(); desIt->next())
			{
				const Des& des = desIt->currentItem();
				
				xw.writeAtomTag(cDesTag, AttrMap(cDesNameAttr, toString(des.getName()),
								cDesLocationAttr, convertToRelative(toString(des.getFileName()))));
			}
		}
		xw.writeCloseTag(cSubsysSupDesTag);

		//write the list of plant DES
		xw.writeOpenTag(cSubsysPlantDesTag);
		{
			DesSubsystem::DesIteratorPtr desIt = subsys.createDesIterator(ePlantDes);
			for(desIt->first(); desIt->notDone(); desIt->next())
			{
				const Des& des = desIt->currentItem();
				xw.writeAtomTag(cDesTag, AttrMap(cDesNameAttr, toString(des.getName()),
								cDesLocationAttr, convertToRelative(toString(des.getFileName()))));
			}
		}
		xw.writeCloseTag(cSubsysPlantDesTag);

		if (m_project->getType() == eHierProject)
		{
			//write the list of dependent subsystems
			if (subsys.getDependsCount() != 0)
			{
				xw.writeOpenTag(cSubsysUsesTag);
				{
					//<InterfaceRef name = "Interface 1" provider ="Low Level Subsystem 1"/>
					DesSubsystem::DependIteratorPtr depIt = subsys.createDependsIterator();
					for(depIt->first(); depIt->notDone(); depIt->next())
					{
						const DesSubsystem::Dependency& depend = depIt->currentItem();
						xw.writeAtomTag(cInterfRefTag, AttrMap(cInterfNameAttr, toString(depend.interface->getName()),
										cInterfProviderAttr, toString(depend.subsystem->getName())));
					}			
				}
				xw.writeCloseTag(cSubsysUsesTag);
			}
			else
			{
				xw.writeAtomTag(cSubsysUsesTag);
			}
		}
	}
	xw.writeCloseTag(cSubsysTag);
}

//_________________________________________________________________________________________________

void ProjectSerializer::writeProjInterfaces(XmlWriter& xw)
{
	DesHierProject::InterfIteratorPtr interfIt = hierProject()->createInterfIterator();
	for(interfIt->first(); interfIt->notDone(); interfIt->next())
	{
		const DesInterface& interf = interfIt->currentItem();
		writeInterface(xw, interf);
	}
}

//_________________________________________________________________________________________________

void ProjectSerializer::writeInterface(XmlWriter& xw, const DesInterface& interf)
{
	//Write the interface tag: e.g. <Interface name = "Interface 1">
	xw.writeOpenTag(cInterfaceTag, AttrMap(cInterfNameAttr, toString(interf.getName()),
										   cInterfValidStatusAttr, getInterfValidStatus(interf),
										   cInterfIConsistProp, getInterfIConsistProp(interf)));
	{
		//write all DES that are part of the interface
		//e.g. <Des name = "I1-Des-1" location="FullPath\I1-Des-1.des"/>
		DesInterface::DesIteratorPtr desIt = interf.createDesIterator();
		for(desIt->first(); desIt->notDone(); desIt->next())
		{
			const Des& des = desIt->currentItem();
			xw.writeAtomTag(cDesTag, AttrMap(cDesNameAttr, toString(des.getName()),
											 cDesLocationAttr, convertToRelative(toString(des.getFileName()))));
		}
	}
	xw.writeCloseTag(cInterfaceTag);
}

//_________________________________________________________________________________________________

ProjectType ProjectSerializer::getProjectType(const QString& projTypeName)
{
	if (projTypeName == cProjTypeFlatVal)
	{
		return eFlatProject;
	}
	else if (projTypeName == cProjTypeHierVal)
	{
		return eHierProject;
	}
	else
	{
		assert(true);
		qWarning("Unknown value \"%s\". Value will default to flat project", projTypeName.toAscii().data());		
		return eFlatProject;
	}
}

//_________________________________________________________________________________________________

QString ProjectSerializer::getProjectType()
{
	switch(m_project->getType())
	{
		case eFlatProject:
			return cProjTypeFlatVal;

		case eHierProject:
			return cProjTypeHierVal;

		default:
			assert(true);
			qWarning("Unknown project type value.");		
			return "ERROR: Unknown project type";
	}
}

//_________________________________________________________________________________________________

Integrity ProjectSerializer::getProjIntegrity(const QString& integStatusName)
{
	if (integStatusName == cProjIntegStatusYesVal)
	{
		return eIntegYes;
	}
	else if (integStatusName == cProjIntegStatusNoVal)
	{
		return eIntegNo;
	}
	else if ( integStatusName == cProjIntegStatusNotVerifVal)
	{
		return eIntegNotVerified;
	}
	else
	{
		assert(true);
		qWarning("Unknown value \"%s\". Value will default to integrity-not-verified", integStatusName.toAscii().data());		
		return eIntegNotVerified;
	}
}

//_________________________________________________________________________________________________

QString	ProjectSerializer::getProjIntegrity()
{
	switch(m_project->getIntegrity())
	{
		case eIntegYes:
			return cProjIntegStatusYesVal;

		case eIntegNo:
			return cProjIntegStatusNoVal;

		case eIntegNotVerified:
			return cProjIntegStatusNotVerifVal;

		default:
			assert(true);
			qWarning("Unknown project integrity value.");		
			return "ERROR: Unknown integrity value";
	}
}

//_________________________________________________________________________________________________

ControllableProp ProjectSerializer::getCtrlProp(const QString& ctrlPropName)
{
	if (ctrlPropName == cProjCtrlPropYesVal)
	{
		return eCtrlYes;
	}
	else if (ctrlPropName == cProjCtrlPropNoVal)
	{
		return eCtrlNo;
	}
	else if ( ctrlPropName == cProjCtrlPropNotVerifVal)
	{
		return eCtrlNotVerified;
	}
	else
	{
		assert(true);
		qWarning("Unknown value \"%s\". Value will default to not-verified", ctrlPropName.toAscii().data());		
		return eCtrlNotVerified;
	}
}

//_________________________________________________________________________________________________

QString ProjectSerializer::getCtrlProp()
{
	switch(m_project->getControllableProp())
	{
		case eCtrlYes:
			return cProjCtrlPropYesVal;

		case eCtrlNo:
			return cProjCtrlPropNoVal;

		case eCtrlNotVerified:
			return cProjCtrlPropNotVerifVal;

		default:
			assert(true);
			qWarning("Unknown project controllable property value.");		
			return "ERROR: Unknown controllable property value";
	}
}

//_________________________________________________________________________________________________

NonBlockingProp ProjectSerializer::getNonBlockProp(const QString& nonBlockPropName)
{
	if (nonBlockPropName == cProjNonBlockPropYesVal)
	{
		return eNonBlockYes;
	}
	else if (nonBlockPropName == cProjNonBlockPropNoVal)
	{
		return eNonBlockNo;
	}
	else if ( nonBlockPropName == cProjNonBlockPropNotVerifVal)
	{
		return eNonBlockNotVerified;
	}
	else
	{
		assert(true);
		qWarning("Unknown value \"%s\". Value will default to not-verified", nonBlockPropName.toAscii().data());		
		return eNonBlockNotVerified;
	}
}

//_________________________________________________________________________________________________

QString ProjectSerializer::getNonBlockProp()
{
	switch(m_project->getNonBlockingProp())
	{
		case eNonBlockYes:
			return cProjNonBlockPropYesVal;

		case eNonBlockNo:
			return cProjNonBlockPropNoVal;

		case eNonBlockNotVerified:
			return cProjNonBlockPropNotVerifVal;

		default:
			assert(true);
			qWarning("Unknown value nonblocking property value");		
			return "ERROR: Unknown non-blocking value";
	}
}

//_________________________________________________________________________________________________

IConsistProp ProjectSerializer::getProjIConsist(const QString& iConsName)
{
	if (iConsName == cProjIConsPropYesVal)
	{
		return eIConsYes;
	}
	else if (iConsName == cProjIConsPropNoVal)
	{
		return eIConsNo;
	}
	else if ( iConsName == cProjIConsPropNotVerifVal)
	{
		return eIConsNotVerified;
	}
	else
	{
		assert(true);
		qWarning("Unknown value \"%s\". Value will default to integrity-not-verified", iConsName.toAscii().data());		
		return eIConsNotVerified;
	}
}

//_________________________________________________________________________________________________

QString	ProjectSerializer::getProjIConsist()
{
	switch(hierProject()->getIConsistProp())
	{
		case eIConsYes:
			return cProjIConsPropYesVal;

		case eIConsNo:
			return cProjIConsPropNoVal;

		case eIConsNotVerified:
			return cProjIConsPropNotVerifVal;

		default:
			assert(true);
			qWarning("Unknown interface consistent property value.");		
			return "ERROR: Unknown interface consistent property value";
	}
}

//_________________________________________________________________________________________________

LwCtrlProp ProjectSerializer::getLwCtrlProp(const QString& lwCtrlPropName)
{
	if (lwCtrlPropName == cProjLwCtrlPropYesVal)
	{
		return eLwCtrlYes;
	}
	else if (lwCtrlPropName == cProjLwCtrlPropNoVal)
	{
		return eLwCtrlNo;
	}
	else if ( lwCtrlPropName == cProjLwCtrlPropNotVerifVal)
	{
		return eLwCtrlNotVerified;
	}
	else
	{
		assert(true);
		qWarning("Unknown value \"%s\". Value will default to not-verified", lwCtrlPropName.toAscii().data());		
		return eLwCtrlNotVerified;
	}
}

//_________________________________________________________________________________________________

QString ProjectSerializer::getLwCtrlProp()
{
	switch(hierProject()->getLwCtrlProp())
	{
		case eLwCtrlYes:
			return cProjLwCtrlPropYesVal;

		case eLwCtrlNo:
			return cProjLwCtrlPropNoVal;

		case eLwCtrlNotVerified:
			return cProjLwCtrlPropNotVerifVal;

		default:
			assert(true);
			qWarning("Unknown project LD level-wise controllable property value.");		
			return "ERROR: Unknown LD level-wise controllable property value";
	}
}

//_________________________________________________________________________________________________

LwNonBlockProp ProjectSerializer::getLwNonBlockProp(const QString& lwNonBlockPropName)
{
	if (lwNonBlockPropName == cProjLwNonBlockPropYesVal)
	{
		return eLwNonBlockYes;
	}
	else if (lwNonBlockPropName == cProjLwNonBlockPropNoVal)
	{
		return eLwNonBlockNo;
	}
	else if ( lwNonBlockPropName == cProjLwNonBlockPropNotVerifVal)
	{
		return eLwNonBlockNotVerified;
	}
	else
	{
		assert(true);
		qWarning("Unknown value \"%s\". Value will default to not-verified", lwNonBlockPropName.toAscii().data());		
		return eLwNonBlockNotVerified;
	}
}

//_________________________________________________________________________________________________

QString ProjectSerializer::getLwNonBlockProp()
{
	switch(hierProject()->getLwNonBlockProp())
	{
		case eLwNonBlockYes:
			return cProjLwNonBlockPropYesVal;

		case eLwNonBlockNo:
			return cProjLwNonBlockPropNoVal;

		case eLwNonBlockNotVerified:
			return cProjLwNonBlockPropNotVerifVal;

		default:
			assert(true);
			qWarning("Unknown value LD level-wise nonblocking property value");		
			return "ERROR: Unknown LD level-wise non-blocking value";
	}
}


//_________________________________________________________________________________________________

QString ProjectSerializer::getLevelValue(const DesSubsystem& subsys)
{
	return QVariant(subsys.getLevel()).toString();
}

//_________________________________________________________________________________________________

bool ProjectSerializer::getSubsysLwCtrlProp(const QString& lwCtrlPropName)
{
	if (lwCtrlPropName == cSubsysLwCtrlYesVal)
	{
		return true;
	}
	else if (lwCtrlPropName == cSubsysLwCtrlNoVal)
	{
		return false;
	}
	else
	{
		assert(true);
		qWarning("Unknown value \"%s\". Value will default to -no-", lwCtrlPropName.toAscii().data());		
		return false;
	}
}

//_________________________________________________________________________________________________

QString ProjectSerializer::getSubsysLwCtrlProp(const DesSubsystem& subsys)
{
	return subsys.isControllable() ? cSubsysLwCtrlYesVal : cSubsysLwCtrlNoVal;
}

//_________________________________________________________________________________________________

bool ProjectSerializer::getSubsysLwNonBlockProp(const QString& lwNonBlockPropName)
{
	if (lwNonBlockPropName == cSubsysLwNonBlockYesVal)
	{
		return true;
	}
	else if (lwNonBlockPropName == cSubsysLwNonBlockNoVal)
	{
		return false;
	}
	else
	{
		assert(true);
		qWarning("Unknown value \"%s\". Value will default to -no-", lwNonBlockPropName.toAscii().data());		
		return false;
	}
}

//_________________________________________________________________________________________________

QString ProjectSerializer::getSubsysLwNonBlockProp(const DesSubsystem& subsys)
{
	return subsys.isNonBlocking() ? cSubsysLwNonBlockYesVal : cSubsysLwNonBlockNoVal;
}

//_________________________________________________________________________________________________

bool ProjectSerializer::getSubsysIConsistProp(const QString& iConsistPropName)
{
	if (iConsistPropName == cSubsysIConsistYesVal)
	{
		return true;
	}
	else if (iConsistPropName == cSubsysIConsistNoVal)
	{
		return false;
	}
	else
	{
		assert(true);
		qWarning("Unknown value \"%s\". Value will default to -no-", iConsistPropName.toAscii().data());		
		return false;
	}
}

//_________________________________________________________________________________________________

QString ProjectSerializer::getSubsysIConsistProp(const DesSubsystem& subsys)
{
	return subsys.isInterfConsist() ? cSubsysIConsistYesVal : cSubsysIConsistNoVal;  
}

//_________________________________________________________________________________________________

bool ProjectSerializer::getInterfIConsistProp(const QString& iConsistPropName)
{
	if (iConsistPropName == cInterfIConsistYesVal)
	{
		return true;
	}
	else if (iConsistPropName == cInterfIConsistNoVal)
	{
		return false;
	}
	else
	{
		assert(true);
		qWarning("Unknown value \"%s\". Value will default to -no-", iConsistPropName.toAscii().data());		
		return false;
	}
}

//_________________________________________________________________________________________________

QString ProjectSerializer::getInterfIConsistProp(const DesInterface& interf)
{
	return interf.isInterfConsist() ? cInterfIConsistYesVal : cInterfIConsistNoVal;  
}

//_________________________________________________________________________________________________

bool ProjectSerializer::getSubsysValidStatus(const QString& validStatusName)
{
	if (validStatusName == cSubsysValidStatusYesVal)
	{
		return true;
	}
	else if (validStatusName == cSubsysValidStatusNoVal)
	{
		return false;
	}
	else
	{
		assert(true);
		qWarning("Unknown value \"%s\". Value will default to -no-", validStatusName.toAscii().data());		
		return false;
	}
}

//_________________________________________________________________________________________________

QString ProjectSerializer::getSubsysValidStatus(const DesSubsystem& subsys)
{
	return subsys.isValid() ? cSubsysValidStatusYesVal : cSubsysValidStatusNoVal;  
}

//_________________________________________________________________________________________________

bool ProjectSerializer::getInterfValidStatus(const QString& validStatusName)
{
	if (validStatusName == cInterfValidStatusYesVal)
	{
		return true;
	}
	else if (validStatusName == cInterfValidStatusNoVal)
	{
		return false;
	}
	else
	{
		assert(true);
		qWarning("Unknown value \"%s\". Value will default to -no-", validStatusName.toAscii().data());		
		return false;
	}
}

//_________________________________________________________________________________________________

QString ProjectSerializer::getInterfValidStatus(const DesInterface& interf)
{
	return interf.isValid() ? cInterfValidStatusYesVal : cInterfValidStatusNoVal;  
}

//_________________________________________________________________________________________________

void ProjectSerializer::setProjectProperties()
{
	m_projectAccess->setIntegrity(m_integStatus);
	m_projectAccess->setIntegrityStamp(m_integDateStamp);

	m_projectAccess->setNonBlockingProp(m_nonBlockStatus);
	m_projectAccess->setNonBlockingStamp(m_nonBlockDateStamp);

	m_projectAccess->setControllableProp(m_ctrlStatus);
	m_projectAccess->setCtrlStamp(m_ctrlDateStamp);

	if (m_project->getType() == eHierProject)
	{
		hierProjAccess()->setIConsistProp(m_iConsStatus);
		hierProjAccess()->setIConsistStamp(m_iConsDateStamp);

		hierProjAccess()->setLwNonBlockProp(m_lwNonBlockStatus);
		hierProjAccess()->setLwNonBlockStamp(m_lwNonBlockDateStamp);

		hierProjAccess()->setLwCtrlProp(m_lwCtrlStatus);
		hierProjAccess()->setLwCtrlStamp(m_lwCtrlDateStamp);
	}
}

//_________________________________________________________________________________________________

void ProjectSerializer::resolveInterfImplementations()
{
	for(unsigned int i = 0; i < m_unresImpls.size(); i++)
	{
		InterfImpl& unresImpl = m_unresImpls[i];
		DesInterface* interf = hierProjAccess()->getInterface(unresImpl.interfName);
		unresImpl.subsys->setInterface(*interf);
	}
}

//_________________________________________________________________________________________________

void ProjectSerializer::resolveSubsysDependencies()
{
	for(unsigned int i = 0; i < m_unresDepends.size(); i++)
	{
		SubsysDependency& unresDepend = m_unresDepends[i];
		DesInterface* interf = hierProjAccess()->getInterface(unresDepend.dependRef.interfName);
		DesSubsystem* lSubsys = hierProjAccess()->getSubsystem(unresDepend.dependRef.subsysName);
		unresDepend.subsys->addDependency(interf, lSubsys);
	}
}

//_________________________________________________________________________________________________

QString ProjectSerializer::toString(int intVal)
{
	return QVariant(intVal).toString();
}

//_________________________________________________________________________________________________

QString ProjectSerializer::toString(const std::wstring stdStr)
{
	return QString::fromStdWString(stdStr);
}

//_________________________________________________________________________________________________

QString ProjectSerializer::convertToRelative(const QString& desFileName)
{
	QFileInfo projFileInfo(m_fileName);
	QDir projDir = projFileInfo.dir();
	return projDir.relativeFilePath(desFileName);
}

//_________________________________________________________________________________________________

QString ProjectSerializer::convertToAbsolute(const QString& desRelativeFileName)
{
	if (desRelativeFileName.isEmpty())
		return QString();

	QFileInfo projFileInfo(m_fileName);
	QDir projDir = projFileInfo.dir();
	return QDir::cleanPath(projDir.absoluteFilePath(desRelativeFileName));
}

} // end of namespace DESpot
