#---------------------------------------------------------------------
#      SCC (StateChart Compiler)
#           -- a compiler for an extended statechart formalism
#---------------------------------------------------------------------
#
# Copyright (C) 2003 Thomas Huining Feng
#
#---------------------------------------------------------------------
# Address:      MSDL, SOCS, McGill Univ., Montreal, Canada
# HomePage:     http://msdl.cs.mcgill.ca/people/tfeng/
# SCC HomePage: http://msdl.cs.mcgill.ca/people/tfeng/?research=scc
# Download:     http://savannah.nongnu.org/files/?group=svm
# CVS:          :pserver:anoncvs@subversions.gnu.org:/cvsroot/svm
#               (projects "svm" and "jsvm")
# Email:        hfeng2@cs.mcgill.ca
#---------------------------------------------------------------------
#
# This file is part of SCC.
#
#---------------------------------------------------------------------
# SCC is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#
# SCC is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SCC; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#---------------------------------------------------------------------


from string import *
from StringUtil import *
from EventHandler import EventHandler
from CodeGenerator import *
import time

class CppGenerator(CodeGenerator):
  CppHeaderInterface='\
// C++ interface generated by SCC (StateChart Compiler) 0.3, written by Thomas Feng\n\
//   Source: [MODEL_FILE]\n\
//   Date:   [DATE]\n\
//   Time:   [TIME]\n\
[DESCRIPTION]\
\n\
// Header Section -- definition and module importation used by the following parts\n\
[PYTHON_HEAD]\
#include <iostream>\n\
#include <string>\n\
#include <time.h>\n\
using namespace std;\n\
\n\
#define null 0\n\
#define boolean bool\n\
\n\
class State {\n\
public:\n\
  int StateID;\n\
  State* Next;\n\
  State();\n\
  ~State();\n\
};\n\
\n\
class StateMachine;\n\
class History {\n\
public:\n\
  int* States;\n\
  long* Times;\n\
  StateMachine* Submodel;\n\
  History();\n\
  ~History();\n\
};\n\
\n\
class EventList {\n\
public:\n\
  string Event;\n\
  EventList* Next;\n\
  EventList();\n\
  ~EventList();\n\
  void Append(string e);\n\
  void Append(EventList* el);\n\
};\n\
\n\
class StringList {\n\
public:\n\
  string str;\n\
  StringList* Next;\n\
  StringList();\n\
  StringList(string str);\n\
  ~StringList();\n\
};\n\
\n\
[ADDITIONAL_CLASSES]\
class HierarchyList {\n\
public:\n\
  string StateName;\n\
  string PathName;\n\
  int StateNum;\n\
  int Level;\n\
  HierarchyList* Next;\n\
  HierarchyList();\n\
  ~HierarchyList();\n\
};\n\
\n\
class StateMachine {\n\
protected:\n\
  virtual int eventStr2Int(string event)=0;\n\
\n\
public:\n\
  virtual ~StateMachine();\n\
  virtual void topLevelHistory()=0;\n\
  virtual StringList* getCurrentStateList()=0;\n\
  virtual string getCurrentState()=0;\n\
  virtual EventList* getEnabledEvents()=0;\n\
  virtual bool isInState(int s, bool check_substate=true)=0;\n\
  virtual bool isInState(string s, bool check_substate=true)=0;\n\
  virtual int getParentState(int state)=0;\n\
  virtual boolean isHistoryState(int state)=0;\n\
  virtual boolean isLeafState(string state)=0;\n\
  HierarchyList* getHierarchy();\n\
  virtual HierarchyList* getHierarchy(int start_level, string state_prefix)=0;\n\
[SM_MODEL_INTERFACE]\
};\n\
\n'

  CppHeaderImplementation='\
// C++ implementation generated by SCC (StateChart Compiler) 0.3, written by Thomas Feng\n\
//   Source: [MODEL_FILE]\n\
//   Date:   [DATE]\n\
//   Time:   [TIME]\n\
[DESCRIPTION]\
[INCLUDE_STR]\
\n\
[PYTHON_INTERFACE_IMPLEMENTATION]\
// Implementation of class "State" in the header\n\
State::State() {\n\
  StateID=-1;\n\
  Next=null;\n\
}\n\
State::~State() {\n\
  if (Next!=null)\n\
    delete Next;\n\
}\n\
\n\
// Implementation of class "History" in the header\n\
History::History() {\n\
  States=null;\n\
  Times=null;\n\
  Submodel=null;\n\
}\n\
History::~History() {\n\
  if (States!=null)\n\
    delete[] States;\n\
  if (Times!=null)\n\
    delete[] Times;\n\
}\n\
\n\
// Implementation of class "EventList" in the header\n\
EventList::EventList() {\n\
  Next=null;\n\
}\n\
EventList::~EventList() {\n\
  if (Next!=null)\n\
    delete Next;\n\
}\n\
void EventList::Append(string e) {\n\
  EventList* el=new EventList;\n\
  el->Event=e;\n\
  EventList* cur=this;\n\
  while (cur->Next!=null && cur->Event!=e)\n\
    cur=cur->Next;\n\
  if (cur->Event!=e)\n\
    cur->Next=el;\n\
}\n\
void EventList::Append(EventList* el) {\n\
  while (el!=null) {\n\
    Append(el->Event);\n\
    el=el->Next;\n\
  }\n\
}\n\
\n\
// Implementation of class "StringList" in the header\n\
StringList::StringList() {\n\
  StringList("");\n\
}\n\
StringList::StringList(string str) {\n\
  Next=null;\n\
  this->str=str;\n\
}\n\
StringList::~StringList() {\n\
  if (Next!=null)\n\
    delete Next;\n\
}\n\
\n\
[ADDITIONAL_IMPLEMENTATION]\
// Implementation of class "HierarchyList" in the header\n\
HierarchyList::HierarchyList() {\n\
  StateNum=-1;\n\
  Level=-1;\n\
  Next=null;\n\
}\n\
HierarchyList::~HierarchyList() {\n\
  if (Next!=null)\n\
    delete Next;\n\
}\n\
\n\
// Implementation of class "StateMachine" in the header\n\
StateMachine::~StateMachine() {\n\
}\n\
HierarchyList* StateMachine::getHierarchy() {\n\
  return getHierarchy(0, null);\n\
}\n\
\n\
// Global method\n\
boolean startsWith(string s, string head) {\n\
  return (s.length()>=head.length() && s.substr(0, head.length())==head);\n\
}\n\
\n'

  CppTemplateInterface='\
[HEADER_INTERFACE]\
[ACCESSIBILITY_INTERFACE]class [MODEL_NAME] : public StateMachine {\n\
private:\n\
  // Constants for this model\n\
  static const int     StateNum=[STATE_NUM];\n\
  static const char*   EventNames[[EVENT_NUM]];\n\
  static const char*   StateNames[[STATE_NUM]];\n\
  static const int     ParentTable[[STATE_NUM]];\n\
  static const int     HistoryStateTable[[STATE_NUM]];\n\
  static const char*   LeafStateTable[[STATE_NUM]];\n\
  static const boolean OrthogonalInBetween[[STATE_NUM]+1][[STATE_NUM]];\n\
  static const int     CommonStateTable[[STATE_NUM]][[STATE_NUM]];\n\
  static const boolean Hierarchy[[STATE_NUM]][[STATE_NUM]];\n\
  static const char*   Description;\n\
\n\
[PUBLIC_CONSTANTS_INTERFACE]\
  // Variables\n\
  State* state;\n\
  StateMachine* Submodels[[STATE_NUM]];\n\
  History* history[[STATE_NUM]];\n\
  bool Started;\n\
[EXTENDED_VARIABLES]\
\n\
public:\n\
  // Constructor\n\
[CONSTRUCTOR_INTERFACE]\
  virtual ~[MODEL_NAME]();\n\
[MDL_ACTION_INTERFACE]\
\n\
private:\n\
  boolean isParent(int sp, int sc);\n\
  boolean addInState(int s);\n\
  void generateStates(int common, int dest, int history_type=0);\n\
  void removeOutStates(int common_state);\n\
  string stateInt2Str(int state);\n\
  boolean isLeafState(int state);\n\
  boolean isHistoryUp2Date(int state, long time);\n\
  void mergeHistory(int state, int* states, long* times);\n\
  void recordHistory(int top_state);\n\
  boolean hasHistoryRecorded(int state);\n\
  boolean hasOrthogonalStateInBetween(int parent, int leaf);\n\
  boolean check_history(int dest);\n\
  string getCurrentState(StringList* states);\n\
\n\
protected:\n\
  virtual int eventStr2Int(string event);\n\
\n\
public:\n\
  virtual boolean isInState(int s, bool check_substate=true);\n\
  virtual boolean isInState(string s, bool check_substate=true);\n\
  static void main(int argn, char** argv);\n\
[INIT_MODEL_INTERFACE]\
  void forceIntoState(int s);\n\
  void changeState(int s1, int s2, boolean check_history=false);\n\
  virtual StringList* getCurrentStateList();\n\
  virtual string getCurrentState();\n\
  virtual int getParentState(int state);\n\
  virtual boolean isHistoryState(int state);\n\
  virtual boolean isLeafState(string state);\n\
  virtual EventList* getEnabledEvents();\n\
  virtual HierarchyList* getHierarchy(int start_level, string state_prefix);\n\
  virtual void topLevelHistory();\n\
};\n\
\n\
[OTHER_MODELS_INTERFACE]\
\n'

  CppTemplateImplementation='\
[HEADER_IMPLEMENTATION]\
\n\
[ACCESSIBILITY_IMPLEMENTATION]\
\n\
// Static arrays\n\
\n\
[EVENT_INT2STR_TABLE]\
[STATE_INT2STR_TABLE]\
[PARENT_TABLE]\
[HISTORY_STATE_TABLE]\
[LEAF_STATE_TABLE]\
[ORTHOGONAL_IN_BETWEEN]\
[HIERARCHY_DEFINITION]\
[COMMON_STATE_TABLE]\
const char* [MODEL_NAME]::Description=[ESC_DESCRIPTION];\n\
[PUBLIC_CONSTANTS_IMPLEMENTATION]\
\n\
[CONSTRUCTOR_IMPLEMENTATION]\
[MODEL_NAME]::~[MODEL_NAME]() {\n\
  if (state!=null)\n\
    delete state;\n\
  for (int i=0; i<StateNum; i++) {\n\
    if (Submodels[i]!=null)\n\
      delete Submodels[i];\n\
    if (history[i]!=null)\n\
      delete history[i];\n\
  }\n\
[DESTROY_LOCK]\
}\n\
[START_CODE]\
boolean [MODEL_NAME]::isParent(int sp, int sc) {\n\
  return sc>=0 && (sp<0 || Hierarchy[sp][sc]);\n\
}\n\
boolean [MODEL_NAME]::isInState(int s, bool check_substate) {\n\
  State* st=state;\n\
  while (st!=null) {\n\
    if (st->StateID==s || (check_substate && isParent(s, st->StateID)))\n\
      return true;\n\
    else\n\
      st=st->Next;\n\
  }\n\
  return false;\n\
}\n\
boolean [MODEL_NAME]::isInState(string s, bool check_substate) {\n\
  for (int i=0; i<StateNum; i++)\n\
    if (s==StateNames[i])\n\
      return isInState(i, check_substate);\n\
  for (int i=0; i<StateNum; i++) {\n\
    string stname=StateNames[i];\n\
    if (Submodels[i]!=null && startsWith(s, stname+".")) {\n\
      int pos=stname.length()+1;\n\
      string SubmodelState=s.substr(pos, s.length()-pos);\n\
      return isInState(i) && Submodels[i]->isInState(SubmodelState, check_substate);\n\
    }\n\
  }\n\
  return false;\n\
}\n\
void [MODEL_NAME]::main(int argn, char** argv) {\n\
[INTERFACE]\
}\n\
[INIT_CODE]\
[EVENT_CODE]\
void [MODEL_NAME]::forceIntoState(int s) {\n\
  boolean changed=false;\n\
  State* s2=state;\n\
  while (s2!=null) {\n\
    boolean HasCommonParent=false;\n\
    for (int i=0; i<StateNum; i++)\n\
      if (isParent(i, s2->StateID) && isParent(i, s)) {\n\
        HasCommonParent=true;\n\
        if (!hasOrthogonalStateInBetween(i, s2->StateID)) {\n\
          changeState(s2->StateID, s);\n\
          changed=true;\n\
        }\n\
      }\n\
    if (!HasCommonParent) {\n\
      changeState(s2->StateID, s);\n\
      changed=true;\n\
    }\n\
    s2=s2->Next;\n\
  }\n\
  if (!changed)\n\
    addInState(s);\n\
}\n\
void [MODEL_NAME]::changeState(int s1, int s2, boolean check_history) {\n\
  // t1=common(s1, s2)\n\
  int t1=[MODEL_NAME]::CommonStateTable[s1][s2];\n\
  recordHistory(t1);\n\
  if (t1>=0)\n\
    removeOutStates(t1);\n\
  else\n\
    state=null;\n\
  // t2=history(s2)\n\
  int t2=[MODEL_NAME]::HistoryStateTable[s2];\n\
  if (t2==0) // no history\n\
    generateStates(t1, s2);\n\
  else if (t2==1) // normal history\n\
    if (!check_history)\n\
      generateStates(t1, s2);\n\
    else if (hasHistoryRecorded(s2))\n\
      generateStates(t1, history[s2]->States[s2]);\n\
    else\n\
      generateStates(t1, s2, 1);\n\
  else if (t2==2) // deep history\n\
    if (check_history && hasHistoryRecorded(s2))\n\
      for (int i=0; i<[MODEL_NAME]::StateNum; i++) {\n\
        int hs=history[s2]->States[i];\n\
        if (hs>=0 && isLeafState(hs)) {\n\
[CHANGE_STATE_RECORD_ENTER]\
          addInState(hs);\n\
        }\n\
      }\n\
    else\n\
      generateStates(t1, s2);\n\
}\n\
boolean [MODEL_NAME]::addInState(int s) {\n\
  if (!isInState(s)) {\n\
    State* st=new State();\n\
    st->StateID=s;\n\
    st->Next=state;\n\
    state=st;\n\
    return true;\n\
  }\n\
  else\n\
    return false;\n\
}\n\
void [MODEL_NAME]::generateStates(int common, int dest, int history_type) {\n\
[STATES_CODE]\
}\n\
void [MODEL_NAME]::removeOutStates(int common_state) {\n\
  State *s=state, *prev=null;\n\
  while (s!=null) {\n\
    if (isParent(common_state, s->StateID))\n\
      if (prev==null)\n\
        state=state->Next;\n\
      else\n\
        prev->Next=s->Next;\n\
    else\n\
      prev=s;\n\
    s=s->Next;\n\
  }\n\
}\n\
string [MODEL_NAME]::stateInt2Str(int state) {\n\
  if (state==-1)\n\
    return "";\n\
  else\n\
    return StateNames[state];\n\
}\n\
int [MODEL_NAME]::eventStr2Int(string event) {\n\
  for (int i=0; i<[EVENT_NUM]; i++)\n\
    if (event==EventNames[i])\n\
      return i;\n\
  return -1;\n\
}\n\
StringList* [MODEL_NAME]::getCurrentStateList() {\n\
  StringList *sl=new StringList, *slend=sl;\n\
  State *s=state;\n\
  while (s!=null) {\n\
    StateMachine *sm=Submodels[s->StateID];\n\
    string curstate=stateInt2Str(s->StateID);\n\
    if (sm!=null) {\n\
      slend->Next=sm->getCurrentStateList();\n\
      while (slend->Next!=null) {\n\
        slend->Next->str=curstate+"."+slend->Next->str;\n\
        slend=slend->Next;\n\
      }\n\
    }\n\
    else {\n\
      slend->Next=new StringList(curstate);\n\
      slend=slend->Next;\n\
    }\n\
    s=s->Next;\n\
  }\n\
  return sl->Next;\n\
}\n\
string [MODEL_NAME]::getCurrentState() {\n\
  return getCurrentState(null);\n\
}\n\
string [MODEL_NAME]::getCurrentState(StringList* states) {\n\
    string strst;\n\
    if (states==null) {\n\
      states=getCurrentStateList();\n\
      if (states!=null)\n\
        strst="["+getCurrentState(states)+"\\\'"+states->str+"\\\'"+"]";\n\
      else\n\
        strst="[]";\n\
    }\n\
    else {\n\
      if (states->Next!=null)\n\
        strst=getCurrentState(states->Next)+"\\\'"+states->Next->str+"\\\'"+", ";\n\
      else\n\
        strst="";\n\
    }\n\
    return strst;\n\
}\n\
int [MODEL_NAME]::getParentState(int state) {\n\
  return ParentTable[state];\n\
}\n\
boolean [MODEL_NAME]::isHistoryState(int state) {\n\
  return HistoryStateTable[state]>0;\n\
}\n\
boolean [MODEL_NAME]::isLeafState(string state) {\n\
  for (int i=0; i<StateNum; i++) {\n\
    if (LeafStateTable[i]==null)\n\
      continue;\n\
    if (state==LeafStateTable[i] && Submodels[i]==null)\n\
      return true;\n\
    else if (startsWith(state, string(LeafStateTable[i])+".") && Submodels[i]!=null) {\n\
      int pos=string(LeafStateTable[i]).length()+1;\n\
      string SubmodelState=state.substr(pos, state.length()-pos);\n\
      return Submodels[i]->isLeafState(SubmodelState);\n\
    }\n\
  }\n\
  return false;\n\
}\n\
boolean [MODEL_NAME]::isLeafState(int state) {\n\
  return LeafStateTable[state]!=null;\n\
}\n\
boolean [MODEL_NAME]::isHistoryUp2Date(int state, long time) {\n\
  for (int i=0; i<StateNum; i++)\n\
    if (history[state]->Times[i]>=time)\n\
      return true;\n\
  return false;\n\
}\n\
void [MODEL_NAME]::mergeHistory(int state, int* states, long* times) {\n\
  long max=-1;\n\
  for (int i=0; i<StateNum; i++)\n\
    if (times[i]>max)\n\
      max=times[i];\n\
  if (isHistoryUp2Date(state, max)) {\n\
    for (int i=0; i<StateNum; i++)\n\
      if (times[i]>history[state]->Times[i]) {\n\
        history[state]->States[i]=states[i];\n\
        history[state]->Times[i]=times[i];\n\
      }\n\
  }\n\
  else\n\
    for (int i=0; i<StateNum; i++) {\n\
      history[state]->States[i]=states[i];\n\
      history[state]->Times[i]=times[i];\n\
    }\n\
}\n\
void [MODEL_NAME]::recordHistory(int top_state) {\n\
  long time=clock();\n\
  State *s=state;\n\
  while (s!=null) {\n\
    int child=s->StateID;\n\
    int states[StateNum];\n\
    long times[StateNum];\n\
    for (int i=0; i<StateNum; i++) {\n\
      states[i]=-1;\n\
      times[i]=-1;\n\
    }\n\
    states[child]=child;\n\
    times[child]=time;\n\
    if (top_state<0 || isParent(top_state, child)) {\n\
      int parent=getParentState(child);\n\
      if (isHistoryState(child))\n\
        history[child]->Submodel=Submodels[child];\n\
      while (parent!=top_state && times[parent]!=time) {\n\
        states[parent]=child;\n\
        times[parent]=time;\n\
        if (isHistoryState(parent))\n\
          mergeHistory(parent, states, times);\n\
        child=parent;\n\
        parent=getParentState(child);\n\
      }\n\
    }\n\
    s=s->Next;\n\
  }\n\
}\n\
boolean [MODEL_NAME]::hasHistoryRecorded(int state) {\n\
  for (int i=0; i<StateNum; i++) {\n\
    if (history[state]->States[i]!=-1)\n\
      return true;\n\
    if (Submodels[state]!=null)\n\
      return true;\n\
  }\n\
  return false;\n\
}\n\
boolean [MODEL_NAME]::hasOrthogonalStateInBetween(int parent, int leaf) {\n\
  return OrthogonalInBetween[parent+1][leaf];\n\
}\n\
boolean [MODEL_NAME]::check_history(int dest) {\n\
  State *s=state;\n\
  while (s!=null) {\n\
    if (isParent(dest, s->StateID) && !hasOrthogonalStateInBetween(dest, s->StateID))\n\
      return false;\n\
    s=s->Next;\n\
  }\n\
  return true;\n\
}\n\
EventList* [MODEL_NAME]::getEnabledEvents() {\n\
[ENABLED_EVENTS_CODE]\
}\n\
HierarchyList* [MODEL_NAME]::getHierarchy(int start_level, string state_prefix) {\n\
[HIERARCHY_CODE]\
}\n\
void [MODEL_NAME]::topLevelHistory() {\n\
  int s=state->StateID, t;\n\
  do {\n\
    t=getParentState(s);\n\
    if (t!=-1)\n\
      s=t;\n\
  } while (t!=-1);\n\
  changeState(s, s);\n\
}\n\
[MDL_ACTION_IMPLEMENTATION]\
\n\
[OTHER_MODELS_IMPLEMENTATION]\
\n\
[ENDING]'
    
  TextInterface='\
  [MODEL_NAME] model;\n\
  string cmd="";\n\
  model.initModel();\n\
  if ([MODEL_NAME]::Description!=null)\n\
    cout << [MODEL_NAME]::Description << endl;\n\
  while (cin && cmd!="exit") {\n\
    cout << model.getCurrentState() << " > ";\n\
    getline(cin, cmd);\n\
    if (!cin || cmd=="exit")\n\
      break;\n\
    model.handleEvent(cmd);\n\
  }\n'

  TextInterfaceExt='\
  Py_Initialize();\n\
  [MODEL_NAME] model;\n\
  string cmd="";\n\
  model.initModel();\n\
  if (model.HasInteractor)\n\
    model.runInteractor();\n\
  else {\n\
    pthread_mutex_t lock;\n\
    pthread_mutex_init(&lock, null);\n\
    if ([MODEL_NAME]::Description!=null)\n\
      cout << [MODEL_NAME]::Description << endl;\n\
    while (cin && cmd!="exit") {\n\
      cout << model.getCurrentState() << " > ";\n\
      getline(cin, cmd);\n\
      if (!cin || cmd=="exit")\n\
        break;\n\
      pthread_mutex_lock(&lock);\n\
      model.event(cmd, null, null, &lock);\n\
      pthread_mutex_lock(&lock);\n\
      pthread_mutex_unlock(&lock);\n\
    }\n\
    pthread_mutex_destroy(&lock);\n\
  }\n\
  model.runFinalizer();\n\
  Py_Finalize();\n'

  def __init__(self, eventhandler, action_ext=0):
    CodeGenerator.__init__(self, eventhandler, "cpp")
    self.action_ext=action_ext

    if self.action_ext:
      self.actions=[]
      self.conditions=[]
    self.initializer_num=0
    self.finalizer_num=0
    self.interactor_num=0

  def generate_code(self, need_header=1, public_class=1, separate_interface=0, need_include=0):

    self.init_generator()

    if self.action_ext:
      self.handle_timed_transitions()
    
    if self.action_ext:
      self.handle_model_finalizer()

    if self.action_ext:
      self.handle_model_interactor()

    localtime=time.localtime()
    months=["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
    if self.eventhandler.description:
      desc="//\nModel Description:\n"+self.eventhandler.description
      x=0
      while x<len(desc):
        if desc[x]=='\n':
	  desc=desc[:x]+"\n//   "+desc[x+1:]
        x=x+1
      desc=desc+"\n"
    else:
      desc=""
    self.model_name=self.eventhandler.options[MODEL_NAME]
    other_models=self.generate_other_models();
    if need_include:
      include_str='\n#include "%s.h"\n' % self.model_name
    else:
      include_str=''
    if self.eventhandler.description:
      description=escape(self.eventhandler.description)
    else:
      description="null"

    if self.action_ext:
      additional_classes='\
class IntList {\n\
public:\n\
  int i;\n\
  IntList* Next;\n\
  IntList(int i=0) {\n\
    this->i=i;\n\
    Next=null;\n\
  }\n\
};\n\
\n\
class PendingEventList : public EventList {\n\
public:\n\
  PyObject* Params;\n\
  PyObject* PyLock;\n\
  pthread_mutex_t* Lock;\n\
  bool CallSubmodels;\n\
  StateMachine* Callee;\n\
};\n\
\n\
class Scheduler {\n\
private:\n\
  StateMachine* Model;\n\
  string Event;\n\
  string Interval; // interval in seconds\n\
  bool Repeat;\n\
  bool Stopped;\n\
  pthread_mutex_t Lock;\n\
  static void* run(void* param);\n\
\n\
public:\n\
  Scheduler* Next;\n\
  Scheduler(StateMachine* model, string event, string interval, bool repeat) :\n\
            Model(model), Event(event), Interval(interval), Repeat(repeat) {\n\
    pthread_mutex_init(&Lock, null);\n\
    Stopped=false;\n\
    Next=null;\n\
  }\n\
  ~Scheduler() {\n\
    pthread_mutex_destroy(&Lock);\n\
  }\n\
  void start();\n\
  void stop();\n\
  void clear();\n\
};\n\
\n'
      extended_variables='\
  PyObject* EmbeddedModule;\n\
  PyThreadState* DefaultInterpreter;\n\
  IntList* StatesEntered;\n\
  pthread_mutex_t EventsLock;\n\
  PendingEventList* PendingEvents;\n\
  PendingEventList* PendingEventsTail;\n\
  bool HandleEventRunning;\n\
  Scheduler* TimedTransitions[StateNum];\n'
      interface=CppGenerator.TextInterfaceExt
      constructor_interface='\
  [MODEL_NAME](PyThreadState* interpreter=null);\n'
      constructor_implementation='\
[MODEL_NAME]::[MODEL_NAME](PyThreadState* interpreter) {\n\
  if (interpreter==null)\n\
    interpreter=Py_NewInterpreter();\n\
  DefaultInterpreter=interpreter;\n\
  PyObject* module=Py_InitModule("__embedded_module__", ExtendedMethods);\n\
  EmbeddedModule=module;\n\
\n\
  // Create all the builtin methods\n\
  PyObject* thisobj=PyCObject_FromVoidPtr(this, null);\n\
  PyModule_AddObject(module, "__state_machine__", thisobj);\n\
  PyObject* desc=Py_BuildValue("s", [MODEL_NAME]::Description);\n\
  PyModule_AddObject(module, "__description__", desc);\n\
  runCode("from __embedded_module__ import __state_machine__, __event__, __description__, __is_in_state__, __start__");\n\
  runCode("import __embedded_module__");\n\
  runCode("def dump_message(msg):\\n  print msg");\n\
  runCode("\
class EventHandler:\\n\
  def __init__(self, statemachine, event, description, isinstate, start):\\n\
    self.__state_machine__=statemachine\\n\
    self.__event__=event\\n\
    self.__params__=[]\\n\
    self.description=description\\n\
    self.__is_in_state__=isinstate\\n\
    self.__start__=start\\n\
  def event(self, e, params=[], lock=None):\\n\
    self.__event__(self.__state_machine__, e, params, lock)\\n\
  def get_event_params(self):\\n\
    return self.__params__\\n\
  def is_in_state(self, s, check_substate=0):\\n\
    return self.__is_in_state__(self.__state_machine__, s, check_substate)\\n\
  def start(self, lock=None):\\n\
    self.__start__(self.__state_machine__, lock)\\n\
  def shutdown(self):\\n\
    pass");\n\
  runCode("eventhandler=EventHandler(__state_machine__, __event__, __description__, __is_in_state__, __start__)");\n\
\n\
  runCode("from __embedded_module__ import __test_condition__, __eval_interval__, __get_sysargv__");\n\
  runCode("import sys; sys.argv=__get_sysargv__(); sys.path.insert(0, \\".\\")");\n\
  state=null;\n\
  int i;\n\
  for (i=0; i<StateNum; i++) {\n\
    Submodels[i]=null;\n\
    history[i]=new History;\n\
    history[i]->States=new int[StateNum];\n\
    history[i]->Times=new long[StateNum];\n\
    for (int j=0; j<StateNum; j++) {\n\
      history[i]->States[j]=-1;\n\
      history[i]->Times[j]=-1;\n\
    }\n\
  }\n\
  for (i=0; i<StateNum; i++)\n\
    TimedTransitions[i]=null;\n\
  clearEnteredStates();\n\
  Started=false;\n\
  pthread_mutex_init(&EventsLock, null);\n\
  PendingEvents=null;\n\
  PendingEventsTail=null;\n\
  HandleEventRunning=false;\n\
}\n'
      mdl_action_interface='\
\n\
private:\n\
  void runActionCode(int code_num);\n\
  bool testCondition(int cond_num);\n\
  void recordEnteredState(int s, bool superstates=false, bool submodel=false, int commonstate=-1);\n\
  void runEnterActionsForStates(IntList* states, bool recursive=false);\n\
  void runEnterActions(int state);\n\
  void runExitActions(int state);\n\
  IntList* getSubstates(int state);\n\
  static void* handleEvent_wrapper(void* event);\n\
  void checkPendingEvents();\n\
  void releasePyLock(PyObject* pylock);\n\
\n\
protected:\n\
  virtual void clearEnteredStates();\n\
\n\
public:\n\
  virtual void runCode(string c);\n\
  virtual void start(PyObject* pylock=null, bool run_enter_actions=true);\n\
  virtual void recordAllEnteredStates();\n\
  virtual void runAllEnterActions();\n\
  virtual bool runExitActionsForStates(int common_state);\n\
  virtual void runInitializer();\n\
  virtual void runFinalizer();\n\
  virtual void runInteractor();\n\
  virtual bool handleEvent(string se, PyObject* params=null, PyObject* pylock=null, pthread_mutex_t* lock=null, bool call_submodels=true);\n\
  virtual void event(string se, PyObject* params=null, PyObject* pylock=null, pthread_mutex_t* lock=null, bool call_submodels=true);\n'
      mdl_action_implementation='\
void* [MODEL_NAME]::handleEvent_wrapper(void* ev) {\n\
  PendingEventList* event=(PendingEventList*)ev;\n\
  event->Callee->handleEvent(event->Event, event->Params, event->PyLock, event->Lock, event->CallSubmodels);\n\
  delete event;\n\
  return null;\n\
}\n\
void [MODEL_NAME]::event(string se, PyObject* params, PyObject* pylock, pthread_mutex_t* lock, bool call_submodels) {\n\
  PendingEventList* ev=new PendingEventList();\n\
  ev->Event=se;\n\
  ev->Params=params;\n\
  ev->PyLock=pylock;\n\
  ev->Lock=lock;\n\
  ev->CallSubmodels=call_submodels;\n\
  ev->Callee=this;\n\
  pthread_mutex_lock(&EventsLock);\n\
  bool running=HandleEventRunning;\n\
  if (!running && Started)\n\
    HandleEventRunning=true;\n\
  pthread_mutex_unlock(&EventsLock);\n\
  if (!running && Started) {\n\
    pthread_t t;\n\
    pthread_create(&t, null, [MODEL_NAME]::handleEvent_wrapper, (void*)ev);\n\
  } else {\n\
    pthread_mutex_lock(&EventsLock);\n\
    if (PendingEventsTail!=null)\n\
      PendingEventsTail->Next=ev;\n\
    else\n\
      PendingEvents=ev;\n\
    PendingEventsTail=ev;\n\
    pthread_mutex_unlock(&EventsLock);\n\
  }\n\
}\n\
void [MODEL_NAME]::checkPendingEvents() {\n\
  pthread_mutex_lock(&EventsLock);\n\
  PendingEventList* ev=PendingEvents;\n\
  if (ev!=null) {\n\
    PendingEvents=(PendingEventList*)ev->Next;\n\
    if (PendingEvents==null)\n\
      PendingEventsTail=null;\n\
    pthread_mutex_unlock(&EventsLock);\n\
    handleEvent_wrapper(ev);\n\
  } else {\n\
    HandleEventRunning=false;\n\
    pthread_mutex_unlock(&EventsLock);\n\
  }\n\
}\n\
void [MODEL_NAME]::releasePyLock(PyObject* pylock) {\n\
  PyModule_AddObject(EmbeddedModule, "__lock__", pylock);\n\
  runCode("if __embedded_module__.__lock__:\\n  __embedded_module__.__lock__.release()");\n\
}\n\
void [MODEL_NAME]::runCode(string c) {\n\
  if (c.length()>0) {\n\
    PyThreadState_Swap(DefaultInterpreter);\n\
    string l="", i;\n\
    int pos=0, next_pos;\n\
    do {\n\
      next_pos=c.find("\\n", pos);\n\
      if (next_pos==string::npos)\n\
        i=c.substr(pos);\n\
      else\n\
        i=c.substr(pos, next_pos-pos);\n\
      pos=next_pos+1;\n\
      if (l.length()==0)\n\
        l=i;\n\
      else if (i.find(" ")!=0 && !(i.find("else")==0 && i.substr(4, i.length()-4)==":") && \\\n\
                                i.find("elif ")!=0 && i.find("elif\\t")!=0 && \\\n\
                                !(i.find("except")==0 && i.substr(6, i.length()-6)==":") && \\\n\
                                i.find("except ")!=0 && i.find("except\\t")!=0) {\n\
        PyRun_SimpleString((char*)((l+"\\n").c_str()));\n\
        l=i;\n\
      }\n\
      else\n\
        l=l+"\\n"+i;\n\
    } while (next_pos!=string::npos);\n\
    if (l.length()>0)\n\
      PyRun_SimpleString((char*)((l+"\\n").c_str()));\n\
  }\n\
}\n\
[ACTION_CODE]\
[CONDITION_CODE]\
void [MODEL_NAME]::clearEnteredStates() {\n\
  StatesEntered=null;\n\
  for (int i=0; i<StateNum; i++)\n\
    if (Submodels[i])\n\
      Submodels[i]->clearEnteredStates();\n\
}\n\
void [MODEL_NAME]::recordAllEnteredStates() {\n\
  State* st=state;\n\
  while (st!=null) {\n\
    recordEnteredState(st->StateID, true, true);\n\
    st=st->Next;\n\
  }\n\
}\n\
void [MODEL_NAME]::recordEnteredState(int s, bool superstates, bool submodel, int commonstate) {\n\
  // test if s is already recorded\n\
  IntList* se=StatesEntered;\n\
  bool found=false;\n\
  while (se!=null) {\n\
    if (se->i==s) {\n\
      found=true;\n\
      break;\n\
    }\n\
    se=se->Next;\n\
  }\n\
  if (!found) {\n\
    if (superstates) {\n\
      int parent=getParentState(s);\n\
      if (parent>=0 && parent!=commonstate)\n\
        recordEnteredState(parent, true);\n\
    }\n\
    IntList* st=new IntList();\n\
    st->Next=StatesEntered;\n\
    st->i=s;\n\
    StatesEntered=st;\n\
    if (submodel && Submodels[s]!=null)\n\
      Submodels[s]->recordAllEnteredStates();\n\
  }\n\
}\n\
void [MODEL_NAME]::runAllEnterActions() {\n\
  runEnterActionsForStates(StatesEntered, true);\n\
}\n\
void [MODEL_NAME]::runEnterActionsForStates(IntList* states, bool recursive) {\n\
    if (states!=null) {\n\
      runEnterActionsForStates(states->Next, false);\n\
      runEnterActions(states->i);\n\
    }\n\
    if (recursive) {\n\
      for (int i=0; i<StateNum; i++)\n\
        if (Submodels[i]!=null)\n\
          Submodels[i]->runAllEnterActions();\n\
    }\n\
}\n\
[SUBSTATES_CODE]\
bool [MODEL_NAME]::runExitActionsForStates(int common_state) {\n\
  IntList* substates=getSubstates(common_state);\n\
  IntList* oldsst;\n\
  if (substates==null) {\n\
    State* s=state;\n\
    while (s!=null && s->StateID!=common_state)\n\
      s=s->Next;\n\
    if (s!=null && Submodels[s->StateID]!=null)\n\
      Submodels[s->StateID]->runExitActionsForStates(-1);\n\
    return s!=null;\n\
  }\n\
  else {\n\
    bool has_current_substate=false;\n\
    while (substates!=null) {\n\
      bool res=runExitActionsForStates(substates->i);\n\
      has_current_substate=has_current_substate || res;\n\
      if (res)\n\
        runExitActions(substates->i);\n\
      oldsst=substates;\n\
      substates=substates->Next;\n\
      delete oldsst;\n\
    }\n\
    return has_current_substate;\n\
  }\n\
}\n\
[ENTER_ACTIONS]\
[EXIT_ACTIONS]\
void [MODEL_NAME]::runInitializer() {\n\
  runActionCode([INITIALIZER_NUM]);\n\
  for (int i=0; i<StateNum; i++)\n\
    if (Submodels[i]!=null)\n\
      Submodels[i]->runInitializer();\n\
}\n\
void [MODEL_NAME]::runFinalizer() {\n\
  if (Started) {\n\
    for (int i=0; i<StateNum; i++)\n\
      if (Submodels[i]!=null)\n\
        Submodels[i]->runFinalizer();\n\
    runActionCode([FINALIZER_NUM]);\n\
    Started=false;\n\
  }\n\
}\n\
void [MODEL_NAME]::runInteractor() {\n\
  runCode("from Tkinter import *");\n\
  runActionCode([INTERACTOR_NUM]);\n\
  runEnterActionsForStates(StatesEntered, true);\n\
}\n'
      python_head='\
#include <Python.h>\n\
#include <pthread.h>\n\
#include <math.h>\n'
      sm_model_interface='\
  virtual void runCode(string c)=0;\n\
  virtual void initModel(bool run_initializer=true, bool run_enter_actions=true)=0;\n\
  virtual void start(PyObject* pylock=null, bool run_enter_actions=true)=0;\n\
  virtual bool handleEvent(string se, PyObject* params=null, PyObject* pylock=null, pthread_mutex_t* lock=null, bool call_submodels=true)=0;\n\
  virtual void event(string se, PyObject* params=null, PyObject* pylock=null, pthread_mutex_t* lock=null, bool call_submodels=true)=0;\n\
  virtual void clearEnteredStates()=0;\n\
  virtual void recordAllEnteredStates()=0;\n\
  virtual void runAllEnterActions()=0;\n\
  virtual bool runExitActionsForStates(int common_state)=0;\n\
  virtual void runInitializer()=0;\n\
  virtual void runFinalizer()=0;\n'
      init_model_interface='\
  virtual void initModel(bool run_initializer=true, bool run_enter_actions=true);\n'
      change_state_record_enter='\
          // used only when --ext is set\n\
          recordEnteredState(hs, true, true, t1);\n'
      start_code='\
void [MODEL_NAME]::start(PyObject* pylock, bool run_enter_actions) {\n\
  if (run_enter_actions)\n\
    runEnterActionsForStates(StatesEntered, true);\n\
  Started=true;\n\
  if (run_enter_actions)\n\
    checkPendingEvents();\n\
  if (pylock!=null)\n\
    releasePyLock(pylock);\n\
}\n'
      python_interface_implementation='\
// Implementation of an interface to Python\n\
static int result=0;\n\
static PyObject* extTestCondition(PyObject* self, PyObject* args) {\n\
  int res;\n\
  if (PyArg_ParseTuple(args, "i:__test_condition__", &res)) {\n\
    result=res;\n\
    return Py_BuildValue("");\n\
  }\n\
  return null;\n\
}\n\
static float interval=0.0;\n\
static PyObject* extEvalInterval(PyObject* self, PyObject* args) {\n\
  float res;\n\
  if (PyArg_ParseTuple(args, "f:__eval_interval__", &res)) {\n\
    interval=res;\n\
    return Py_BuildValue("");\n\
  }\n\
  return null;\n\
}\n\
static char** sysargv=null;\n\
static int sysargn=0;\n\
static PyObject* extGetSysArgv(PyObject* self, PyObject* args) {\n\
  if (PyArg_ParseTuple(args, ":__get_sysargv__")) {\n\
    PyObject* arglist=PyList_New(sysargn);\n\
    PyObject* arg;\n\
    for (int i=0; i<sysargn; i++) {\n\
      arg=Py_BuildValue("s", sysargv[i]);\n\
      PyList_SetItem(arglist, i, arg);\n\
    }\n\
    return arglist;\n\
  }\n\
  return null;\n\
}\n\
static PyObject* extEvent(PyObject* self, PyObject* args) {\n\
  PyObject* pymodel;\n\
  char* event;\n\
  PyObject* params;\n\
  PyObject* lock;\n\
  if (PyArg_ParseTuple(args, "OsOO:event", &pymodel, &event, &params, &lock)) {\n\
    Py_INCREF(lock);\n\
    Py_INCREF(pymodel);\n\
    Py_INCREF(params);\n\
    StateMachine* model=(StateMachine*)PyCObject_AsVoidPtr(pymodel);\n\
    model->event(string(event), params, lock);\n\
    return Py_BuildValue("");\n\
  }\n\
  return null;\n\
}\n\
static PyObject* extIsInState(PyObject* self, PyObject* args) {\n\
  PyObject* pymodel;\n\
  char* state;\n\
  int check_substate;\n\
  if (PyArg_ParseTuple(args, "Osi:is_in_state", &pymodel, &state, &check_substate)) {\n\
    Py_INCREF(pymodel);\n\
    StateMachine* model=(StateMachine*)PyCObject_AsVoidPtr(pymodel);\n\
    bool res=model->isInState(string(state), check_substate!=0);\n\
    return Py_BuildValue("i", res?1:0);\n\
  }\n\
  return null;\n\
}\n\
static PyObject* extStart(PyObject* self, PyObject* args) {\n\
  PyObject* pymodel;\n\
  PyObject* lock;\n\
  if (PyArg_ParseTuple(args, "OO:start", &pymodel, &lock)) {\n\
    Py_INCREF(lock);\n\
    Py_INCREF(pymodel);\n\
    StateMachine* model=(StateMachine*)PyCObject_AsVoidPtr(pymodel);\n\
    model->start(lock);\n\
    return Py_BuildValue("");\n\
  }\n\
  return null;\n\
}\n\
static PyMethodDef ExtendedMethods[]={\n\
  {"__test_condition__", extTestCondition, METH_VARARGS, "Receives the test result of a condition."},\n\
  {"__eval_interval__", extEvalInterval, METH_VARARGS, "Evaluates the interval for a timed transition."},\n\
  {"__get_sysargv__", extGetSysArgv, METH_VARARGS, "Retrieves the command-line arguments."},\n\
  {"__event__", extEvent, METH_VARARGS, "Broadcasts an event and appends it to the global event list."},\n\
  {"__is_in_state__", extIsInState, METH_VARARGS, "Tests if the model is in a state or its substates."},\n\
  {"__start__", extStart, METH_VARARGS, "Starts the model."},\n\
  {null, null, 0, null}\n\
};\n\
\n'
      destroy_lock='\
  pthread_mutex_destroy(&EventsLock);\n'
      additional_implementation='\
// Implementation of class "Scheduler" in the header\n\
void Scheduler::start() {\n\
  pthread_t t;\n\
  pthread_create(&t, null, Scheduler::run, this);\n\
}\n\
void Scheduler::stop() {\n\
  pthread_mutex_lock(&Lock);\n\
  Stopped=true;\n\
  pthread_mutex_unlock(&Lock);\n\
}\n\
void Scheduler::clear() {\n\
  stop();\n\
  if (Next!=null)\n\
    Next->clear();\n\
}\n\
void* Scheduler::run(void* param) {\n\
  Scheduler* self=(Scheduler*)param;\n\
  bool stopped=0;\n\
  while (!stopped) {\n\
    self->Model->runCode(string("__eval_interval__(")+self->Interval+")");\n\
    float f=interval;\n\
    time_t sec=(time_t)f;\n\
    long usec=(long)(f-(long)f)*1000000;\n\
    struct timespec req={sec, usec};\n\
    nanosleep(&req, null);\n\
    pthread_mutex_lock(&self->Lock);\n\
    stopped=self->Stopped;\n\
    pthread_mutex_unlock(&self->Lock);\n\
    if (!stopped) {\n\
      self->Model->event(self->Event, null, null, null, false);\n\
      stopped=!self->Repeat;\n\
    }\n\
  }\n\
}\n\
\n'
      public_constants_interface='\
public:\n\
  static const bool    HasInteractor;\n\
\n'
      public_constants_implementation='\
const bool [MODEL_NAME]::HasInteractor=[HAS_INTERACTOR];\n'
      if self.eventhandler.has_interactor:
        has_interactor="true"
      else:
        has_interactor="false"
      cpp_ending='\
int main(int argn, char** argv) {\n\
  sysargv=argv;\n\
  sysargn=argn;\n\
  [MODEL_NAME]::main(argn, argv);\n\
}\n'
      
    else:
      additional_classes=""
      extended_variables=""
      interface=CppGenerator.TextInterface
      constructor_interface='\
  [MODEL_NAME]();\n'
      constructor_implementation='\
[MODEL_NAME]::[MODEL_NAME]() {\n\
  state=null;\n\
  for (int i=0; i<StateNum; i++) {\n\
    Submodels[i]=null;\n\
    history[i]=new History;\n\
    history[i]->States=new int[StateNum];\n\
    history[i]->Times=new long[StateNum];\n\
    for (int j=0; j<StateNum; j++) {\n\
      history[i]->States[j]=-1;\n\
      history[i]->Times[j]=-1;\n\
    }\n\
  }\n\
  Started=false;\n\
}\n'
      mdl_action_interface="\
\n\
public:\n\
  virtual void start();\n\
  virtual boolean handleEvent(string se);\n"
      mdl_action_implementation=""
      python_head=""
      sm_model_interface="\
  virtual void initModel()=0;\n\
  virtual void start()=0;\n\
  virtual boolean handleEvent(string se)=0;\n"
      init_model_interface="\
  virtual void initModel();\n"
      change_state_record_enter=""
      start_code='\
void [MODEL_NAME]::start() {\n\
  Started=true;\n\
}\n'
      python_interface_implementation=""
      destroy_lock="";
      additional_implementation=""
      public_constants_interface=""
      public_constants_implementation=""
      has_interactor="false"
      cpp_ending='\
int main(int argn, char** argv) {\n\
  [MODEL_NAME]::main(argn, argv);\n\
}\n'

    macros={"[MODEL_FILE]": self.eventhandler.model_name,
	    "[DATE]": "%s %d, %d" % (months[localtime[1]-1], localtime[2], localtime[0]),
	    "[TIME]": "%d:%d:%d" % (localtime[3], localtime[4], localtime[5]),
	    "[DESCRIPTION]": desc,
            "[ESC_DESCRIPTION]": description,
            "[INCLUDE_STR]": include_str,
            "[INTERFACE]": interface,
            "[MODEL_NAME]": self.model_name,
            "[INIT_CODE]": self.find_initial_state(self.eventhandler.stateH),
	    "[HIERARCHY_DEFINITION]": self.generate_hierarchy_def(),
	    "[OTHER_MODELS_INTERFACE]": other_models[0],
            "[OTHER_MODELS_IMPLEMENTATION]": other_models[1],
	    "[STATES_CODE]": self.generate_states_code(),
	    "[EVENT_INT2STR_TABLE]": self.generate_event_int2str_table(),
	    "[STATE_INT2STR_TABLE]": self.generate_state_int2str_table(),
	    "[STATE_NUM]": str(self.state_num),
	    "[EVENT_NUM]": str(self.event_num),
	    "[EVENT_CODE]": self.generate_event_code(),
	    "[PARENT_TABLE]": self.generate_parent_table(),
	    "[HISTORY_STATE_TABLE]": self.generate_history_state_table(),
	    "[LEAF_STATE_TABLE]": self.generate_leaf_state_table(),
	    "[ORTHOGONAL_IN_BETWEEN]": self.generate_orthogonal_in_between_table(),
            "[COMMON_STATE_TABLE]": self.generate_common_state_table(),
	    "[ENABLED_EVENTS_CODE]": self.generate_enabled_events_code(),
	    "[HIERARCHY_CODE]": self.generate_hierarchy_code(),
            "[PYTHON_HEAD]": python_head,
            "[ADDITIONAL_CLASSES]": additional_classes,
            "[MDL_ACTION_INTERFACE]": mdl_action_interface,
            "[MDL_ACTION_IMPLEMENTATION]": mdl_action_implementation,
            "[CHANGE_STATE_RECORD_ENTER]": change_state_record_enter,
            "[EXTENDED_VARIABLES]": extended_variables,
            "[ENTER_ACTIONS]": self.generate_enter_actions(),
            "[EXIT_ACTIONS]": self.generate_exit_actions(),
            "[START_CODE]": start_code,
            "[INITIALIZER_NUM]": str(self.initializer_num),
            "[FINALIZER_NUM]": str(self.finalizer_num),
            "[INTERACTOR_NUM]": str(self.interactor_num),
            "[CONSTRUCTOR_INTERFACE]": constructor_interface,
            "[CONSTRUCTOR_IMPLEMENTATION]": constructor_implementation,
            "[SM_MODEL_INTERFACE]": sm_model_interface,
            "[ADDITIONAL_IMPLEMENTATION]": additional_implementation,
            "[PYTHON_INTERFACE_IMPLEMENTATION]": python_interface_implementation,
            "[PUBLIC_CONSTANTS_INTERFACE]": public_constants_interface,
            "[PUBLIC_CONSTANTS_IMPLEMENTATION]": public_constants_implementation,
            "[HAS_INTERACTOR]": has_interactor,
            "[INIT_MODEL_INTERFACE]": init_model_interface,
            "[DESTROY_LOCK]": destroy_lock,
            "[SUBSTATES_CODE]": self.generate_substates_code(),
	    "[ACTION_CODE]": self.generate_action_code(),
            "[CONDITION_CODE]": self.generate_condition_code()}

    if need_header:
      macros["[HEADER_INTERFACE]"]=CppGenerator.CppHeaderInterface
      macros["[HEADER_IMPLEMENTATION]"]=CppGenerator.CppHeaderImplementation
      macros["[ENDING]"]=cpp_ending
    else:
      macros["[HEADER_INTERFACE]"]=''
      macros["[HEADER_IMPLEMENTATION]"]=''
      macros["[ENDING]"]=''
    if public_class:
      macros["[ACCESSIBILITY_INTERFACE]"]='// Interface of the main class -- the top level model that is executed from the command line\n'
      macros["[ACCESSIBILITY_IMPLEMENTATION]"]='// Implementation of the main class -- the top level model that is executed from the command line\n'
    else:
      macros["[ACCESSIBILITY_INTERFACE]"]=''
      macros["[ACCESSIBILITY_IMPLEMENTATION]"]=''
    priority_macros=["[HEADER_INTERFACE]"]
    interf=replace_macros(CppGenerator.CppTemplateInterface, priority_macros, macros)
    priority_macros=["[INTERFACE]", "[HEADER_IMPLEMENTATION]", "[ENDING]", "[MDL_ACTION_IMPLEMENTATION]", "[CONSTRUCTOR_INTERFACE]", "[CONSTRUCTOR_IMPLEMENTATION]", "[START_CODE]", "[PUBLIC_CONSTANTS_IMPLEMENTATION]"]
    impl=replace_macros(CppGenerator.CppTemplateImplementation, priority_macros, macros)
    if separate_interface:
      return [interf, impl]
    else:
      return interf+impl

  def generate_hierarchy_def(self):
    codes=[]
    comments=[]
    ps=0
    states=self.state_table2.keys()
    states.sort()
    while ps<len(states):
      code="{"
      cs=0
      while cs<len(states):
        if cs>0:
          code=code+", "
        if cs!=ps and self.eventhandler.is_or_is_substate(states[cs], states[ps]):
          code=code+"true "
        else:
          code=code+"false"
        cs=cs+1
      code=code+"}"
      codes.append(code)
      comments.append("children for state %s" % states[ps])
      ps=ps+1
    return self.generate_array("const boolean", "%s::Hierarchy[%d][%d]" % (self.model_name, self.state_num, self.state_num), codes, comments)

  def generate_event_code(self):
    if self.action_ext:
      code='\
bool [MODEL_NAME]::handleEvent(string se, PyObject* params, PyObject* pylock, pthread_mutex_t* lock, bool call_submodels) {\n\
  if (!Started) {\n\
    if (lock!=null)\n\
      pthread_mutex_unlock(lock);\n\
    if (pylock!=null)\n\
      releasePyLock(pylock);\n\
    return false;\n\
  }\n\
  pthread_mutex_lock(&EventsLock);\n\
  HandleEventRunning=true;\n\
  pthread_mutex_unlock(&EventsLock);\n\
\n\
  // Prepare the parameters\n\
  if (params!=null) {\n\
    PyModule_AddObject(EmbeddedModule, "__params__", params);\n\
    runCode("eventhandler.__params__=__embedded_module__.__params__");\n\
  } else\n\
    runCode("eventhandler.__params__=[]");\n\
\n'
    else:
      code='\
bool [MODEL_NAME]::handleEvent(string se) {\n\
  if (!Started)\n\
    return false;\n'
    code=code+'\
  int e=eventStr2Int(se);\n\
  switch (e) {\n'
    keys=self.eventhandler.trans.keys()
    keys.sort()
    for t in keys:
      code=code+'\
    case %d: // event "%s"\n' % (self.event_table2[t], t) + self.generate_check_state_code(self.eventhandler.trans, t)
    code=code+'\
  }\n'
    keys=self.submodels.keys()
    keys.sort()
    
    if self.action_ext:
      for k in keys:
        code=code+'\
  if (isInState(%d) && Submodels[%d]->handleEvent(se)) {\n\
    if (lock!=null)\n\
      pthread_mutex_unlock(lock);\n\
    if (pylock!=null)\n\
      releasePyLock(pylock);\n\
    checkPendingEvents();\n\
    return true;\n\
  }\n' % (k, k)
      code=code+'\
  if (lock!=null)\n\
    pthread_mutex_unlock(lock);\n\
  checkPendingEvents();\n'
    else:
      for k in keys:
        code=code+'\
  if (isInState(%d) && Submodels[%d]->handleEvent(se))\n\
    return true;\n' % (k, k)
      
    code=code+'\
  return false;\n\
}\n'
    return code

  def generate_check_state_code(self, trans, e):
    code=''
    for t in trans[e]:

      cond=""
      if self.action_ext:
        if t.has_key('C'):
          condition_num=len(self.conditions)
          self.conditions.append(t['C'])
          cond=cond+" && testCondition(%d)" % condition_num
      
      stnum=self.get_state_num(t['S'])
      code=code+'\
      if (isInState(%d)%s) {\n' % (self.get_state_num(t['S']), cond)

      com=self.eventhandler.common_state(t['S'], t['N'])
      if com:
        com_num=self.get_state_num(com)
      else:
        com_num=-1

      if self.action_ext and self.eventhandler.options[HAREL]=='0':  # exit actions
        code=code+'\
        runExitActionsForStates(%d);\n' % com_num

      if self.action_ext and t.has_key('O'):  # output actions
        action_num=len(self.actions)
        self.actions.append([t['O'], "output action(s) of a transition"])
        code=code+'\
        runActionCode(%d); // output action(s)\n' % action_num        
      
      if self.action_ext and self.eventhandler.options[HAREL]=='1':  # exit actions
        code=code+'\
        runExitActionsForStates(%d);\n' % com_num

      if self.eventhandler.is_ifs(t['S']):
        keys=self.submodels.keys()
        keys.sort()
        for k in keys:
          path=self.state_table1[int(k)]
          if self.eventhandler.is_or_is_substate(path, t['S']):
            if self.action_ext:
              if path!=t['S']:
                code=code+'\
        if (isInState(%d) && Submodels[%d]->handleEvent(se)) {\n\
          if (lock!=null)\n\
            pthread_mutex_unlock(lock);\n\
          if (pylock!=null)\n\
            releasePyLock(pylock);\n\
          checkPendingEvents();\n\
          return true;\n\
        }\n' % (k, k)
	      else:
	        code=code+'\
        if (Submodels[%d]->handleEvent(se)) {\n\
          if (lock!=null)\n\
            pthread_mutex_unlock(lock);\n\
          if (pylock!=null)\n\
            releasePyLock(pylock);\n\
          checkPendingEvents();\n\
          return true;\n\
        }\n' % k
            else:
              if path!=t['S']:
                code=code+'\
        if (isInState(%d) && Submodels[%d]->handleEvent(se))\n\
          return true;\n' % (k, k)
	      else:
	        code=code+'\
        if (Submodels[%d]->handleEvent(se))\n\
          return true;\n' % k
      [p, sp]=self.find_submodel_path(t['N'])
      if t[HISTORY_STATE]:
	chkhs=", true"
      else:
	chkhs=""

      if self.action_ext:
	code=code+'\
	clearEnteredStates();\n'

      if sp:  # transition into a submodel
	pnum=self.get_state_num(p)
	code=code+'\
        changeState(%s, %s%s);\n\
        Submodels[%d]->forceIntoState(%d);\n\
        return true;\n\
      }\n' % (self.get_state_num(t['S']), pnum, pnum, self.generated_models[self.submodels[pnum]].get_state_num(sp), chkhs)
      else:
        code=code+'\
        changeState(%s, %s%s);\n'  % (self.get_state_num(t['S']), self.get_state_num(t['N']), chkhs)

      if self.action_ext:
        code=code+'\
        runEnterActionsForStates(StatesEntered, true);\n\
        if (lock!=null)\n\
          pthread_mutex_unlock(lock);\n\
        if (pylock!=null)\n\
          releasePyLock(pylock);\n\
        checkPendingEvents();\n'

      code=code+'\
        return true;\n\
      }\n\
      break;\n'
    return code

  def generate_states_code(self, stateH=None, path="", code=""):
    first=0
    sk=self.state_table2.keys()
    sk.sort()
    if not code:
      first=1
      stateH=self.eventhandler.stateH
      code=code+"\
  switch (common) {\n\
    case -1:\n\
      switch (dest) {\n"
      for s in sk:
	code=code+"\
        case %d:\n" % self.get_state_num(s) \
	    + "\
          if (history_type!=2 || check_history(-1)) {\n" \
	    + self.generate_in_states(stateH, "", s) \
	    + "\
          }\n\
          break;\n"
      code=code+"\
      }\n\
      break;\n"
    keys=stateH.keys()
    keys.sort()
    for k in keys:
      if not k in StateProperties:
	newpath=self.eventhandler.append_path(path, k)
	code=code+"\
    case %d:\n\
      switch (dest) {\n" % self.get_state_num(newpath)
	for s in sk:
	  if self.eventhandler.is_or_is_substate(s, newpath):

            record_state=""
            if self.action_ext and self.eventhandler.options[HAREL]=='1':
              record_state='\
          recordEnteredState(%s);\n' % self.get_state_num(newpath)
            
	    code=code+"\
        case %d:\n" % self.get_state_num(s) \
	    + "\
          if (history_type!=2 || check_history(%d)) {\n" % self.get_state_num(newpath) \
            + record_state \
	    + self.generate_in_states(stateH[k], newpath, s) \
	    + "\
          }\n\
          break;\n"
        code=code+"\
      }\n\
      break;\n"
	code=self.generate_states_code(stateH[k], newpath, code)
    if first:
      code=code+"\
  }\n"
    return code

  def generate_in_states(self, stateH, com, des):
    desnum=self.get_state_num(des)
    code=''
    dpaths=split(des, '.')
    if com:
      cpaths=split(com, '.')
    else:
      cpaths=[]
    states=stateH
    i=len(cpaths)
    loopin=0
    if i<len(dpaths):
      p=dpaths[i]
      if states[p][CONCURRENT_STATE]:
	keys=states.keys()
	keys.sort()
	for s in keys:
	  if not s in StateProperties:
	    loopin=1
	    next_com=self.eventhandler.append_path(com, s)
            code=code+'\
          if (history_type!=2 || check_history(%d)) {\n' % self.get_state_num(next_com)
            if self.action_ext:
              code=code+'\
          recordEnteredState(%s);\n' % self.get_state_num(next_com)
	    if s!=p:
	      code=code+self.generate_in_states(states[s], next_com, next_com)
	    else:
	      code=code+self.generate_in_states(states[s], next_com, des)
	    code=code+'\
          }\n'
      else:
	loopin=1
	next_com=self.eventhandler.append_path(com, p)
        code=code+'\
          if (history_type!=2 || check_history(%d)) {\n' % self.get_state_num(next_com)
        if self.action_ext:
          code=code+'\
          recordEnteredState(%s);\n' % self.get_state_num(next_com)
	code=code+self.generate_in_states(states[p], next_com, des)
	code=code+'\
          }\n'
      i=i+1
    if not loopin:
      found_def=0
      keys=states.keys()
      keys.sort()
      for s in keys:
	if not s in StateProperties and (states[s][DEFAULT_STATE] or states[s][CONCURRENT_STATE]):
	  found_def=1
	  next_com=self.eventhandler.append_path(com, s)
          code=code+'\
          if (history_type!=2 || check_history(%d)) {\n' % self.get_state_num(next_com)
          if self.action_ext:
            code=code+'\
          recordEnteredState(%s);\n' % self.get_state_num(next_com)
	  code=code+self.generate_in_states(states[s], next_com, next_com)
	  code=code+'\
          }\n'
      if not found_def:
	code=code+'\
          addInState(%d);  // move into leaf state "%s"\n' % (desnum, des)
	stnum=self.get_state_num(des)
	if self.submodels.has_key(stnum):

          if self.action_ext:
            code=code+'\
          if (history_type==1 && Submodels[%d]!=null)\n\
            Submodels[%d]->topLevelHistory();\n\
          else if (history_type!=2 || Submodels[%d]==null) {\n\
            bool run_initializer=true;\n\
            if (Submodels[%d]!=null) {\n\
              delete Submodels[%d];\n\
              run_initializer=false;\n\
            }\n\
            Submodels[%d]=new %s;\n\
            Submodels[%d]->initModel(run_initializer, false);\n\
          }\n' % (stnum, stnum, stnum, stnum, stnum, stnum, self.submodels[stnum], stnum)
          else:
            code=code+'\
          if (history_type==1 && Submodels[%d]!=null)\n\
            Submodels[%d]->topLevelHistory();\n\
          else if (history_type!=2 || Submodels[%d]==null) {\n\
            if (Submodels[%d]!=null)\n\
              delete Submodels[%d];\n\
            Submodels[%d]=new %s;\n\
            Submodels[%d]->initModel();\n\
          }\n' % (stnum, stnum, stnum, stnum, stnum, stnum, self.submodels[stnum], stnum)
    return code

  def generate_array(self, atype, aname, alist, comments=None):
    code="%s %s={" % (atype, aname)
    space=(3+len(atype)+len(aname))
    i=0
    while i<len(alist):
      k=alist[i]
      code=code+str(k)
      if i<len(alist)-1:
	code=code+","
      else:
        code=code+" "
      if comments:
	code=code+"  // "+comments[i]
      if i<len(alist)-1:
        code=code+"\n"+" "*space
      else:
	code=code+"\n"+" "*(space-1)
      i=i+1
    code=code+"};\n"
    return code

  def generate_event_int2str_table(self):
    events=[]
    keys=self.event_table1.keys()
    keys.sort()
    for k in keys:
      events.append('"%s"' % self.event_table1[k])
    return self.generate_array("const char*", "%s::EventNames[%d]" % (self.model_name, self.event_num), events)

  def generate_state_int2str_table(self):
    states=[]
    keys=self.state_table1.keys()
    keys.sort()
    for k in keys:
      states.append('"%s"' % self.state_table1[k])
    return self.generate_array("const char*", "%s::StateNames[%d]" % (self.model_name, self.state_num), states)

  def find_initial_state(self, stateH, path=''):
    """ To find the initial state(s) in the state hierachy, stateH.
    """
    if self.action_ext and path=='':
      code='\
void %s::initModel(bool run_initializer, bool run_enter_actions) {\n\
  clearEnteredStates();\n' % self.model_name
    elif path=='':
      code='\
void %s::initModel() {\n' % self.model_name
    else:
      code=""
    keys=stateH.keys()
    keys.sort()
    enter_recorded=[]
    init_final=0
    for s in keys:
      if not s in StateProperties:
        if stateH[s][DEFAULT_STATE]:
          newstateH=stateH[s]
	  newpath=self.eventhandler.append_path(path, s)
          stnum=self.get_state_num(newpath)
          code=code+self.find_initial_state(newstateH, newpath)
	  has_substate=0
	  skeys=stateH[s].keys()
	  skeys.sort()
	  for ss in skeys:
	    if not ss in StateProperties:
	      has_substate=1
	      break
	  if not has_substate:
	    code=code+'\
  addInState(%s); // init state "%s"\n' % (self.get_state_num(newpath), newpath)
            if path=='' and self.is_final_state(newpath):
              init_final=1
            keys2=self.state_table2.keys()
	    keys2.sort()
            for s in keys2:
	      if self.eventhandler.is_or_is_substate(newpath, s) and not s in enter_recorded:

                if self.action_ext:
                  code=code+'\
  recordEnteredState(%s);\n' % self.get_state_num(s)

                enter_recorded.append(s)
	    if self.submodels.has_key(stnum):
              if self.action_ext:
                code=code+'\
  Submodels[%d]=new %s;\n\
  Submodels[%d]->initModel(false, false);\n' % (stnum, self.submodels[stnum], stnum)
              else:
                code=code+'\
  Submodels[%d]=new %s;\n\
  Submodels[%d]->initModel();\n' % (stnum, self.submodels[stnum], stnum)

    if self.action_ext and path=='':  # execute initializer

      self.initializer_num=len(self.actions)
      self.actions.append([self.eventhandler.init, "model initializer"])
      code=code+'\
  if (run_initializer)\n\
    runInitializer();\n\
  if (!HasInteractor)\n\
    start(null, run_enter_actions);\n'
    elif path=='':
      code=code+'\
  Started=1;\n'

    if init_final:
      code=code+'\
  runFinalizer();  // One of the initial states is final\n'

    if path=='':
      code=code+"\
}\n"
    return code

  def generate_other_models(self):
    int=''
    imp=''
    for eh in self.required_models:
      if not self.compiled_models.has_key(eh.options[MODEL_NAME]):
	self.compiled_models[eh.options[MODEL_NAME]]=eh
	jg=CppGenerator(eh, self.action_ext)
        [interf, impl]=jg.generate_code(0, 0, 1)
        int=int+'\
// Submodel Class "%s" -- the submodel executed by the top-level model\n' % eh.options[MODEL_NAME] + interf
        imp=imp+'\
// Submodel Class "%s" -- the submodel executed by the top-level model' % eh.options[MODEL_NAME] + impl
	self.generated_models[eh.options[MODEL_NAME]]=jg
    return [int, imp]

  def generate_parent_table_rec(self, stateH, plist, comments, pnum=-1, path=""):
    keys=stateH.keys()
    keys.sort()
    for k in keys:
      if not k in StateProperties:
	newpath=self.eventhandler.append_path(path, k)
	cnum=self.get_state_num(newpath)
	plist[cnum]=pnum
	comments[cnum]="%s -- parent " % newpath
	if path:
	  comments[cnum]=comments[cnum]+path
	else:
	  comments[cnum]=comments[cnum]+"(None)"
	self.generate_parent_table_rec(stateH[k], plist, comments, cnum, newpath)
    
  def generate_parent_table(self):
    plist=[]
    comments=[]
    i=0
    while i<self.state_num:
      plist.append(-1);
      comments.append("");
      i=i+1
    self.generate_parent_table_rec(self.eventhandler.stateH, plist, comments)
    return self.generate_array("const int", "%s::ParentTable[%d]" % (self.model_name, self.state_num), plist, comments)

  def generate_history_state_table(self):
    htable=[]
    keys=self.state_table2.keys()
    keys.sort()
    for s in keys:
      htable.append(str(self.has_history_state(s)))
    return self.generate_array("const int", "%s::HistoryStateTable[%d]" % (self.model_name, self.state_num), htable)

  def generate_leaf_state_table(self):
    ltable=[]
    keys=self.state_table2.keys()
    keys.sort()
    for s in keys:
      if self.is_leaf_state(s, 0):
	ltable.append('"%s"' % s);
      else:
	ltable.append('null');
    return self.generate_array("const char*", "%s::LeafStateTable[%d]" % (self.model_name, self.state_num), ltable)

  def generate_orthogonal_in_between_table(self):
    table=[]
    i=0
    while i<self.state_num+1:
      table.append([])
      j=0
      while j<self.state_num:
	table[i].append(0)
        j=j+1
      i=i+1
    hs=[]
    keys=self.state_table2.keys()
    keys.sort()
    for k in keys:
      if self.has_orthogonal_substate(k):
        hs.append(k)
    if len(hs)>0:
      keys=self.state_table1.keys()
      keys.sort()
      for s1 in keys+[-1]:
        foundhist=0
        hist=[]
        for h in hs:
          if s1==-1 or self.eventhandler.is_or_is_substate(h, self.state_table1[s1]):
            foundhist=1
            hist.append(h)
        if foundhist:
          skeys=self.state_table2.keys()
	  skeys.sort()
          for s2 in skeys:
	    if not self.is_leaf_state(s2):
	      continue
            foundhist=0
            for h in hist:
              if self.eventhandler.is_or_is_substate(s2, h):
	        foundhist=1
	        break
	    if foundhist:
	      table[s1+1][self.get_state_num(s2)]=1
    codes=[]
    for hs in table:
      i=0
      code="{"
      while i<self.state_num:
	if hs[i]:
	  code=code+"true "
	else:
	  code=code+"false"
	if i<self.state_num-1:
	  code=code+", "
	i=i+1
      code=code+"}"
      codes.append(code)
    return self.generate_array("const boolean", "%s::OrthogonalInBetween[%d+1][%d]" % (self.model_name, self.state_num, self.state_num), codes)

  def generate_common_state_table(self):
    codes=[]
    i=0
    while i<self.state_num:
      j=0
      code="{"
      while j<self.state_num:
        com=self.eventhandler.common_state(self.state_table1[i], self.state_table1[j])
        if com:
          comnum=self.get_state_num(com)
        else:
          comnum=-1
        code=code+str(comnum)
        if j<self.state_num-1:
          code=code+", "
        else:
          code=code+"}"
        j=j+1
      codes.append(code)
      i=i+1
    return self.generate_array("const int", "%s::CommonStateTable[%d][%d]" % (self.model_name, self.state_num, self.state_num), codes)

  def generate_enabled_events_code(self):
    code="\
  EventList *events=new EventList;\n"
    keys=self.eventhandler.trans.keys()
    keys.sort()
    for k in keys:
      for t in self.eventhandler.trans[k]:
        code=code+"\
  if (isInState(%d))\n\
    events->Append(\"%s\");\n" % (self.state_table2[t['S']], k)
    keys=self.submodels.keys()
    keys.sort()
    for k in keys:
      code=code+"\
  if (isInState(%d))\n\
    events->Append(Submodels[%d]->getEnabledEvents());\n" % (k, k)
    code=code+"\
  return events->Next;\n"
    return code

  def generate_hierarchy_code_rec(self, code, stateH, level=0, path=""):
    keys=stateH.keys()
    keys.sort()
    for k in keys:
      if not k in StateProperties:
	newpath=self.eventhandler.append_path(path, k)
	snum=self.get_state_num(newpath)
	code=code+'\
  // Generate state "%s" in the hierarchy table\n\
  lasth->Next=new HierarchyList;\n\
  lasth->Next->StateName="%s";\n\
  lasth->Next->PathName=state_prefix==""?"%s":state_prefix+".%s";\n\
  lasth->Next->StateNum=%d;\n\
  lasth->Next->Level=start_level+%d;\n\
  lasth=lasth->Next;\n' % (newpath, k, newpath, newpath, snum, level)
	if self.submodels.has_key(snum):
	  code=code+'\
  if (Submodels[%d]!=null) {\n\
    lasth->Next=Submodels[%d]->getHierarchy(start_level+%d+1, lasth->PathName);\n\
    while (lasth->Next!=null)\n\
      lasth=lasth->Next;\n\
  }\n' % (snum, snum, level)
	code=self.generate_hierarchy_code_rec(code, stateH[k], level+1, newpath)
    return code

  def generate_hierarchy_code(self):
    code="\
  HierarchyList *h=new HierarchyList, *lasth=h;\n"
    code=self.generate_hierarchy_code_rec(code, self.eventhandler.stateH)
    code=code+"\
  return h->Next;\n"
    return code

  def generate_action_code(self):
    if self.action_ext:
      code="\
void %s::runActionCode(int code_num) {\n\
  switch (code_num) {\n" % self.model_name
      i=0
      for action in self.actions:
        command=action[0]
        comment=action[1]
        code=code+'\
    case %d: // %s\n' % (i, comment)
        i=i+1
        if command:
          for cmd in command:
            if cmd[0]=='|':  # commands starting with "|" is not interpreted by DefaultInterpreter
              cmd=string.replace(cmd[1:], "\n|", "\n")
              cmd="      "+string.replace(cmd, "\n", "\n      ")
            else:
              lcmd=lstrip(cmd)
              lspace=len(cmd)-len(lcmd)
              cmd=escape(lcmd)
              cmd=" "*(lspace+6)+'runCode(%s);' % cmd
            code=code+cmd+"\n"
        code=code+"\
      break;\n"
      return code+"\
  }\n\
}\n"
    else:
      return ""

  def generate_condition_code(self):
    if self.action_ext:
      code="\
bool %s::testCondition(int cond_num) {\n\
  switch (cond_num) {\n" % self.model_name
      i=0
      for condition in self.conditions:
        code=code+'\
    case %d:\n' % i
        i=i+1
        if condition:
          cond=self.svm_guard_2_scc_guard(condition)
          code=code+'\
      %s\n\
      return result!=0;\n' % cond
        else:
          code=code+"\
      return true;\n"
      code=code+"\
  }\n\
  return false;\n"
      return code+"\
}\n"
    else:
      return ""

  def generate_enter_actions(self):
    if self.action_ext and self.eventhandler.enter:
      code="\
void %s::runEnterActions(int state) {\n\
  switch (state) {\n" % self.model_name
      for s in self.eventhandler.enter.keys():
        sn=self.state_table2[s]  # actions for state s in a submodel are omitted
        code=code+'\
    case %d: // enter action(s) for state "%s"\n' % (sn, s)
        enter_num=len(self.actions)
        enter=[]
        for ent in self.eventhandler.enter[s]:
          if ent.has_key('C'):
            enter.append("|"+self.svm_guard_2_scc_guard(ent['C']));
            enter.append('|if (result) {')
            for o in ent['O']:
              enter.append("  "+o)
            enter.append('|}')
          else:
            enter=enter+ent['O']
        self.actions.append([enter, 'enter actions for state "%s"' % s])
        code=code+'\
      runActionCode(%d);\n\
      break;\n' % enter_num
      return code+"\
  }\n\
}\n"
    elif self.action_ext:
      return '\
void %s::runEnterActions(int state) {\n\
}\n' % self.model_name
    else:
      return ""

  def generate_substates_code(self):  # necessary only if --ext is set
    if self.action_ext:
      code="\
IntList* %s::getSubstates(int state) {\n\
  IntList* substates=null;\n\
  IntList* st;\n\
  switch (state) {\n" % self.model_name
      keys=self.state_table2.keys()
      keys.sort()
      for s in [""]+keys:
        added=0
        if s:
          snum=self.get_state_num(s)
          sp=split(s, ".")
        else:
          snum=-1
          sp=[]
        code=code+'\
    case %d: // substates of "%s"\n' % (snum, s)
        for ss in keys:
          if not s or startswith(ss, s+"."):
            sp2=split(ss, ".")
            if len(sp2)==len(sp)+1:
              ssnum=self.get_state_num(ss)
              code=code+'\
      // add substate "%s"\n\
      st=new IntList();\n\
      st->i=%d;\n\
      st->Next=substates;\n\
      substates=st;\n' % (ss, ssnum)
              added=1
        code=code+'\
      break;\n'

      code=code+'\
  }\n\
  return substates;\n\
}\n'
      return code
    else:
      return ""

  def generate_exit_actions(self):
    if self.action_ext and self.eventhandler.exit:
      code="\
void %s::runExitActions(int state) {\n\
  switch (state) {\n" % self.model_name
      for s in self.eventhandler.exit.keys():
        sn=self.state_table2[s]  # actions for state s in a submodel are omitted
        code=code+'\
    case %d: // exit action(s) for state "%s"\n' % (sn, s)
        exit_num=len(self.actions)
        exit=[]
        for ext in self.eventhandler.exit[s]:
          if ext.has_key('C'):
            exit.append("|"+self.svm_guard_2_scc_guard(ext['C']));
            exit.append('|if (result) {')
            for o in ext['O']:
              exit.append("  "+o)
            exit.append('|}')
          else:
            exit=exit+ext['O']
        self.actions.append([exit, 'exit actions for state "%s"' % s])
        code=code+'\
      runActionCode(%d);\n\
      break;\n' % exit_num
      return code+"\
  }\n\
}\n"
    elif self.action_ext:
      return '\
void %s::runExitActions(int state) {\n\
}\n' % self.model_name
    else:
      return ""

  def svm_guard_2_scc_guard(self, condition):
    cond=strip(condition)
    head="EventHandler.vtest="
    if startswith(cond, head):
      cond='__test_condition__%s' % cond[len(head):]
    return 'runCode(%s);' % escape(cond)

  def handle_timed_transitions(self):
    keys=self.eventhandler.ttrans.keys()
    for s in keys:
      if not self.eventhandler.enter.has_key(s):
        self.eventhandler.enter[s]=[]
      if not self.eventhandler.exit.has_key(s):
        self.eventhandler.exit[s]=[]
      snum=self.get_state_num(s)
      tts=self.eventhandler.ttrans[s]
      for tt in tts:
        interval=escape(tt[1])
        if tt[3]:
          repeat="true"
        else:
          repeat="false"
        self.eventhandler.enter[s].append({'O': [
               '|// a timed transition',
               '|{',
               '|  Scheduler* sched=new Scheduler(this, "%s", %s, %s);' % (
                   tt[0], interval, repeat),
               '|  sched->Next=TimedTransitions[%s];' % snum,
               '|  TimedTransitions[%s]=sched;' % snum,
               '|  sched->start();',
               '|}']})
        self.eventhandler.exit[s].append({'O': [
               '|// clean up timed transitions',
               '|if (TimedTransitions[%s]) {' % snum,
               '|  TimedTransitions[%s]->clear();' % snum,
               '|  TimedTransitions[%s]=null;' % snum,
               '|}']})

  def handle_model_finalizer(self):
    self.finalizer_num=len(self.actions)
    self.actions.append([self.eventhandler.final, "model finalizer"])
    keys=self.state_table2.keys()
    keys.sort()
    for s in keys:
      if self.is_final_state(s):
        if not self.eventhandler.enter.has_key(s):
          self.eventhandler.enter[s]=[]
        snum=self.get_state_num(s)
        self.eventhandler.enter[s].append({'O': [
               '|// run finalizer for a final state',
               '|runFinalizer();']})

  def handle_model_interactor(self):
    self.interactor_num=len(self.actions)
    self.actions.append([self.eventhandler.interactor, "model-specific interactor"])
