# stuff to add for bddhisc

//aside: toString(stdwstring)   seems to be locally defined and
//  produces a QString



#include <QString>
#include "DesFlatProject.h"
#include "DesHierProject.h"
#include "Des.h"
#include "DesProject.h"
//#include "DesFlatProject.h"
#include "DesHierProject.h"
#include "DesSubsystem.h"
#include "DesInterface.h"



  if (!m_pProject->isValid()) 
    {
       throw EX("Project integrity test must pass before exporting allowed.");
    }

# export uses project serializer:   ProjectSerializer
#  projLoader(*this);
#   called from a project funcion
#ProjectSerializer(DesProject& project);
# perhaps use: DesHierProject instead?

#include "ProjectEvent.h"


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

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

	}
  }


# add a check to exclude low-data events for now.  remove when
#  supported.   still will be needed for synthesis.


# make sure to load low levels before the high level for bbddhisc.

#example project file:
[SYSTEM]
Simple illustrative example  #project name

[LOW]
1    #num of low levels
low1  #list of low level directory

[HIGH]
high   #high level directory



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


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




#Output the low subsystems

   // 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++;
	 }
     }



# now export high level


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





# now export an actual des:
#  des.exportToBDDhiscORsd(tmpFileName,true,true)

# 	DesSerializer saver(*this);
# DesSerializer(Des& des);

#include "Des.h"
//#include "DesTypes.h"
//#include "DesStatePool.h"
//#include "DesEventPool.h"
//#include "DesTransitionFunction.h"

   desOut << "[States] \n";  

   int numStates = 0;
   // count the number of states
{
   Des::StateIteratorPtr stateIt = m_des.createStateIterator();
   for(stateIt->first(); stateIt->isDone() == false; stateIt->next())
     {
       numStates++;
     }
 }

   desOut << numStates << "\n"; 

   // output list of states
{
   Des::StateIteratorPtr stateIt = m_des.createStateIterator();
   for(stateIt->first(); stateIt->isDone() == false; stateIt->next())
     {
       const DesState& state = stateIt->currentItem();
       desOut << toString(state.getName()) << "\n"; 
     }
 }


   desOut <<  "\n[InitState]\n";

   if (m_des.hasInitialState())
     {
       const DesState& initState = m_des.getInitialState();
       desOut << toString(initState.getName()) << "\n\n"; 
     }

   desOut <<  "[MarkingStates]\n";  

   // output list of marking states
{
   Des::StateIteratorPtr stateIt = m_des.createStateIterator();
   for(stateIt->first(); stateIt->isDone() == false; stateIt->next())
     {
       const DesState& state = stateIt->currentItem();
       if (state.isMarked())
	 {
	   desOut << toString(state.getName()) << "\n";
	 }
     }
 }



  desOut <<  "\n[Events]\n";  

  //create list of events with cont and type info
  Des::EventIteratorPtr eventIt = m_des.createEventIterator();
  for(eventIt->first(); eventIt->isDone() == false; eventIt->next())
    {
      const DesEvent& event = eventIt->currentItem();
    
      QString contString = "N";
      QString eTypeString = "";

      if (event.isControllable())
	{
	  contString = "Y";
	}
    

      //if we are exporting for bddsd, we just set the event type to
      //low as bddsd will ignore this.

      if (!(isHISC)) 
	{
	  eTypeString = "L";
	} else 	{

	  switch(event.getType())
	    {
	    case eDefaultEvent:
	      if (isHigh) 
		{
		  eTypeString = "H";
		}
	      else 
		{
		  eTypeString = "L";
		}
	      break;
	    case eAnswerEvent:
	      eTypeString = "A";
	      break;
	    case eRequestEvent:
	      eTypeString = "R";
	      break;
	    case eLDataEvent:
	      eTypeString = "D";
	      break;
	    case eHighLevelEvent:
	      eTypeString = "H";
	      break;
	    case eLowLevelEvent:
	      eTypeString = "L";
	      break;
	    default:
	      assert(false); //unknown event type
	      break;
	    }
	}
    
      desOut << toString(event.getName()) << "\t" << contString  << "\t" <<  eTypeString  << "\n";  

    }				 	    

  desOut <<  "\n[Transitions]\n";  


  // create list of transitions
{
   Des::StateIteratorPtr stateIt = m_des.createStateIterator();
   for(stateIt->first(); stateIt->isDone() == false; stateIt->next())
     {
       const DesState& state = stateIt->currentItem();
       bool firstTime = true;

       Des::TransIteratorPtr transIt = m_des.createTransIterator(false);   //false - include global self-loops

       for(transIt->first(); !transIt->isDone(); transIt->next())
	 {
	   const DesTransition& trans = transIt->currentItem();
	   const DesState& fromState = trans.fromState();
	   const DesState& toState = trans.toState();
	   const DesEvent& event=  trans.event();

	   if (state != fromState)
	     {
	       continue;
	     }

	   if (firstTime) 
	     {
	       firstTime = false;
	       desOut << toString(state.getName()) << "\n";
	     }

	   desOut << "(" << toString(event.getName())  << "\t" << toString(toState.getName()) << ")" << "\n";
	 }
     }
}




//  need to map bddhisc error messages to DESpot output
//  same for when they throw an exception.

