#---------------------------------------------------------------------
#      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 <string>\n\
using namespace std;\n\
\n\
#define null 0\n\
\n\
class State {\n\
public:\n\
  int StateID;\n\
  State* Next;\n\
  State();\n\
  ~State();\n\
  State* copy();\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\
  StringList* sort();\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\
  bool Started;\n\
  bool Stopped;\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, bool use_backup=true)=0;\n\
  virtual bool isInState(string s, bool check_substate=true, bool use_backup=true)=0;\n\
  virtual int getParentState(int state)=0;\n\
  virtual bool isHistoryState(int state)=0;\n\
  virtual bool isLeafState(string state)=0;\n\
  virtual void deleteSubmodels()=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]\
[PTHREAD_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\
State* State::copy() {\n\
  State* s=new State();\n\
  s->StateID=StateID;\n\
  if (Next!=null)\n\
    s->Next=Next->copy();\n\
  return s;\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\
StringList* StringList::sort() {\n\
  StringList *first, *prev, *next;\n\
  if (Next!=null) {\n\
    Next=Next->sort();\n\
    if (Next->str<str) {\n\
      first=Next;\n\
      prev=Next;\n\
      next=Next->Next;\n\
      while (next!=null && next->str<str) {\n\
        prev=next;\n\
        next=next->Next;\n\
      }\n\
      Next=next;\n\
      prev->Next=this;\n\
      return first;\n\
    }\n\
  }\n\
  return this;\n\
}\n\
\n\
// 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\
bool 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;\n\
  static const char*   [EVENT_NUM1]EventNames [EVENT_NUM2];\n\
  static const char*   [STATE_NUM1]StateNames [STATE_NUM2];\n\
  static const int     [STATE_NUM1]ParentTable [STATE_NUM2];\n\
  static const int     [STATE_NUM1]HistoryStateTable [STATE_NUM2];\n\
  static const char*   [STATE_NUM1]LeafStateTable [STATE_NUM2];\n\
  static const bool    [STATE_NUM1]OrthogonalInBetween [[STATE_NUM]+1][STATE_NUM2];\n\
  static const bool    [STATE_NUM1][STATE_NUM1]OrthogonalTable [STATE_NUM2][STATE_NUM2];\n\
  static const char*   [EVENT_NUM1]IntervalTable [EVENT_NUM2];\n\
  static const int     [EVENT_NUM1]RescheduleTable [EVENT_NUM2];\n\
  static const int     [STATE_NUM1][STATE_NUM1]CommonStateTable [STATE_NUM2][STATE_NUM2];\n\
  static const bool    [STATE_NUM1][STATE_NUM1]Hierarchy [STATE_NUM2][STATE_NUM2];\n\
\n\
public:\n\
  static const char*   Description;\n\
\n\
[PUBLIC_CONSTANTS_INTERFACE]\
  // Variables\n\
  State* state;\n\
  State* BackState;\n\
  StateMachine* [STATE_NUM1]Submodels[STATE_NUM2];\n\
  History* [STATE_NUM1]history[STATE_NUM2];\n\
  long HistoryCount;\n\
  StateMachine* Parent;\n\
[EXTENDED_VARIABLES]\
\n\
public:\n\
  // Constructor\n\
[CONSTRUCTOR_INTERFACE]\
  virtual ~[MODEL_NAME]();\n\
[MDL_ACTION_INTERFACE]\
\n\
private:\n\
  bool isParent(int sp, int sc);\n\
  bool 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\
  bool isLeafState(int state);\n\
  bool isHistoryUp2Date(int state, long time);\n\
  void mergeHistory(int state, int* states, long* times);\n\
  void recordHistory(int top_state);\n\
  bool hasHistoryRecorded(int state);\n\
  bool hasOrthogonalStateInBetween(int parent, int leaf);\n\
  bool check_history(int dest);\n\
  string getCurrentState(StringList* states);\n\
\n\
protected:\n\
  virtual int eventStr2Int(string event);\n\
\n\
public:\n\
  virtual bool isInState(int s, bool check_substate=true, bool use_backup=true);\n\
  virtual bool isInState(string s, bool check_substate=true, bool use_backup=true);\n\
  static void main(int argn, char** argv);\n\
[INIT_MODEL_INTERFACE]\
  void applyMask(const bool* mask, bool* dest);\n\
  void forceIntoState(int s);\n\
  void changeState(int s1, int s2, bool check_history=false);\n\
  virtual StringList* getCurrentStateList();\n\
  virtual string getCurrentState();\n\
  virtual int getParentState(int state);\n\
  virtual bool isHistoryState(int state);\n\
  virtual bool isLeafState(string state);\n\
  virtual void deleteSubmodels();\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]\
[ORTHOGONAL_TABLE]\
[INTERVAL_TABLE]\
[RESCHEDULE_TABLE]\
[HIERARCHY_DEFINITION]\
[COMMON_STATE_TABLE]\
const int [MODEL_NAME]::StateNum=[STATE_NUM];\n\
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\
  if (Parent==null)  // Top-level model\n\
    deleteSubmodels();\n\
  for (int i=0; i<StateNum; i++)\n\
    if (history[i]!=null)\n\
      delete history[i];\n\
[EXTENDED_FINALIZER]\
}\n\
[START_CODE]\
bool [MODEL_NAME]::isParent(int sp, int sc) {\n\
  return sc>=0 && (sp<0 || Hierarchy[sp][sc]);\n\
}\n\
bool [MODEL_NAME]::isInState(int s, bool check_substate, bool use_backup) {\n\
  State* st;\n\
  if (use_backup)\n\
    st=BackState;\n\
  else\n\
    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\
bool [MODEL_NAME]::isInState(string s, bool check_substate, bool use_backup) {\n\
  int i;\n\
  for (i=0; i<StateNum; i++)\n\
    if (s==StateNames[i])\n\
      return isInState(i, check_substate, use_backup);\n\
  for (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, false, use_backup) && Submodels[i]->isInState(SubmodelState, check_substate, use_backup);\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]::applyMask(const bool* mask, bool* dest) {\n\
  for (int i=0; i<[MODEL_NAME]::StateNum; i++, dest++, mask++)\n\
    *dest = *dest && *mask;\n\
}\n\
void [MODEL_NAME]::forceIntoState(int s) {\n\
  bool changed=false;\n\
  State* s2=state;\n\
  while (s2!=null) {\n\
    bool 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, bool 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) && Submodels[s2]==null)\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\
      if (Submodels[s2]!=null) {\n\
[CHANGE_STATE_RECORD_ENTER1]\
        addInState(s2);\n\
      }\n\
      else\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\
bool [MODEL_NAME]::addInState(int s) {\n\
  if (!isInState(s, true, false)) {\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\
  sl->Next=null;\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\
        states=states->sort();\n\
        strst="[\\\'"+states->str+"\\\'"+getCurrentState(states)+"]";\n\
      }\n\
      else\n\
        strst="[]";\n\
    }\n\
    else {\n\
      if (states->Next!=null)\n\
        strst=", \\\'"+states->Next->str+"\\\'"+getCurrentState(states->Next);\n\
      else\n\
        strst="";\n\
    }\n\
    return strst;\n\
}\n\
int [MODEL_NAME]::getParentState(int state) {\n\
  return ParentTable[state];\n\
}\n\
bool [MODEL_NAME]::isHistoryState(int state) {\n\
  return HistoryStateTable[state]>0;\n\
}\n\
bool [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\
bool [MODEL_NAME]::isLeafState(int state) {\n\
  return LeafStateTable[state]!=null;\n\
}\n\
void [MODEL_NAME]::deleteSubmodels() {\n\
  for (int i=0; i<StateNum; i++)\n\
    if (Submodels[i]!=null) {\n\
      Submodels[i]->deleteSubmodels();\n\
      delete Submodels[i];\n\
    }\n\
}\n\
bool [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=HistoryCount++;\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>=0 && times[parent]!=time) {\n\
        states[parent]=child;\n\
        times[parent]=time;\n\
        if (isHistoryState(parent))\n\
          mergeHistory(parent, states, times);\n\
        if (parent==top_state)\n\
          break;\n\
        child=parent;\n\
        parent=getParentState(child);\n\
      }\n\
    }\n\
    s=s->Next;\n\
  }\n\
}\n\
bool [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\
bool [MODEL_NAME]::hasOrthogonalStateInBetween(int parent, int leaf) {\n\
  return OrthogonalInBetween[parent+1][leaf];\n\
}\n\
bool [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\
  char buf[255];\n\
  char *ptrhead, *ptrend;\n\
  string cmd="";\n\
  model.initModel();\n\
  while (cmd!="exit") {\n\
    printf("%s > ", model.getCurrentState().c_str());\n\
    fgets(buf, 255, stdin);\n\
    ptrend=buf+(strlen(buf)-1);\n\
    while (ptrend>=buf && (*ptrend==\'\\n\' || *ptrend==\'\\r\' || *ptrend==\' \' || *ptrend==\'\\t\')) {\n\
      *ptrend=0;\n\
      ptrend--;\n\
    }\n\
    ptrhead=buf;\n\
    while (ptrhead<ptrend && (*ptrhead==\' \' || *ptrhead==\'\\t\'))\n\
      ptrhead++;\n\
    cmd=ptrhead;\n\
    if (cmd=="exit")\n\
      break;\n\
    if (!model.Stopped)\n\
      model.handleEvent(cmd);\n\
  }\n'

  TextInterfaceExt='\
  // Initialize Python\n\
  Py_Initialize();\n\
  PyEval_InitThreads();\n\
  PyThreadState *mainState=PyThreadState_Swap(NULL);\n\
  PyEval_ReleaseLock();\n\
\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_cond_t cond;\n\
    char buf[255];\n\
    char *ptrhead, *ptrend;\n\
    pthread_mutex_init(&lock, null);\n\
    pthread_cond_init(&cond, null);\n\
    while (cmd!="exit") {\n\
      printf("%s > ", model.getCurrentState().c_str());\n\
      fgets(buf, 255, stdin);\n\
      ptrend=buf+(strlen(buf)-1);\n\
      while (ptrend>=buf && (*ptrend==\'\\n\' || *ptrend==\'\\r\' || *ptrend==\' \' || *ptrend==\'\\t\')) {\n\
        *ptrend=0;\n\
        ptrend--;\n\
      }\n\
      ptrhead=buf;\n\
      while (ptrhead<ptrend && (*ptrhead==\' \' || *ptrhead==\'\\t\'))\n\
        ptrhead++;\n\
      cmd=ptrhead;\n\
      if (cmd=="exit")\n\
        break;\n\
      if (!model.Stopped) {\n\
        pthread_mutex_lock(&lock);\n\
        model.event(cmd, null, null, &lock, &cond);\n\
        pthread_cond_wait(&cond, &lock);\n\
        pthread_mutex_unlock(&lock);\n\
      }\n\
    }\n\
    pthread_mutex_destroy(&lock);\n\
    pthread_cond_destroy(&cond);\n\
  }\n\
  model.runFinalizer();\n\
\n\
  // Finalize Python\n\
  PyEval_AcquireLock();\n\
  PyThreadState_Swap(mainState);\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()

    self.model_name=self.eventhandler.options[MODEL_NAME]

    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=""
    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\
  pthread_cond_t* Cond;\n\
  StateMachine* Callee;\n\
  StateMachine* Scheduler;\n\
};\n\
\n\
class Schedule {\n\
public:\n\
  int id;\n\
  double time;\n\
  string interval;\n\
  string event;\n\
  Schedule* next;\n\
  StateMachine* scheduler;\n\
};\n\
\n'
      extended_variables='\
  PyObject* EmbeddedModule;\n\
  PyThreadState* DefaultInterpreter;\n\
  IntList* StatesEntered;\n\
  pthread_mutex_t EventsLock, SchedulerLock;\n\
  pthread_cond_t EventsCond, SchedulerCond;\n\
  pthread_t EventsThread, SchedulerThread;\n\
  PendingEventList* PendingEvents;\n\
  PendingEventList* PendingEventsTail;\n\
  Schedule* Schedules;\n'
      interface=CppGenerator.TextInterfaceExt
      constructor_interface='\
  [MODEL_NAME](PyThreadState* interpreter=null, StateMachine* parent=null, [MODEL_NAME]* oldinstance=null);\n'
      constructor_implementation='\
[MODEL_NAME]::[MODEL_NAME](PyThreadState* interpreter, StateMachine* parent, [MODEL_NAME]* oldinstance) {\n\
  Parent=parent;\n\
  if (Parent!=null)\n\
    DefaultInterpreter=interpreter;\n\
  else {  // Top-level model\n\
    PyEval_AcquireLock();\n\
    if (interpreter==null)\n\
      interpreter=Py_NewInterpreter();\n\
    else\n\
      PyThreadState_Swap(interpreter);\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__, __get_current_state__", false);\n\
    runCode("import __embedded_module__", false);\n\
    runCode("def dump_message(msg):\\n  print msg", false);\n\
    runCode("\
class EventHandler:\\n\
  def __init__(self, statemachine, event, description, isinstate, start, getcurrentstate):\\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\
    self.__get_current_state__=getcurrentstate\\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 get_current_state(self):\\n\
    return self.__get_current_state__(self.__state_machine__)\\n\
  def shutdown(self):\\n\
    pass", false);\n\
    runCode("eventhandler=EventHandler(__state_machine__, __event__, __description__, __is_in_state__, __start__, __get_current_state__)", false);\n\
\n\
    runCode("from __embedded_module__ import __test_condition__, __eval_interval__, __get_sysargv__", false);\n\
    runCode("import sys; sys.argv=__get_sysargv__(); sys.path.insert(0, \\".\\")", false);\n\
    runCode("import time", false);\n\
    PyThreadState_Swap(NULL);\n\
    PyEval_ReleaseLock();\n\
    pthread_mutex_init(&EventsLock, null);\n\
    pthread_mutex_init(&SchedulerLock, null);\n\
    pthread_cond_init(&EventsCond, null);\n\
    pthread_cond_init(&SchedulerCond, null);\n\
  }\n\
  HistoryCount=0;\n\
  state=null;\n\
  BackState=null;\n\
  int i;\n\
  if (oldinstance!=null)\n\
    for (i=0; i<StateNum; i++)\n\
      Submodels[i]=oldinstance->Submodels[i];\n\
  else\n\
    for (i=0; i<StateNum; i++)\n\
      Submodels[i]=null;\n\
  for (i=0; i<StateNum; i++) {\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\
  clearEnteredStates();\n\
  Started=false;\n\
  PendingEvents=null;\n\
  PendingEventsTail=null;\n\
  Stopped=false;\n\
  Schedules=null;\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* mdl);\n\
  static void* scheduler(void* mdl);\n\
  void releasePyLock(PyObject* pylock);\n\
\n\
protected:\n\
  virtual void clearEnteredStates();\n\
  virtual void addSchedule(int id, string interval, string event, StateMachine* scheduler);\n\
  virtual void removeSchedule(int id, StateMachine* scheduler);\n\
\n\
public:\n\
  virtual void runCode(string c, bool lock=true);\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(bool join=true);\n\
  virtual void runInteractor();\n\
  virtual bool handleEvent(string se, PyObject* params=null, PyObject* pylock=null, pthread_mutex_t* lock=null, pthread_cond_t* cond=null, StateMachine* scheduler=null);\n\
  virtual void event(string se, PyObject* params=null, PyObject* pylock=null, pthread_mutex_t* lock=null, pthread_cond_t* cond=null, StateMachine* scheduler=null);\n'
      mdl_action_implementation='\
void* [MODEL_NAME]::handleEvent_wrapper(void* mdl) {\n\
  [MODEL_NAME]* model=([MODEL_NAME]*)mdl;\n\
  pthread_mutex_lock(&model->EventsLock);\n\
  while (true) {\n\
    if (model->PendingEvents==NULL)\n\
      pthread_cond_wait(&model->EventsCond, &model->EventsLock);\n\
    if (model->Stopped) {\n\
      pthread_mutex_unlock(&model->EventsLock);\n\
      return NULL;\n\
    }\n\
    PendingEventList* event=(PendingEventList*)model->PendingEvents;\n\
    model->PendingEvents=(PendingEventList*)(model->PendingEvents->Next);\n\
    if (model->PendingEvents==null)\n\
      model->PendingEventsTail=null;\n\
    event->Next=null;\n\
    pthread_mutex_unlock(&model->EventsLock);\n\
    event->Callee->handleEvent(event->Event, event->Params, event->PyLock, event->Lock, event->Cond, event->Scheduler);\n\
    delete event;\n\
    pthread_mutex_lock(&model->EventsLock);\n\
    if (model->Stopped) {\n\
      pthread_mutex_unlock(&model->EventsLock);\n\
      return NULL;\n\
    }\n\
  }\n\
}\n\
void [MODEL_NAME]::addSchedule(int id, string interval, string event, StateMachine* scheduler) {\n\
  if (Parent!=null) {  // Non-top-level model\n\
    Parent->addSchedule(id, interval, event, scheduler);\n\
    return;\n\
  }\n\
  // Compute interval\n\
  PyEval_AcquireLock();\n\
  PyThreadState_Swap(DefaultInterpreter);\n\
  runCode(string("__eval_interval__(")+interval+")", false);\n\
  float f=__interval__;\n\
  PyThreadState_Swap(NULL);\n\
  PyEval_ReleaseLock();\n\
\n\
  pthread_mutex_lock(&SchedulerLock);\n\
  timeval t;\n\
  Schedule* s=new Schedule();\n\
  s->id=id;\n\
  s->interval=interval;\n\
  s->scheduler=scheduler;\n\
  gettimeofday(&t, NULL);\n\
  s->time=TV2DBL(t)+f;\n\
  s->event=event;\n\
  if (Schedules==NULL) {\n\
    Schedules=s;\n\
    s->next=NULL;\n\
  } else {\n\
    Schedule* global_s=Schedules;\n\
    if (global_s->time > s->time) {\n\
      s->next=global_s;\n\
      Schedules=s;\n\
    } else\n\
      while (global_s!=NULL) {\n\
        if (global_s->time <= s->time && (global_s->next == NULL || global_s->next->time > s->time)) {\n\
          s->next=global_s->next;\n\
          global_s->next=s;\n\
          break;\n\
        }\n\
        global_s=global_s->next;\n\
      }\n\
  }\n\
  pthread_cond_signal(&SchedulerCond);\n\
  pthread_mutex_unlock(&SchedulerLock);\n\
}\n\
void [MODEL_NAME]::removeSchedule(int id, StateMachine* scheduler) {\n\
  if (Parent!=null) {  // Non-top-level model\n\
    Parent->removeSchedule(id, scheduler);\n\
    return;\n\
  }\n\
  pthread_mutex_lock(&SchedulerLock);\n\
  Schedule* this_sched;\n\
  while (Schedules!=NULL && Schedules->id==id) {\n\
    this_sched=Schedules;\n\
    Schedules=Schedules->next;\n\
    delete this_sched;\n\
  }\n\
  if (Schedules!=NULL) {\n\
    Schedule* last_sched=Schedules;\n\
    this_sched=Schedules->next;\n\
    while (this_sched!=NULL)\n\
      if (this_sched->id==id && this_sched->scheduler==scheduler) {\n\
        last_sched->next=this_sched->next;\n\
        delete this_sched;\n\
        this_sched=last_sched->next;\n\
      } else {\n\
        last_sched=this_sched;\n\
        this_sched=this_sched->next;\n\
      }\n\
  }\n\
  pthread_mutex_unlock(&SchedulerLock);\n\
}\n\
void* [MODEL_NAME]::scheduler(void* mdl) {\n\
  [MODEL_NAME]* model=([MODEL_NAME]*)mdl;\n\
  timeval t;\n\
  double current_time;\n\
  pthread_mutex_t wait_lock;\n\
  pthread_cond_t wait_cond;\n\
  pthread_mutex_lock(&model->SchedulerLock);\n\
  pthread_cond_init(&wait_cond, null);\n\
  while (true) {\n\
    while (model->Schedules==NULL) {\n\
      pthread_cond_wait(&model->SchedulerCond, &model->SchedulerLock);\n\
      if (model->Stopped) {\n\
        pthread_mutex_unlock(&model->SchedulerLock);\n\
        pthread_cond_destroy(&wait_cond);\n\
        return NULL;\n\
      }\n\
    }\n\
    gettimeofday(&t, NULL);\n\
    current_time=TV2DBL(t);\n\
    while (model->Schedules!=NULL && model->Schedules->time <= current_time) {\n\
      Schedule* this_sched=model->Schedules;\n\
      model->Schedules=model->Schedules->next;\n\
      model->event(this_sched->event, null, null, &model->SchedulerLock, &wait_cond, this_sched->scheduler);\n\
      pthread_cond_wait(&wait_cond, &model->SchedulerLock);\n\
      if (model->Stopped) {\n\
        pthread_mutex_unlock(&model->SchedulerLock);\n\
        pthread_cond_destroy(&wait_cond);\n\
        return NULL;\n\
      }\n\
      delete this_sched;\n\
    }\n\
    if (model->Schedules!=NULL) {\n\
      timespec t=DBL2TS(model->Schedules->time);\n\
      pthread_cond_timedwait(&model->SchedulerCond, &model->SchedulerLock, &t);\n\
      if (model->Stopped) {\n\
        pthread_mutex_unlock(&model->SchedulerLock);\n\
        pthread_cond_destroy(&wait_cond);\n\
        return NULL;\n\
      }\n\
    }\n\
  }\n\
}\n\
void [MODEL_NAME]::event(string se, PyObject* params, PyObject* pylock, pthread_mutex_t* lock, pthread_cond_t* cond, StateMachine* scheduler) {\n\
  PendingEventList* ev=new PendingEventList();\n\
  ev->Event=se;\n\
  ev->Params=params;\n\
  ev->PyLock=pylock;\n\
  ev->Lock=lock;\n\
  ev->Cond=cond;\n\
  ev->Callee=this;\n\
  ev->Scheduler=scheduler;\n\
  pthread_mutex_lock(&EventsLock);\n\
  if (PendingEventsTail!=null)\n\
    PendingEventsTail->Next=ev;\n\
  else\n\
    PendingEvents=ev;\n\
  PendingEventsTail=ev;\n\
  pthread_cond_signal(&EventsCond);\n\
  pthread_mutex_unlock(&EventsLock);\n\
}\n\
void [MODEL_NAME]::releasePyLock(PyObject* pylock) {\n\
  if (pylock!=null && pylock!=Py_None) {\n\
    PyEval_AcquireLock();\n\
    PyThreadState_Swap(DefaultInterpreter);\n\
    PyModule_AddObject(EmbeddedModule, "__lock__", pylock);\n\
    runCode("if __embedded_module__.__lock__:\\n  __embedded_module__.__lock__.release()", false);\n\
    PyThreadState_Swap(NULL);\n\
    PyEval_ReleaseLock();\n\
  }\n\
}\n\
void [MODEL_NAME]::runCode(string c, bool lock) {\n\
  if (c.length()>0) {\n\
    if (lock) {\n\
      PyEval_AcquireLock();\n\
      PyThreadState_Swap(DefaultInterpreter);\n\
    }\n\
    PyRun_SimpleString((char*)(c+"\\n").c_str());\n\
    if (lock) {\n\
      PyThreadState_Swap(NULL);\n\
      PyEval_ReleaseLock();\n\
    }\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, false, commonstate);\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(bool join) {\n\
  bool old_started=false;\n\
  if (Started) {\n\
    old_started=true;\n\
    Started=false;\n\
    for (int i=0; i<StateNum; i++)\n\
      if (Submodels[i]!=null)\n\
        Submodels[i]->runFinalizer();\n\
    runActionCode([FINALIZER_NUM]);\n\
  }\n\
  if (join && Parent==null && (old_started || Stopped)) {  // Top-level model\n\
    pthread_mutex_lock(&EventsLock);\n\
    pthread_mutex_lock(&SchedulerLock);\n\
    Stopped=true;\n\
    pthread_cond_signal(&EventsCond);\n\
    pthread_cond_signal(&SchedulerCond);\n\
    pthread_mutex_unlock(&SchedulerLock);\n\
    pthread_mutex_unlock(&EventsLock);\n\
    pthread_join(EventsThread, null);\n\
    pthread_join(SchedulerThread, null);\n\
  } else\n\
    Stopped=true;\n\
}\n\
void [MODEL_NAME]::runInteractor() {\n\
  runCode("from Tkinter import *");\n\
  runActionCode([INTERACTOR_NUM]);\n\
}\n'
      python_head='\
#include <Python.h>\n\
#define TV2DBL(t) (t.tv_sec+((double)t.tv_usec)/1000000l)\n\
#define DBL2TS(d) {(long)d, (long)((d-(long)d)*1000000000l)}\n\
\n\
#ifndef _WIN32\n\
  #include <pthread.h>\n\
#else\n\
  #include <windows.h>\n\
\n\
  typedef long time_t;\n\
\n\
  typedef struct {\n\
    int waiters_count_;\n\
    CRITICAL_SECTION waiters_count_lock_;\n\
    int release_count_;\n\
    int wait_generation_count_;\n\
    HANDLE event_;\n\
  } pthread_cond_t;\n\
\n\
  typedef struct {\n\
    time_t tv_sec;\n\
    long tv_nsec;\n\
  } timespec;\n\
\n\
  typedef HANDLE pthread_t;\n\
  typedef CRITICAL_SECTION pthread_mutex_t;\n\
  typedef void pthread_mutexattr_t;\n\
  typedef void pthread_condattr_t;\n\
  typedef void pthread_attr_t;\n\
  typedef void* (*PTHREAD_ROUTINE)(void*);\n\
\n\
  int gettimeofday(struct timeval* tv, struct timezone* tz);\n\
\n\
  int pthread_create(pthread_t* thread, pthread_condattr_t* attr, PTHREAD_ROUTINE routine, void* arg);\n\
  int pthread_join(pthread_t th, void** thread_return);\n\
\n\
  int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr);\n\
  int pthread_mutex_lock(pthread_mutex_t* mutex);\n\
  int pthread_mutex_unlock(pthread_mutex_t* mutex);\n\
  int pthread_mutex_destroy(pthread_mutex_t* mutex);\n\
\n\
  int pthread_cond_init (pthread_cond_t* cond, const pthread_condattr_t* attr);\n\
  int pthread_cond_wait (pthread_cond_t* cond, pthread_mutex_t* external_mutex);\n\
  int pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const timespec* abstime);\n\
  int pthread_cond_signal (pthread_cond_t* cond);\n\
  int pthread_cond_destroy(pthread_cond_t* cond);\n\
#endif\n\
\n'
      sm_model_interface='\
  virtual void runCode(string c, bool lock=true)=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, pthread_cond_t* cond=null, StateMachine* scheduler=null)=0;\n\
  virtual void event(string se, PyObject* params=null, PyObject* pylock=null, pthread_mutex_t* lock=null, pthread_cond_t* cond=null, StateMachine* scheduler=null)=0;\n\
  virtual void clearEnteredStates()=0;\n\
  virtual void addSchedule(int id, string interval, string event, StateMachine* scheduler)=0;\n\
  virtual void removeSchedule(int id, StateMachine* scheduler)=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(bool join=true)=0;\n'
      init_model_interface='\
  virtual void initModel(bool run_initializer=true, bool run_enter_actions=true);\n'
      change_state_record_enter='\
            recordEnteredState(hs, true, true, t1);\n'
      change_state_record_enter1='\
        recordEnteredState(s2, true, true, t1);\n'
      start_code='\
void [MODEL_NAME]::start(PyObject* pylock, bool run_enter_actions) {\n\
  if (Parent!=null) {  // Non-top-level model\n\
    Started=true;\n\
    return;\n\
  }\n\
  if (run_enter_actions) {\n\
    PyThreadState *oldstate=PyThreadState_Swap(NULL);\n\
    PyEval_ReleaseLock();\n\
    runEnterActionsForStates(StatesEntered, true);\n\
    PyEval_AcquireLock();\n\
    PyThreadState_Swap(oldstate);\n\
  }\n\
  Started=true;\n\
  pthread_create(&EventsThread, null, handleEvent_wrapper, this);\n\
  pthread_create(&SchedulerThread, null, scheduler, this);\n\
  if (pylock!=null) {\n\
    PyThreadState *oldstate=PyThreadState_Swap(NULL);\n\
    PyEval_ReleaseLock();\n\
    releasePyLock(pylock);\n\
    PyEval_AcquireLock();\n\
    PyThreadState_Swap(oldstate);\n\
  }\n\
  for (int i=0; i<StateNum; i++)\n\
    if (Submodels[i]!=null)\n\
      Submodels[i]->start();\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 PyObject* extGetCurrentState(PyObject* self, PyObject* args) {\n\
  PyObject* pymodel;\n\
  if (PyArg_ParseTuple(args, "O:get_current_state", &pymodel)) {\n\
    Py_INCREF(pymodel);\n\
    StateMachine* model=(StateMachine*)PyCObject_AsVoidPtr(pymodel);\n\
    return Py_BuildValue("s", model->getCurrentState().c_str());\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\
  {"__get_current_state__", extGetCurrentState, METH_VARARGS, "Gets the current state as a string."},\n\
  {null, null, 0, null}\n\
};\n\
\n'
      extended_finalizer='\
  Schedule* sched;\n\
  while (Schedules!=null) {\n\
    sched=Schedules;\n\
    Schedules=Schedules->next;\n\
    delete sched;\n\
  }\n\
  if (Parent==null) {  // Top-level model\n\
    pthread_mutex_destroy(&EventsLock);\n\
    pthread_cond_destroy(&EventsCond);\n\
    pthread_mutex_destroy(&SchedulerLock);\n\
    pthread_cond_destroy(&SchedulerCond);\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\
  return 0;\n\
}\n'
      pthread_implementation='\
// Implementation of pthread library under Windows\n\
#ifdef _WIN32\n\
int gettimeofday(struct timeval* tv, struct timezone* tz) {\n\
  FILETIME file_time;\n\
  SYSTEMTIME system_time;\n\
  ULARGE_INTEGER ularge;\n\
\n\
  GetSystemTime(&system_time);\n\
  SystemTimeToFileTime(&system_time, &file_time);\n\
  ularge.LowPart = file_time.dwLowDateTime;\n\
  ularge.HighPart = file_time.dwHighDateTime;\n\
  tv->tv_sec = (time_t) ((ularge.QuadPart - 116444736000000000L) / 10000000L);\n\
  tv->tv_usec = (long) (system_time.wMilliseconds * 1000);\n\
  return 0;\n\
}\n\
\n\
int pthread_create(pthread_t* thread, pthread_condattr_t* attr, PTHREAD_ROUTINE routine, void* arg) {\n\
  DWORD thread_id;\n\
  *thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)routine, arg, 0, &thread_id);\n\
  return 0;\n\
}\n\
\n\
int pthread_join(pthread_t th, void** thread_return) {\n\
  WaitForSingleObject(th, INFINITE);\n\
  if (thread_return)\n\
    GetExitCodeThread(th, (LPDWORD)thread_return);\n\
  return 0;\n\
}\n\
\n\
int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr) {\n\
  InitializeCriticalSection(mutex);\n\
  return 0;\n\
}\n\
\n\
int pthread_mutex_lock(pthread_mutex_t* mutex) {\n\
  EnterCriticalSection(mutex);\n\
  return 0;\n\
}\n\
\n\
int pthread_mutex_unlock(pthread_mutex_t* mutex) {\n\
  LeaveCriticalSection(mutex);\n\
  return 0;\n\
}\n\
\n\
int pthread_mutex_destroy(pthread_mutex_t* mutex) {\n\
  DeleteCriticalSection(mutex);\n\
  return 0;\n\
}\n\
\n\
int pthread_cond_init(pthread_cond_t* cond, const pthread_condattr_t* attr) {\n\
  cond->waiters_count_ = 0;\n\
  cond->wait_generation_count_ = 0;\n\
  cond->release_count_ = 0;\n\
  cond->event_ = CreateEvent(NULL, TRUE, FALSE, NULL);\n\
  InitializeCriticalSection(&cond->waiters_count_lock_);\n\
  return 0;\n\
}\n\
\n\
int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) {\n\
  int my_generation;\n\
  int wait_done;\n\
  int last_waiter;\n\
  EnterCriticalSection(&cond->waiters_count_lock_);\n\
  cond->waiters_count_++;\n\
  my_generation = cond->wait_generation_count_;\n\
  LeaveCriticalSection(&cond->waiters_count_lock_);\n\
  LeaveCriticalSection(mutex);\n\
  for (;;) {\n\
    WaitForSingleObject(cond->event_, INFINITE);\n\
    EnterCriticalSection(&cond->waiters_count_lock_);\n\
    wait_done = cond->release_count_ > 0 && cond->wait_generation_count_ != my_generation;\n\
    LeaveCriticalSection(&cond->waiters_count_lock_);\n\
    if (wait_done)\n\
      break;\n\
  }\n\
  EnterCriticalSection(mutex);\n\
  EnterCriticalSection(&cond->waiters_count_lock_);\n\
  cond->waiters_count_--;\n\
  cond->release_count_--;\n\
  last_waiter = cond->release_count_ == 0;\n\
  LeaveCriticalSection(&cond->waiters_count_lock_);\n\
  if (last_waiter)\n\
    ResetEvent (cond->event_);\n\
  return 0;\n\
}\n\
\n\
int pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const timespec* abstime) {\n\
  int my_generation;\n\
  int wait_done;\n\
  int last_waiter;\n\
  DWORD wait_result;\n\
  long sched_m_sec = abstime->tv_sec*1000 + abstime->tv_nsec/1000000l;\n\
  timeval curr_time;\n\
  long curr_m_sec, wait_m_sec;\n\
  gettimeofday(&curr_time, NULL);\n\
  curr_m_sec = curr_time.tv_sec * 1000 + curr_time.tv_usec;\n\
  wait_m_sec = sched_m_sec - curr_m_sec;\n\
\n\
  EnterCriticalSection(&cond->waiters_count_lock_);\n\
  cond->waiters_count_++;\n\
  my_generation = cond->wait_generation_count_;\n\
  LeaveCriticalSection(&cond->waiters_count_lock_);\n\
  LeaveCriticalSection(mutex);\n\
  for (;;) {\n\
    if (wait_m_sec > 0)\n\
      wait_result = WaitForSingleObject(cond->event_, wait_m_sec);\n\
    else\n\
      wait_result = WAIT_TIMEOUT;\n\
    EnterCriticalSection(&cond->waiters_count_lock_);\n\
    if (wait_result == WAIT_TIMEOUT) {  // simulate a signal\n\
      if (cond->waiters_count_ > cond->release_count_) {\n\
        cond->release_count_++;\n\
        cond->wait_generation_count_++;\n\
      }\n\
    }\n\
    wait_done = cond->release_count_ > 0 && cond->wait_generation_count_ != my_generation;\n\
    LeaveCriticalSection(&cond->waiters_count_lock_);\n\
    if (wait_done)\n\
      break;\n\
  }\n\
  EnterCriticalSection(mutex);\n\
  EnterCriticalSection(&cond->waiters_count_lock_);\n\
  cond->waiters_count_--;\n\
  cond->release_count_--;\n\
  last_waiter = cond->release_count_ == 0;\n\
  LeaveCriticalSection(&cond->waiters_count_lock_);\n\
  if (last_waiter)\n\
    ResetEvent (cond->event_);\n\
  return 0;\n\
}\n\
\n\
int pthread_cond_signal(pthread_cond_t* cond) {\n\
  EnterCriticalSection(&cond->waiters_count_lock_);\n\
  if (cond->waiters_count_ > cond->release_count_) {\n\
    SetEvent(cond->event_);\n\
    cond->release_count_++;\n\
    cond->wait_generation_count_++;\n\
  }\n\
  LeaveCriticalSection(&cond->waiters_count_lock_);\n\
  return 0;\n\
}\n\
\n\
int pthread_cond_destroy(pthread_cond_t* cond) {\n\
  CloseHandle(cond->event_);\n\
  DeleteCriticalSection(&cond->waiters_count_lock_);\n\
  return 0;\n\
}\n\
#endif\n\
\n'
      
    else:
      additional_classes=""
      extended_variables=""
      interface=CppGenerator.TextInterface
      constructor_interface='\
  [MODEL_NAME](StateMachine* parent=null, [MODEL_NAME]* oldinstance=null);\n'
      constructor_implementation='\
[MODEL_NAME]::[MODEL_NAME](StateMachine* parent, [MODEL_NAME]* oldinstance) {\n\
  int i;\n\
  HistoryCount=0;\n\
  state=null;\n\
  BackState=null;\n\
  Parent=parent;\n\
  if (oldinstance!=null)\n\
    for (i=0; i<StateNum; i++)\n\
      Submodels[i]=oldinstance->Submodels[i];\n\
  else\n\
    for (i=0; i<StateNum; i++)\n\
      Submodels[i]=null;\n\
  for (i=0; i<StateNum; i++) {\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\
  Stopped=false;\n\
}\n'
      mdl_action_interface="\
\n\
public:\n\
  virtual void start();\n\
  virtual bool handleEvent(string se);\n"
      mdl_action_implementation=""
      python_head=""
      sm_model_interface="\
  virtual void initModel()=0;\n\
  virtual void start()=0;\n\
  virtual bool handleEvent(string se)=0;\n"
      init_model_interface="\
  virtual void initModel();\n"
      change_state_record_enter=""
      change_state_record_enter1=""
      start_code='\
void [MODEL_NAME]::start() {\n\
  Started=true;\n\
}\n'
      python_interface_implementation=""
      extended_finalizer="";
      public_constants_interface=""
      public_constants_implementation=""
      has_interactor="false"
      cpp_ending='\
int main(int argn, char** argv) {\n\
  [MODEL_NAME]::main(argn, argv);\n\
  return 0;\n\
}\n'
      pthread_implementation=""

    if self.state_num==0:
      self.state_num1='*'
      self.state_num2=''
    else:
      self.state_num1=''
      self.state_num2='[%d]' % self.state_num
    if self.event_num==0:
      self.event_num1='*'
      self.event_num2=''
    else:
      self.event_num1=''
      self.event_num2='[%d]' % self.event_num

    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),
            "[STATE_NUM1]": self.state_num1,
            "[EVENT_NUM1]": self.event_num1,
            "[STATE_NUM2]": self.state_num2,
            "[EVENT_NUM2]": self.event_num2,
	    "[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(),
            "[ORTHOGONAL_TABLE]": self.generate_orthogonal_table(),
            "[INTERVAL_TABLE]": self.generate_interval_table(),
            "[RESCHEDULE_TABLE]": self.generate_reschedule_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,
            "[CHANGE_STATE_RECORD_ENTER1]": change_state_record_enter1,
            "[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,
            "[PYTHON_INTERFACE_IMPLEMENTATION]": python_interface_implementation,
            "[PTHREAD_IMPLEMENTATION]": pthread_implementation,
            "[PUBLIC_CONSTANTS_INTERFACE]": public_constants_interface,
            "[PUBLIC_CONSTANTS_IMPLEMENTATION]": public_constants_implementation,
            "[HAS_INTERACTOR]": has_interactor,
            "[INIT_MODEL_INTERFACE]": init_model_interface,
            "[EXTENDED_FINALIZER]": extended_finalizer,
            "[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 bool%s%s" % (self.state_num1, self.state_num1), "%s::Hierarchy%s%s" % (self.model_name, self.state_num2, self.state_num2), 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, pthread_cond_t* cond, StateMachine* scheduler) {\n\
  if (!Started) {\n\
    if (lock!=null && cond!=null) {\n\
      pthread_mutex_lock(lock);\n\
      pthread_cond_signal(cond);\n\
      pthread_mutex_unlock(lock);\n\
    } else if (lock!=null)\n\
      pthread_mutex_unlock(lock);\n\
    if (pylock!=null)\n\
      releasePyLock(pylock);\n\
    return false;\n\
  }\n\
\n\
  // Prepare the parameters\n\
  if (params!=null && Parent==null && params!=Py_None) {  // Top-level model\n\
    PyEval_AcquireLock();\n\
    PyThreadState_Swap(DefaultInterpreter);\n\
    PyModule_AddObject(EmbeddedModule, "__params__", params);\n\
    runCode("eventhandler.__params__=__embedded_module__.__params__", false);\n\
    PyThreadState_Swap(NULL);\n\
    PyEval_ReleaseLock();\n\
  } else if (Parent==null)\n\
    runCode("eventhandler.__params__=[]");\n\
\n'
    else:
      code='\
bool [MODEL_NAME]::handleEvent(string se) {\n\
  if (!Started)\n\
    return false;\n'
    code=code+'\
  bool handled=false;\n\
  bool %stable%s;\n\
  int e=eventStr2Int(se);\n\
  bool* tableptr=table;\n\
  for (int i=0; i<%d; i++) {\n\
    *tableptr++ = true;\n\
  }\n\
  if (state!=null)\n\
    BackState=state->copy();\n\
  else\n\
    BackState=null;\n\
  switch (e) {\n' % (self.state_num1, self.state_num2, self.state_num)
    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) +'\
      break;\n'
    code=code+'\
  }\n'
    keys=self.submodels.keys()
    keys.sort()
    
    if self.action_ext:
      for k in keys:
        code=code+'\
  if (table[%d] && isInState(%d) && Submodels[%d]->handleEvent(se, params, pylock, lock, cond, scheduler)) {\n\
      applyMask(OrthogonalTable[%d], table);\n\
      handled=true;\n\
  }\n' % (k, k, k, k)
      code=code+'\
  if (Parent==null) {\n\
    if (lock!=null && cond!=null) {\n\
      pthread_mutex_lock(lock);\n\
      pthread_cond_signal(cond);\n\
      pthread_mutex_unlock(lock);\n\
    } else if (lock!=null)\n\
      pthread_mutex_unlock(lock);\n\
    if (pylock!=null)\n\
      releasePyLock(pylock);\n\
  }\n'
    else:
      for k in keys:
        code=code+'\
  if (table[%d] && isInState(%d) && Submodels[%d]->handleEvent(se)) {\n\
    applyMask(OrthogonalTable[%d], table);\n\
    handled=true;\n\
  }\n' % (k, k, k, k)

    if self.action_ext:
      code=code+'\
  if (!handled && e>=0 && (scheduler==this || scheduler==null) && RescheduleTable[e]>=0)\n\
    addSchedule(RescheduleTable[e], IntervalTable[e], EventNames[e], scheduler);\n'
    code=code+'\
  return handled;\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
        test_sched='(scheduler==null || scheduler==this) && '
      else:
        test_sched=''
      
      stnum=self.get_state_num(t['S'])
      code=code+'\
      if (table[%d] && isInState(%d)%s) {\n' % (stnum, stnum, 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.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 (table[%d] && isInState(%d) && Submodels[%d]->handleEvent(se, params, pylock, lock, cond, scheduler)) {\n\
          applyMask(OrthogonalTable[%d], table);\n\
          handled=true;\n\
        }\n' % (k, k, k, k)
	      else:
	        code=code+'\
        if (table[%d] && Submodels[%d]->handleEvent(se, params, pylock, lock, cond, scheduler)) {\n\
          applyMask(OrthogonalTable[%d], table);\n\
          handled=true;\n\
        }\n' % (k, k, k)
            else:
              if path!=t['S']:
                code=code+'\
        if (table[%d] && isInState(%d) && Submodels[%d]->handleEvent(se)) {\n\
          applyMask(OrthogonalTable[%d], table);\n\
          handled=true;\n\
        }\n' % (k, k, k, k)
	      else:
	        code=code+'\
        if (table[%d] && Submodels[%d]->handleEvent(se)) {\n\
          applyMask(OrthogonalTable[%d], table);\n\
          handled=true;\n\
        }\n' % (k, k, k)

      code=code+'\
        if (%stable[%d]) {\n' % (test_sched, stnum)

      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

      [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' % (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'

      code=code+'\
          applyMask(OrthogonalTable[%d], table);\n\
          handled=true;\n\
        }\n\
      }\n' % self.get_state_num(t['S'])

    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)
            elif self.is_final_state(next_com):
              code=code+'\
          Stopped=true;\n'
	    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)
        elif self.is_final_state(next_com):
          code=code+'\
          Stopped=true;\n'
	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)
          elif self.is_final_state(next_com):
            code=code+'\
          Stopped=true;\n'
	  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\
            StateMachine* old_submodel=Submodels[%d];\n\
            Submodels[%d]=new %s(DefaultInterpreter, this, (%s*)old_submodel);\n\
            if (old_submodel==null && %s::Description!=null)\n\
              printf("%%s\\n", %s::Description);\n\
            if (old_submodel!=null) {\n\
              delete old_submodel;\n\
              run_initializer=false;\n\
            }\n\
            Submodels[%d]->initModel(run_initializer, false);\n\
            Submodels[%d]->start();\n\
          }\n' % (stnum, stnum, stnum, stnum, stnum, self.submodels[stnum], self.submodels[stnum], self.submodels[stnum], self.submodels[stnum], 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\
            StateMachine* old_submodel=Submodels[%d];\n\
            Submodels[%d]=new %s(this, (%s*)old_submodel);\n\
            if (old_submodel==null && %s::Description!=null)\n\
              printf("%%s\\n", %s::Description);\n\
            if (old_submodel!=null)\n\
              delete old_submodel;\n\
            Submodels[%d]->initModel();\n\
            Submodels[%d]->start();\n\
          }\n' % (stnum, stnum, stnum, stnum, stnum, self.submodels[stnum], self.submodels[stnum], self.submodels[stnum], self.submodels[stnum], stnum, stnum)
    return code

  def generate_array(self, atype, aname, alist, comments=None):
    if len(alist)==0:
      return "%s %s=null;\n" % (atype, aname)
    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" % self.event_num1, "%s::EventNames%s" % (self.model_name, self.event_num2), 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" % self.state_num1, "%s::StateNames%s" % (self.model_name, self.state_num2), 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\
  if (Parent==null && Description!=null)  // Top-level model\n\
    printf("%%s\\n", Description);\n' % self.model_name
    elif path=='':
      code='\
void %s::initModel() {\n\
  if (Parent==null && Description!=null)  // Top-level model\n\
    printf("%%s\\n", Description);\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)
                elif self.is_final_state(s):
                  code=code+'\
  Stopped=true;\n'

                enter_recorded.append(s)
	    if self.submodels.has_key(stnum):
              if self.action_ext:
                code=code+'\
  Submodels[%d]=new %s(DefaultInterpreter, this);\n\
  if (%s::Description!=null)\n\
    printf("%%s\\n", %s::Description);\n\
  Submodels[%d]->initModel(false, false);\n' % (stnum, self.submodels[stnum], self.submodels[stnum], self.submodels[stnum], stnum)
              else:
                code=code+'\
  Submodels[%d]=new %s(this);\n\
  if (%s::Description!=null)\n\
    printf("%%s\\n", %s::Description);\n\
  Submodels[%d]->initModel();\n' % (stnum, self.submodels[stnum], self.submodels[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\
    PyEval_AcquireLock();\n\
    PyThreadState_Swap(DefaultInterpreter);\n\
    start(null, run_enter_actions);\n\
    PyThreadState_Swap(NULL);\n\
    PyEval_ReleaseLock();\n\
  }\n'
    elif path=='':
      code=code+'\
  Started=true;\n'

    if init_final and self.action_ext:
      code=code+'\
  runFinalizer(false);  // 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" % self.state_num1, "%s::ParentTable%s" % (self.model_name, self.state_num2), 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" % self.state_num1, "%s::HistoryStateTable%s" % (self.model_name, self.state_num2), 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" % self.state_num1, "%s::LeafStateTable%s" % (self.model_name, self.state_num2), 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
    if self.state_num>0:
      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)
    else:
      codes=["null"]
    return self.generate_array("const bool%s" % self.state_num1, "%s::OrthogonalInBetween[%d+1]%s" % (self.model_name, self.state_num, self.state_num2), 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%s" % (self.state_num1, self.state_num1), "%s::CommonStateTable%s%s" % (self.model_name, self.state_num2, self.state_num2), codes)

  def generate_orthogonal_table_rec(self, stateH, path, table, orthogonal):
    if path:
      snum=self.get_state_num(path)
      for o in orthogonal:
        if not self.eventhandler.is_or_is_substate(path, o):
          for s2 in self.state_table1.keys():
            if self.eventhandler.is_or_is_substate(self.state_table1[s2], o):
              table[snum][s2]=1
              table[s2][snum]=1
    neworthogonal=[]
    for s in stateH.keys():
      if not s in StateProperties:
        if stateH[s][CONCURRENT_STATE]:
          neworthogonal.append(self.eventhandler.append_path(path, s))
    for s in stateH.keys():
      if not s in StateProperties:
        self.generate_orthogonal_table_rec(stateH[s], self.eventhandler.append_path(path, s), table, orthogonal+neworthogonal)
    
  def generate_orthogonal_table(self):
    i=0
    table=[]
    while i<self.state_num:
      table.append([])
      j=0
      while j<self.state_num:
        table[i].append(0)
        j=j+1
      i=i+1
    self.generate_orthogonal_table_rec(self.eventhandler.stateH, "", table, [])
    i=0
    while i<self.state_num:
      j=0
      s='{'
      while j<self.state_num:
        if table[i][j]:
          s=s+'true'
        else:
          s=s+'false'
        if j<self.state_num-1:
          s=s+', '
        j=j+1
      s=s+'}'
      table[i]=s
      i=i+1
    return self.generate_array("const bool%s%s" % (self.state_num1, self.state_num1), "%s::OrthogonalTable%s%s" % (self.model_name, self.state_num2, self.state_num2), table)

  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:
        evnum=self.event_table2[tt[0]]
        self.eventhandler.enter[s].append({'O': [
               '|// a timed transition',
               '|addSchedule(%s, IntervalTable[%d], EventNames[%d], this);' % (snum, evnum, evnum)]})
        self.eventhandler.exit[s].append({'O': [
               '|// clean up timed transitions',
               '|removeSchedule(%s, this);' % snum]})
        if tt[3] and self.eventhandler.trans.has_key(tt[0]):
          for tr in self.eventhandler.trans[tt[0]]:
            if self.eventhandler.is_or_is_substate(tr['N'], tr['S']):
              if not tr.has_key('O'):
                tr['O']=[]
              tr['O']=tr['O']+['|// repeated timed transition',
                               '|addSchedule(%s, IntervalTable[%d], EventNames[%d], this);' % (snum, evnum, evnum)]

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

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

  def generate_interval_table(self):
    if not self.action_ext:
      return ""
    
    table=[]
    i=0
    while i<self.event_num:
      table.append("null")
      i=i+1
    tkeys=self.eventhandler.ttrans.keys()
    for tk in tkeys:
      for t in self.eventhandler.ttrans[tk]:
        table[self.event_table2[t[0]]]=escape(t[1])
    return self.generate_array("const char*%s" % self.event_num1, "%s::IntervalTable%s" % (self.model_name, self.event_num2), table)

  def generate_reschedule_table(self):
    if not self.action_ext:
      return ""

    keys=self.event_table1.keys()
    keys.sort()
    table=[]
    i=0
    while i<self.event_num:
      table.append('-1')
      i=i+1
    for k in keys:
      ev=self.event_table1[k]
      if startswith(ev, "__INTERNAL_"):
        tkeys=self.eventhandler.ttrans.keys()
        for tk in tkeys:
          for t in self.eventhandler.ttrans[tk]:
            if t[0]==ev and t[3]:
              table[k]='%d' % self.get_state_num(tk)
    return self.generate_array("const int%s" % self.event_num1, "%s::RescheduleTable%s" % (self.model_name, self.event_num2), table)
