#---------------------------------------------------------------------
#      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 PythonGenerator(CodeGenerator):
  PythonHeader='\
# Python source code generated by SCC (StateChart Compiler) 0.3, written by Thomas Feng\n\
#   Source: [MODEL_FILE]\n\
#   Date:   [DATE]\n\
#   Time:   [TIME]\n\
[DESCRIPTION]\
\n\
\n\
# Header Section -- definition and module importation used by the following parts\n\
import sys\n\
import copy\n\
import time\n\
import string\n\
\n\
\n\
class State:\n\
\n\
  def __init__(self):\n\
\n\
    self.StateID=-1\n\
    self.Next=None\n\
\n\
\n\
class History:\n\
\n\
  def __init__(self):\n\
\n\
    self.States=None\n\
    self.Times=None\n\
    self.Submodel=None\n\
\n\
\n\
class EventList:\n\
\n\
  def __init__(self):\n\
\n\
    self.Event=None\n\
    self.Next=None\n\
\n\
  def Append(self, e):\n\
\n\
    if isinstance(e, str):\n\
      el=EventList()\n\
      el.Event=e\n\
      cur=this\n\
      while cur.Next!=None and cur.Event!=e:\n\
        cur=cur.Next;\n\
      if cur.Event!=e:\n\
        cur.Next=el\n\
\n\
    elif isinstance(e, EventList):\n\
      el=e\n\
      while el!=None:\n\
        self.Append(el.Event)\n\
        el=el.Next\n\
\n\
\n\
class StringList:\n\
\n\
  def __init__(self, str=""):\n\
\n\
    self.str=str\n\
    self.Next=None\n\
\n\
\n\
[INTLIST]\
class Hierarchy:\n\
\n\
  def __init__(self):\n\
\n\
    self.StateName=None\n\
    self.PathName=None\n\
    self.StateNum=-1\n\
    self.Level=-1\n\
    self.Next=None\n\
\n\
\n\
[SCHEDULER]\
class StateMachine:\n\
\n\
  def eventStr2Int(self, event):\n\
\n\
    return -1\n\
\n\
  def getCurrentStateList(self):\n\
\n\
    return None\n\
\n\
  def getCurrentState(self):\n\
\n\
    return "[]"\n\
\n\
  def getEnabledEvents(self):\n\
\n\
    return None\n\
\n\
[DUMMY_INIT_MODEL]\
  def isInState(self, s):\n\
\n\
    return 0\n\
\n\
  def getParentState(self, state):\n\
\n\
    return -1\n\
\n\
  def isHistoryState(self, state):\n\
\n\
    return 0\n\
\n\
  def isLeafState(self, state):\n\
\n\
    return 0\n\
\n\
  def getHierarchy(self, start_level=0, state_prefix=None):\n\
\n\
    return None\n\
\n\
  def topLevelHistory(self):\n\
\n\
    pass\n\
\n\
[DUMMY_CODE]\
\n\
def startswith(s, ss):\n\
\n\
  return ss==None or (s!=None and len(s)>=len(ss) and s[0:len(ss)]==ss)\n\
\n\
\n'

  PythonTemplate='\
[HEADER]\
[IMPORT_INTERPRETER]\
[ACCESSIBILITY]class [MODEL_NAME](StateMachine):\n\
\n\
  # Constants for this model\n\
  StateNum=[STATE_NUM]\n\
[EVENT_INT2STR_TABLE]\
[STATE_INT2STR_TABLE]\
[PARENT_TABLE]\
[HISTORY_STATE_TABLE]\
[LEAF_STATE_TABLE]\
[ORTHOGONAL_IN_BETWEEN]\
[HIERARCHY_DEFINITION]\
[COMMON_STATE_TABLE]\
  Description=[ESC_DESCRIPTION]\n\
\n\
[EXTENDED_CLASS_ATTRS]\
  def __init__(self, Interpreter=None):\n\
\n\
    # Variables\n\
    self.state=None\n\
    self.Submodels=[]\n\
    for i in range([MODEL_NAME].StateNum):\n\
      self.Submodels.append(None)\n\
    self.history=[]\n\
    for i in range([MODEL_NAME].StateNum):\n\
      self.history.append(None)\n\
\n\
    # Constructor\n\
    for i in range([MODEL_NAME].StateNum):\n\
      self.history[i]=History()\n\
      self.history[i].States=[]\n\
      self.history[i].Times=[]\n\
      for j in range([MODEL_NAME].StateNum):\n\
        self.history[i].States.append(-1)\n\
        self.history[i].Times.append(-1)\n\
\n\
[EXTENDED_INITIALIZER]\
    self.Started=0\n\
\n\
    self.description=[MODEL_NAME].Description\n\
\n\
  # Methods\n\
  def isParent(self, sp, sc):\n\
\n\
    return sc>=0 and (sp<0 or [MODEL_NAME].Hierarchy[sp][sc])\n\
\n\
  def isInState(self, s):\n\
\n\
    if isinstance(s, int):\n\
      st=self.state\n\
      while st!=None:\n\
        if st.StateID==s or self.isParent(s, st.StateID):\n\
          return 1\n\
        else:\n\
          st=st.Next\n\
      return 0\n\
\n\
    elif isinstance(s, str):\n\
      for i in range([MODEL_NAME].StateNum):\n\
        if s==[MODEL_NAME].StateNames[i]:\n\
          return self.isInState(i)\n\
      for i in range([MODEL_NAME].StateNum):\n\
        if self.Submodels[i]!=None and startsWith(s, [MODEL_NAME].StateNames[i]+"."):\n\
          SubmodelState=s[len([MODEL_NAME].StateNames[i])+1:]\n\
          return self.isInState(i) and self.Submodels[i].isInState(SubmodelState)\n\
    return 0\n\
\n\
  def main(self, argv):\n\
\n\
[INTERFACE]\
\n\
[INIT_CODE]\
[EVENT_CODE]\
  def forceIntoState(self, s):\n\
\n\
    changed=0\n\
    s2=self.state\n\
    while s2!=None:\n\
      HasCommonParent=0\n\
      for i in range([MODEL_NAME].StateNum):\n\
        if self.isParent(i, s2.StateID) and self.isParent(i, s):\n\
          HasCommonParent=1\n\
          if not self.hasOrthogonalStateInBetween(i, s2.StateID):\n\
            self.changeState(s2.StateID, s)\n\
            changed=1\n\
      if not HasCommonParent:\n\
        self.changeState(s2.StateID, s)\n\
        changed=1\n\
      s2=s2.Next\n\
    if not changed:\n\
      self.addInState(s)\n\
\n\
  def changeState(self, s1, s2, check_history=0, top_level=0):\n\
\n\
    # t1=common(s1, s2)\n\
    t1=[MODEL_NAME].CommonStateTable[s1][s2]\n\
    self.recordHistory(t1)\n\
    if t1>=0:\n\
      self.removeOutStates(t1)\n\
    else:\n\
      self.state=None\n\
    # t2=history(s2)\n\
    t2=[MODEL_NAME].HistoryStateTable[s2]\n\
    if t2==0: # no history\n\
      self.generateStates(t1, s2)\n\
    elif t2==1: # normal history\n\
      if not check_history:\n\
        self.generateStates(t1, s2)\n\
      elif self.hasHistoryRecorded(s2):\n\
        self.generateStates(t1, self.history[s2].States[s2])\n\
      else:\n\
        self.generateStates(t1, s2, 1)\n\
    elif t2==2: # deep history\n\
      if check_history and self.hasHistoryRecorded(s2):\n\
        for i in range([MODEL_NAME].StateNum):\n\
          hs=self.history[s2].States[i]\n\
          if hs>=0 and self.isLeafState(hs):\n\
[CHANGE_STATE_RECORD_ENTER]\
            self.addInState(hs)\n\
      else:\n\
        self.generateStates(t1, s2)\n\
\n\
  def addInState(self, s):\n\
\n\
    if not self.isInState(s):\n\
      st=State()\n\
      st.StateID=s\n\
      st.Next=self.state\n\
      self.state=st\n\
      return 1\n\
    else:\n\
      return 0\n\
\n\
  def generateStates(self, common, dest, history_type=0):\n\
\n\
[STATES_CODE]\
\n\
  def removeOutStates(self, common_state):\n\
\n\
    s=self.state\n\
    prev=None\n\
    while s!=None:\n\
      if self.isParent(common_state, s.StateID):\n\
        if prev==None:\n\
          self.state=self.state.Next\n\
        else:\n\
          prev.Next=s.Next\n\
      else:\n\
        prev=s\n\
      s=s.Next\n\
\n\
  def eventStr2Int(self, event):\n\
\n\
    for i in range([EVENT_NUM]):\n\
      if event==[MODEL_NAME].EventNames[i]:\n\
        return i\n\
    return -1\n\
\n\
  def stateInt2Str(self, state):\n\
\n\
    if state==-1:\n\
      return ""\n\
    else:\n\
      return [MODEL_NAME].StateNames[state]\n\
\n\
  def getCurrentStateList(self):\n\
\n\
    sl=StringList()\n\
    slend=sl\n\
    s=self.state\n\
    while s!=None:\n\
      sm=self.Submodels[s.StateID]\n\
      curstate=self.stateInt2Str(s.StateID)\n\
      if sm!=None:\n\
        slend.Next=sm.getCurrentStateList()\n\
        while slend.Next!=None:\n\
          slend.Next.str=curstate+"."+slend.Next.str\n\
          slend=slend.Next\n\
      else:\n\
        slend.Next=StringList(curstate)\n\
        slend=slend.Next\n\
      s=s.Next\n\
    return sl.Next\n\
\n\
  def getCurrentState(self, states=None):\n\
\n\
    if states==None:\n\
      states=self.getCurrentStateList()\n\
      if states!=None:\n\
        strst="[%s\'%s\']" % (self.getCurrentState(states), states.str)\n\
      else:\n\
        strst="[]"\n\
    else:\n\
      if states.Next:\n\
        strst="%s\'%s\', " % (self.getCurrentState(states.Next), states.Next.str)\n\
      else:\n\
        strst=""\n\
    return strst\n\
\n\
  def getParentState(self, state):\n\
\n\
    return [MODEL_NAME].ParentTable[state]\n\
\n\
[SUBSTATES_CODE]\
  def isHistoryState(self, state):\n\
\n\
    return [MODEL_NAME].HistoryStateTable[state]>0\n\
\n\
  def isLeafState(self, state):\n\
\n\
    if isinstance(state, int):\n\
      return [MODEL_NAME].LeafStateTable[state]!=None\n\
\n\
    elif isinstance(state, str):\n\
      for i in range([MODEL_NAME].StateNum):\n\
        if [MODEL_NAME].LeafStateTable[i]==None:\n\
          continue\n\
        if state==[MODEL_NAME].LeafStateTable[i] and self.Submodels[i]==None:\n\
          return 1\n\
        elif startswith(state, [MODEL_NAME].LeafStateTable[i]+".") and self.Submodels[i]!=None:\n\
          SubmodelState=state[[MODEL_NAME].LeafStateTable[i].length()+1:]\n\
          return self.Submodels[i].isLeafState(SubmodelState)\n\
    return 0\n\
\n\
  def isHistoryUp2Date(self, state, time):\n\
\n\
    for i in range([MODEL_NAME].StateNum):\n\
      if self.history[state].Times[i]>=time:\n\
        return 1\n\
    return 0\n\
\n\
  def mergeHistory(self, state, states, times):\n\
\n\
    max=-1\n\
    for i in range([MODEL_NAME].StateNum):\n\
      if times[i]>max:\n\
        max=times[i]\n\
    if self.isHistoryUp2Date(state, max):\n\
      for i in range([MODEL_NAME].StateNum):\n\
        if times[i]>self.history[state].Times[i]:\n\
          self.history[state].States[i]=states[i]\n\
          self.history[state].Times[i]=times[i]\n\
    else:\n\
      self.history[state].States=copy.copy(states)\n\
      self.history[state].Times=copy.copy(times)\n\
\n\
  def recordHistory(self, top_state):\n\
\n\
    curtime=time.time();\n\
    s=self.state;\n\
    while s!=None:\n\
      child=s.StateID\n\
      states=[]\n\
      times=[]\n\
      for i in range([MODEL_NAME].StateNum):\n\
        states.append(-1)\n\
        times.append(-1)\n\
      states[child]=child\n\
      times[child]=curtime\n\
      if top_state<0 or self.isParent(top_state, child):\n\
        parent=self.getParentState(child)\n\
        if self.isHistoryState(child):\n\
          self.history[child].Submodel=self.Submodels[child]\n\
        while parent!=top_state and times[parent]!=curtime:\n\
          states[parent]=child\n\
          times[parent]=curtime\n\
          if self.isHistoryState(parent):\n\
            self.mergeHistory(parent, states, times)\n\
          child=parent\n\
          parent=self.getParentState(child)\n\
      s=s.Next\n\
\n\
  def hasHistoryRecorded(self, state):\n\
\n\
    for i in range([MODEL_NAME].StateNum):\n\
      if self.history[state].States[i]!=-1:\n\
        return 1\n\
      if self.Submodels[state]!=None:\n\
        return 1\n\
    return 0\n\
\n\
  def hasOrthogonalStateInBetween(self, parent, leaf):\n\
\n\
    return [MODEL_NAME].OrthogonalInBetween[parent+1][leaf]\n\
\n\
  def check_history(self, dest):\n\
\n\
    s=self.state\n\
    while s!=None:\n\
      if self.isParent(dest, s.StateID) and not self.hasOrthogonalStateInBetween(dest, s.StateID):\n\
        return 0\n\
      s=s.Next\n\
    return 1\n\
\n\
  def getEnabledEvents(self):\n\
\n\
[ENABLED_EVENTS_CODE]\
\n\
  def getHierarchy(self, start_level, state_prefix):\n\
\n\
[HIERARCHY_CODE]\
\n\
  def topLevelHistory(self):\n\
\n\
    s=self.state.StateID\n\
    t=self.getParentState(s)\n\
    while t!=-1:\n\
      s=t\n\
      t=self.getParentState(s)\n\
    self.changeState(s, s)\n\
\n\
[ACTION_CODE]\
[CONDITION_CODE]\
[ENTER_ACTIONS]\
[EXIT_ACTIONS]\
[INTERACTOR_CODE]\
[EXTENDED_METHODS]\
[EXTENDED_START]\
[EXTENDED_EVENT]\
\n\
[OTHER_MODELS]\
[ENDING]'

  PythonEnding='\
# main\n\
if __name__=="__main__":\n\
  [MODEL_NAME]().main(sys.argv)'

  TextInterface='\
    model=[MODEL_NAME]()\n\
    cmd=""\n\
    model.initModel()\n\
    if [MODEL_NAME].Description:\n\
      sys.__stdout__.write([MODEL_NAME].Description+"\\n")\n\
    while cmd!="exit":\n\
      sys.__stdout__.write(model.getCurrentState()+" > ")\n\
      cmd=string.strip(sys.__stdin__.readline())\n\
      if cmd=="exit":\n\
        break\n\
      model.handleEvent(cmd)\n'

  TextInterfaceExt='\
    model=[MODEL_NAME]()\n\
    cmd=""\n\
    model.initModel()\n\
    if model.HasInteractor:\n\
      model.runInteractor()\n\
    else:\n\
      if [MODEL_NAME].Description:\n\
        sys.__stdout__.write([MODEL_NAME].Description+"\\n")\n\
      lock=thread.allocate_lock()\n\
      while cmd!="exit":\n\
        sys.__stdout__.write(model.getCurrentState()+" > ")\n\
        cmd=string.strip(sys.__stdin__.readline())\n\
        if cmd=="exit":\n\
          break\n\
        lock.acquire()\n\
        model.event(cmd, [], lock)\n\
        lock.acquire()\n\
        lock.release()\n\
    model.runFinalizer()\n'

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

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

  def generate_code(self, need_header=1, public_class=1):

    self.init_generator()

    if self.action_ext:
      self.handle_timed_transitions()

    if self.action_ext:
      self.handle_model_finalizer()

    header=PythonGenerator.PythonTemplate

    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]
    if self.eventhandler.description:
      description=escape(self.eventhandler.description)
    else:
      description="None"

    if self.action_ext:
      interface=PythonGenerator.TextInterfaceExt
      dummy_code="\
  def recordAllEnteredStates(self):\n\
\n\
    pass\n\
\n\
  def runAllEnterActions(self):\n\
\n\
    pass\n\
\n\
  def runInitializer(self):\n\
\n\
    pass\n\
\n\
  def runFinalizer(self):\n\
\n\
    pass\n\
\n\
  def runInteractor(self):\n\
\n\
    pass\n\
\n\
  def state(self):\n\
\n\
    pass\n\
\n\
  def handleEvent(self, se, params=[], lock=None, call_submodels=1):\n\
\n\
    return 0\n\
\n\
  def event(self, e, params=[], lock=None, call_submodels=1):\n\
\n\
    pass\n\
\n"
      dummy_init_model='\
  def initModel(self, run_initializer=1, run_enter_actions=1):\n\
\n\
    pass\n\
\n'
      scheduler_class='\
# Scheduler for timed transitions (used only when --ext is set)\n\
import thread\n\
import time\n\
class Scheduler:\n\
\n\
  def __init__(self, model, event, interval, repeat):\n\
\n\
    self.Model=model\n\
    self.Event=event\n\
    self.Interval=interval\n\
    self.Repeat=repeat\n\
    self.Lock=thread.allocate_lock()\n\
    self.Stopped=0\n\
    self.Next=None\n\
\n\
  def start(self):\n\
\n\
    thread.start_new_thread(self.run, ())\n\
\n\
  def stop(self):\n\
\n\
    self.Lock.acquire()\n\
    self.Stopped=1\n\
    self.Lock.release()\n\
\n\
  def clear(self):\n\
\n\
    self.stop()\n\
    if self.Next:\n\
      self.Next.clear()\n\
\n\
  def run(self):\n\
\n\
    stopped=0\n\
    while not stopped:\n\
      time.sleep(self.Interval)\n\
      self.Lock.acquire()\n\
      stopped=self.Stopped\n\
      self.Lock.release()\n\
      if not stopped:\n\
        self.Model.event(self.Event, [], None, 0)\n\
        stopped=not self.Repeat\n\
\n\
\n'
      extended_initializer='\
    self.TimedTransitions=[] # used only when --ext is set\n\
    for i in range([MODEL_NAME].StateNum):\n\
      self.TimedTransitions.append(None)\n\
\n\
    self.clearEnteredStates()\n\
\n\
    # Interpreter of action code\n\
    if Interpreter:\n\
      self.DefaultInterpreter=Interpreter\n\
    else:\n\
      self.DefaultInterpreter=InteractiveInterpreter()\n\
    self.HasInteractor=[HAS_INTERACTOR]\n\
    self.setupInterpreter()\n\
\n\
    self.EventsLock=thread.allocate_lock()\n\
    self.PendingEvents=None\n\
    self.PendingEventsTail=None\n\
    self.HandleEventRunning=0\n'
      extended_class_attrs='\
  Lock=thread.allocate_lock()\n\
  CurrentModel=None\n\
\n'
      extended_methods='\
  def recordAllEnteredStates(self):\n\
\n\
    st=self.state\n\
    while st!=None:\n\
      self.recordEnteredState(st.StateID, 1, 1)\n\
      st=st.Next\n\
\n\
  def recordEnteredState(self, s, superstates=0, submodel=0, commonstate=-1):\n\
\n\
    # test if s is already recorded\n\
    se=self.StatesEntered\n\
    found=0\n\
    while se!=None:\n\
      if se.int==s:\n\
        found=1\n\
        break\n\
      se=se.Next\n\
\n\
    if not found:\n\
      if superstates:\n\
        parent=self.getParentState(s)\n\
        if parent>=0 and parent!=commonstate:\n\
          self.recordEnteredState(parent, 1)\n\
      st=IntList()\n\
      st.Next=self.StatesEntered\n\
      st.int=s\n\
      self.StatesEntered=st\n\
      if submodel and self.Submodels[s]:\n\
        self.Submodels[s].recordAllEnteredStates()\n\
\n\
  def runAllEnterActions(self):\n\
\n\
    self.runEnterActionsForStates(self.StatesEntered, 1)\n\
\n\
  def runEnterActionsForStates(self, states, recursive=0):\n\
\n\
    if states:\n\
      self.runEnterActionsForStates(states.Next, 0)\n\
      self.runEnterActions(states.int)\n\
    if recursive:\n\
      for s in self.Submodels:\n\
        if s:\n\
          s.runAllEnterActions()\n\
\n\
  def runExitActionsForStates(self, common_state):\n\
\n\
    substates=self.getSubstates(common_state)\n\
    if substates==None:\n\
      s=self.state\n\
      while s!=None and s.StateID!=common_state:\n\
        s=s.Next\n\
      if s!=None and self.Submodels[s.StateID]:\n\
        self.Submodels[s.StateID].runExitActionsForStates(-1)\n\
      return s!=None\n\
    else:\n\
      has_current_substate=0\n\
      while substates!=None:\n\
        res=self.runExitActionsForStates(substates.int)\n\
        has_current_substate=has_current_substate or res\n\
        if res:\n\
          self.runExitActions(substates.int)\n\
        substates=substates.Next\n\
      return has_current_substate\n\
\n\
  def runInitializer(self):\n\
\n\
    self.runActionCode([INITIALIZER_NUM])\n\
    for s in self.Submodels:\n\
      if s:\n\
        s.runInitializer()\n\
\n\
  def runFinalizer(self):\n\
\n\
    if self.Started:\n\
      for s in self.Submodels:\n\
        if s:\n\
          s.runFinalizer()\n\
      self.runActionCode([FINALIZER_NUM])\n\
      self.Started=0\n\
\n\
  def clearEnteredStates(self):\n\
\n\
    self.StatesEntered=None\n\
    for s in self.Submodels:\n\
      if s:\n\
        s.clearEnteredStates()\n\
\n\
  def runCode(self, c):\n\
\n\
    if len(c)>0:\n\
      l=""\n\
      for i in string.split(c, "\\n"):\n\
        if len(l)==0:\n\
          l=i\n\
        elif string.find(i, " ")!=0 and not (string.find(i, "else")==0 and string.strip(i[4:])==":") and \\\n\
                               string.find(i, "elif ")!=0 and string.find(i, "elif\\t")!=0 and \\\n\
                               not (string.find(i, "except")==0 and string.strip(i[6:])==":") and \\\n\
                               string.find(i, "except ")!=0 and string.find(i, "except\\t")!=0:\n\
          self.DefaultInterpreter.runsource(l+"\\n")\n\
          l=i\n\
        else:\n\
          l=l+"\\n"+i\n\
      if len(l)>0:\n\
        self.DefaultInterpreter.runsource(l+"\\n")\n\
\n\
  def setupInterpreter(self):\n\
\n\
    self.DefaultInterpreter.locals["eventhandler"]=self\n\
    self.DefaultInterpreter.locals["dump_message"]=self.dump_message\n\
\n\
  def checkPendingEvents(self):\n\
\n\
    self.EventsLock.acquire()\n\
    ev=self.PendingEvents\n\
    if ev!=None:\n\
      self.PendingEvents=ev.Next\n\
      if self.PendingEvents==None:\n\
        self.PendingEventsTail=None\n\
      self.EventsLock.release()\n\
      self.handleEvent(ev.Event[0], ev.Event[1], ev.Event[2], ev.Event[3])\n\
    else:\n\
      self.HandleEventRunning=0\n\
      self.EventsLock.release()\n\
\n\
  def get_event_params(self):\n\
\n\
    return self.params\n\
\n\
  def dump_message(self, msg):\n\
\n\
    print msg\n\
\n\
  def is_in_state(self, state, check_substate=0):\n\
\n\
    i=0\n\
    while i<[MODEL_NAME].StateNum and [MODEL_NAME].StateNames[i]!=state:\n\
      i=i+1\n\
    if i<[MODEL_NAME].StateNum:\n\
      return (not check_substate or self.isLeafState(i)) and self.isInState(i)\n\
    else:\n\
      return 0\n\
\n'
      extended_start='\
  def start(self, lock=None, run_enter_actions=1):\n\
\n\
    if run_enter_actions:\n\
      self.runEnterActionsForStates(self.StatesEntered, 1)\n\
    self.Started=1\n\
    if run_enter_actions:\n\
      self.checkPendingEvents()\n\
    if lock:\n\
      lock.release()\n\
\n\
  def shutdown(self):\n\
\n\
    pass\n\
\n'
      import_interpreter='\
# used only when --ext is set\n\
from code import InteractiveInterpreter\n\
\n\
\n'
      change_state_record_enter='\
            # used only when --ext is set\n\
            self.recordEnteredState(hs, 1, 1, t1)\n'
      extended_event='\
  def event(self, e, params=[], lock=None, call_submodels=1):\n\
\n\
    self.EventsLock.acquire()\n\
    running=self.HandleEventRunning\n\
    if not running and self.Started:\n\
      self.HandleEventRunning=1\n\
    self.EventsLock.release()\n\
    if not running and self.Started:\n\
      thread.start_new_thread(self.handleEvent, (e, params, lock, call_submodels))\n\
    else:\n\
      self.EventsLock.acquire()\n\
      ev=EventList()\n\
      ev.Event=[e, params, lock, call_submodels]\n\
      if self.PendingEventsTail!=None:\n\
        self.PendingEventsTail.Next=ev\n\
      else:\n\
        self.PendingEvents=ev\n\
      self.PendingEventsTail=ev\n\
      self.EventsLock.release()\n\
\n'
      int_list='\
class IntList:\n\
\n\
  def __init__(self, int=0):\n\
\n\
    self.int=int\n\
    self.Next=None\n\
\n\
\n'
    else:
      interface=PythonGenerator.TextInterface
      dummy_code="\
  def handleEvent(self, se):\n\
\n\
    return 0\n\
\n"
      dummy_init_model='\
  def initModel(self):\n\
\n\
    pass\n\
\n'
      scheduler_class=""
      extended_initializer=""
      extended_class_attrs=""
      extended_methods=""
      extended_start='\
  def start(self):\n\
\n\
      self.Started=1\n\
\n'
      import_interpreter=""
      change_state_record_enter=""
      extended_event=""
      int_list=""

    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,
            "[INTERFACE]": interface,
            "[MODEL_NAME]": self.model_name,
            "[INIT_CODE]": self.find_initial_state(self.eventhandler.stateH),
	    "[HIERARCHY_DEFINITION]": self.generate_hierarchy_def(),
	    "[OTHER_MODELS]": self.generate_other_models(),
	    "[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(),
            "[ENTER_ACTIONS]": self.generate_enter_actions(),
            "[EXIT_ACTIONS]": self.generate_exit_actions(),
            "[INTERACTOR_CODE]": self.generate_interactor_code(),
            "[DUMMY_CODE]": dummy_code,
            "[DUMMY_INIT_MODEL]": dummy_init_model,
            "[IMPORT_INTERPRETER]": import_interpreter,
            "[CHANGE_STATE_RECORD_ENTER]": change_state_record_enter,
            "[SCHEDULER]": scheduler_class,
            "[EXTENDED_INITIALIZER]": extended_initializer,
            "[EXTENDED_CLASS_ATTRS]": extended_class_attrs,
            "[EXTENDED_METHODS]": extended_methods,
            "[EXTENDED_START]": extended_start,
            "[EXTENDED_EVENT]": extended_event,
            "[INTLIST]": int_list,
	    "[ACTION_CODE]": self.generate_action_code(),
            "[CONDITION_CODE]": self.generate_condition_code(),
            "[INITIALIZER_NUM]": str(self.initializer_num),
            "[FINALIZER_NUM]": str(self.finalizer_num),
            "[SUBSTATES_CODE]": self.generate_substates_code(),
            "[HAS_INTERACTOR]": str(self.eventhandler.has_interactor and self.action_ext)}

    if need_header:
      macros["[HEADER]"]=PythonGenerator.PythonHeader
      macros["[ENDING]"]=PythonGenerator.PythonEnding
    else:
      macros["[HEADER]"]=''
      macros["[ENDING]"]=''
    if public_class:
      macros["[ACCESSIBILITY]"]='# Main Class -- the top level model that is executed from the command line\n'
    else:
      macros["[ACCESSIBILITY]"]=''

    priority_macros=["[INTERFACE]", "[HEADER]", "[ENDING]", "[EXTENDED_METHODS]", "[EXTENDED_INITIALIZER]"]
    return replace_macros(header, priority_macros, macros)

  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+"1"
        else:
          code=code+"0"
        cs=cs+1
      code=code+"]"
      codes.append(code)
      comments.append("substates of state %s" % states[ps])
      ps=ps+1
    return self.generate_array("Hierarchy", codes, comments)

  def generate_event_code(self):
    if self.action_ext:
      code='\
  def handleEvent(self, se, params=[], lock=None, call_submodels=1):\n\
\n\
    if not self.Started:\n\
      if lock:\n\
        lock.release()\n\
      return 0\n\
    self.EventsLock.acquire()\n\
    self.HandleEventRunning=1\n\
    self.EventsLock.release()\n\
    self.params=params\n'
    else:
      code='\
  def handleEvent(self, se):\n\
\n\
    if not self.Started:\n\
      return 0\n'

    code=code+'\
    e=self.eventStr2Int(se)\n'

    i=0
    keys=self.eventhandler.trans.keys()
    keys.sort()
    for t in keys:
      if i==0:
        code=code+'\
    if'
      else:
        code=code+'\
    elif'

      i=i+1
      code=code+' e==%d: # event "%s"\n' % (self.event_table2[t], t) + self.generate_check_state_code(self.eventhandler.trans, t)
    keys=self.submodels.keys()
    keys.sort()

    if self.action_ext:
      for k in keys:
        code=code+'\
    if self.isInState(%d) and call_submodels and self.Submodels[%d].handleEvent(se, params):\n\
      if lock:\n\
        lock.release()\n\
      self.checkPendingEvents()\n\
      return 1\n' % (k, k)
      code=code+'\
    if lock:\n\
      lock.release()\n\
    self.checkPendingEvents()\n'
    else:
      for k in keys:
        code=code+'\
    if self.isInState(%d) and call_submodels and self.Submodels[%d].handleEvent(se, params):\n\
      return 1\n' % (k, k)
    code=code+'\
    return 0\n'
    return code+"\n"

  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+" and self.testCondition(%d)" % condition_num

      stnum=self.get_state_num(t['S'])
      code=code+'\
      if self.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+'\
        self.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+'\
        self.runActionCode(%d) # output action(s)\n' % action_num

      if self.action_ext and self.eventhandler.options[HAREL]=='1':  # exit actions
        code=code+'\
        self.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 self.isInState(%d) and call_submodels and self.Submodels[%d].handleEvent(se, params):\n\
          if lock:\n\
            lock.release()\n\
          self.checkPendingEvents()\n\
          return 1\n' % (k, k)
	      else:
	        code=code+'\
        if call_submodels and self.Submodels[%d].handleEvent(se, params):\n\
          if lock:\n\
            lock.release()\n\
          self.checkPendingEvents()\n\
          return 1\n' % k
            else:
              if path!=t['S']:
                code=code+'\
        if self.isInState(%d) and call_submodels and self.Submodels[%d].handleEvent(se, params):\n\
          return 1\n' % (k, k)
	      else:
	        code=code+'\
        if call_submodels and self.Submodels[%d].handleEvent(se, params):\n\
          return 1\n' % k
      [p, sp]=self.find_submodel_path(t['N'])
      if t[HISTORY_STATE]:
	chkhs=", 1"
      else:
	chkhs=""

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

      if sp:  # transition into a submodel
	pnum=self.get_state_num(p)
	code=code+'\
        self.changeState(%s, %s%s)\n\
        self.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+'\
        self.changeState(%s, %s%s)\n' % (self.get_state_num(t['S']), self.get_state_num(t['N']), chkhs)

      if self.action_ext:
        code=code+'\
        self.runEnterActionsForStates(self.StatesEntered, 1)\n\
        if lock:\n\
          lock.release()\n\
        self.checkPendingEvents()\n'
        
      code=code+'\
        return 1\n'
    return code

  def generate_states_code(self, stateH=None, path="", code="", space=4):
    first=0
    sk=self.state_table2.keys()
    sk.sort()
    if not code:
      first=1
      stateH=self.eventhandler.stateH
      code=code+" "*space+"if common==-1:\n"
      i=0
      for s in sk:
        if i==0:
          code=code+" "*space+"  if"
        else:
          code=code+" "*space+"  elif"
        i=i+1

        code=code+" dest==%d:\n" % self.get_state_num(s) \
	    + " "*space+"    if history_type!=2 or self.check_history(-1):\n" \
	    + self.generate_in_states(stateH, "", s, 10)
    keys=stateH.keys()
    keys.sort()
    for k in keys:
      if not k in StateProperties:
	newpath=self.eventhandler.append_path(path, k)
	code=code+" "*space+"elif common==%d:\n" % self.get_state_num(newpath)
        i=0
	for s in sk:
	  if self.eventhandler.is_or_is_substate(s, newpath):
            if i==0:
	      code=code+" "*space+"  if"
            else:
              code=code+" "*space+"  elif"
            i=i+1

	    record_state=""
	    if self.action_ext and self.eventhandler.options[HAREL]=='1':
              record_state=" "*space+"      self.recordEnteredState(%s)\n" % self.get_state_num(newpath)

	    code=code+" dest==%d:\n" % self.get_state_num(s) \
	    + " "*space+"    if history_type!=2 or self.check_history(%d):\n" % self.get_state_num(newpath) \
	    + record_state \
	    + self.generate_in_states(stateH[k], newpath, s, space+6)
	code=self.generate_states_code(stateH[k], newpath, code, space)
    return code

  def generate_in_states(self, stateH, com, des, space=10):
    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)

	    record_state=""
	    if self.action_ext:
              record_state=" "*space+"  self.recordEnteredState(%s)\n" % self.get_state_num(next_com)

	    code=code+" "*space+'if history_type!=2 or self.check_history(%d):\n' % self.get_state_num(next_com)
	    code=code+record_state
	    if s!=p:
	      code=code+self.generate_in_states(states[s], next_com, next_com, space+2)
	    else:
	      code=code+self.generate_in_states(states[s], next_com, des, space+2)
      else:
	loopin=1
	next_com=self.eventhandler.append_path(com, p)

        record_state=""
	if self.action_ext:
          record_state=" "*space+"  self.recordEnteredState(%s)\n" % self.get_state_num(next_com)

	code=code+" "*space+'if history_type!=2 or self.check_history(%d):\n' % self.get_state_num(next_com)
	code=code+record_state

	code=code+self.generate_in_states(states[p], next_com, des, space+2)
      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)

	  record_state=""
	  if self.action_ext:
            record_state=" "*space+"  self.recordEnteredState(%s)\n" % self.get_state_num(next_com)

          code=code+" "*space+'if history_type!=2 or self.check_history(%d):\n' % self.get_state_num(next_com)
	  code=code+record_state

	  code=code+self.generate_in_states(states[s], next_com, next_com, space+2)
      if not found_def:
	code=code+" "*space+'self.addInState(%d)  # move into leaf state "%s"\n' % (desnum, des)
	stnum=self.get_state_num(des)
	if self.submodels.has_key(stnum):
	  code=code + \
" "*space+'if history_type==1 and self.Submodels[%d]!=None:\n'%stnum + \
" "*space+'  self.Submodels[%d].topLevelHistory()\n'%stnum + \
" "*space+'elif history_type!=2 or self.Submodels[%d]==None:\n'%stnum
          if self.action_ext:
            code=code + \
" "*space+'  run_initializer=1\n' + \
" "*space+'  if self.Submodels[%d]:\n' % stnum + \
" "*space+'    run_initializer=0\n' + \
" "*space+'  self.Submodels[%d]=%s()\n' % (stnum, self.submodels[stnum]) + \
" "*space+'  self.Submodels[%d].initModel(run_initializer, 0)\n' % stnum
          else:
            code=code + \
" "*space+'  self.Submodels[%d]=%s()\n' % (stnum, self.submodels[stnum]) + \
" "*space+'  self.Submodels[%d].initModel()\n' % stnum
    return code

  def generate_array(self,  aname, alist, comments=None):
    code="\
  %s=[" % aname
    space=(4+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("EventNames", 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("StateNames", states)

  def find_initial_state(self, stateH, path=''):
    """ To find the initial state(s) in the state hierachy, stateH.
    """
    if path=='' and self.action_ext:
      code='\
  def initModel(self, run_initializer=1, run_enter_actions=1):\n\
\n\
    self.clearEnteredStates()\n'
    elif path=='':
      code='\
  def initModel(self):\n\
\n'
    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+'\
    self.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+'\
    self.recordEnteredState(%s)\n' % self.get_state_num(s)

                enter_recorded.append(s)
	    if self.submodels.has_key(stnum):
              if self.action_ext:
                code=code+'\
    self.Submodels[%d]=%s()\n\
    self.Submodels[%d].initModel(0, 0)\n\
\n' % (stnum, self.submodels[stnum], stnum)
              else:
                code=code+'\
    self.Submodels[%d]=%s()\n\
    self.Submodels[%d].initModel()\n\
\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\
      self.runInitializer()\n\
    if not self.HasInteractor:\n\
      self.start(None, run_enter_actions)\n'
    elif path=='':
      code=code+'\
    self.Started=1\n'

    if init_final:
      code=code+'\
    self.runFinalizer()  # One of the initial states is final\n'

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

    return code

  def generate_other_models(self):
    code=''
    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
	pg=PythonGenerator(eh, self.action_ext)
	code=code+'\
# Submodel Class "%s" -- the submodel executed by the top-level model\n' % eh.options[MODEL_NAME] + pg.generate_code(0, 0)
	self.generated_models[eh.options[MODEL_NAME]]=pg
    return code

  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("ParentTable", 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("HistoryStateTable", 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('None');
    return self.generate_array("LeafStateTable", 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+"1"
	else:
	  code=code+"0"
	if i<self.state_num-1:
	  code=code+", "
	i=i+1
      code=code+"]"
      codes.append(code)
    return self.generate_array("OrthogonalInBetween", 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("CommonStateTable", codes)

  def generate_enabled_events_code(self):
    code="\
    events=EventList()\n"
    keys=self.eventhandler.trans.keys()
    keys.sort()
    for k in keys:
      for t in self.eventhandler.trans[k]:
        code=code+"\
    if self.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 self.isInState(%d):\n\
      events.Append(self.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=Hierarchy()\n\
    lasth.Next.StateName="%s"\n\
    if state_prefix==None:\n\
      lasth.Next.PathName="%s"\n\
    else:\n\
      lasth.Next.PathName=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]!=None:\n\
      lasth.Next=self.Submodels[%d].getHierarchy(start_level+%d+1, lasth.PathName)\n\
      while lasth.Next!=None:\n\
        lasth=lasth.Next\n' % (snum, snum, level)
	code=self.generate_hierarchy_code_rec(code, stateH[k], level+1, newpath)
    return code

  def generate_hierarchy_code(self):
    code="\
    h=Hierarchy()\n\
    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="\
  def runActionCode(self, code_num):\n\
\n"
      i=0
      for action in self.actions:
        command=action[0]
        comment=action[1]
        if i==0:
          code=code+'\
    if code_num==%d: # %s\n' % (i, comment)
        else:
          code=code+'\
    elif code_num==%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)+'self.runCode(%s)' % cmd
            code=code+cmd+"\n"
        else:
          code=code+"      pass\n"
      return code+"\n"
    else:
      return ""

  def generate_condition_code(self):
    if self.action_ext:
      code="\
  def testCondition(self, cond_num):\n\
\n"
      i=0
      for condition in self.conditions:
        if i==0:
          code=code+'\
    if cond_num==%d and \\\n' % i
        else:
          code=code+'\
    elif cond_num==%d and \\\n' % i
        i=i+1
        if condition:
          cond=self.svm_guard_2_scc_guard(condition)
          code=code+"       "+cond
        else:
          code=code+"       1"
        code=code+":\n"
        code=code+"\
      return 1\n"
      code=code+"\
    return 0\n"
      return code+"\n"
    else:
      return ""

  def generate_enter_actions(self):
    if self.action_ext and self.eventhandler.enter:
      code="\
  def runEnterActions(self, state):\n\
\n"
      i=0
      for s in self.eventhandler.enter.keys():
        sn=self.state_table2[s]  # actions for state s in a submodel are omitted
        if i==0:
          code=code+'\
    if'
        else:
          code=code+'\
    elif'
        i=i+1
        code=code+' state==%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('|if %s:' % self.svm_guard_2_scc_guard(ent['C']))
            for o in ent['O']:
              enter.append("  "+o)
          else:
            enter=enter+ent['O']
        self.actions.append([enter, 'enter actions for state "%s"' % s])
        code=code+'\
      self.runActionCode(%d)\n' % enter_num
      return code+"\n"
    elif self.action_ext:
      return '\
  def runEnterActions(self, state):\n\
\n\
    pass\n\
\n'
    else:
      return ""

  def generate_exit_actions(self):
    if self.action_ext and self.eventhandler.exit:
      code="\
  def runExitActions(self, state):\n\
\n"
      i=0
      for s in self.eventhandler.exit.keys():
        sn=self.state_table2[s]  # actions for state s in a submodel are omitted
        if i==0:
          code=code+'\
    if'
        else:
          code=code+'\
    elif'
        i=i+1
        code=code+' state==%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('|if %s:' % self.svm_guard_2_scc_guard(ext['C']))
            for o in ext['O']:
              exit.append("  "+o)
          else:
            exit=exit+ext['O']
        self.actions.append([exit, 'exit actions for state "%s"' % s])
        code=code+'\
      self.runActionCode(%d)\n' % exit_num
      return code+"\n"
    elif self.action_ext:
      return '\
  def runExitActions(self, state):\n\
\n\
    pass\n\
\n'
    else:
      return ""

  def generate_substates_code(self):  # necessary only if --ext is set
    if self.action_ext:
      code="\
  def getSubstates(self, state):\n\
\n\
    substates=None\n"
      i=0
      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=[]
        if i==0:
          code=code+"\
    if"
        else:
          code=code+"\
    elif"
        i=i+1
        code=code+' state==%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=IntList()\n\
      st.int=%d\n\
      st.Next=substates\n\
      substates=st\n' % (ss, ssnum)
              added=1
        if not added:
          code=code+'\
      pass\n'
      code=code+'\
    return substates\n'
      return code+"\n"
    else:
      return ""

  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:
        self.eventhandler.enter[s].append({'O': [
               '|# a timed transition',
               '|sched=Scheduler(self, "%s", eval(%s, self.DefaultInterpreter.locals), %d)' % (
                   tt[0], escape(tt[1]), tt[3]),
               '|sched.Next=self.TimedTransitions[%s]' % snum,
               '|self.TimedTransitions[%s]=sched' % snum,
               '|sched.start()']})
        self.eventhandler.exit[s].append({'O': [
               '|# clean up timed transitions',
               '|if self.TimedTransitions[%s]:' % snum,
               '|  self.TimedTransitions[%s].clear()' % snum,
               '|  self.TimedTransitions[%s]=None' % snum]})

  def generate_interactor_code(self):
    if self.action_ext and self.eventhandler.has_interactor:
      interactor_num=len(self.actions)
      self.actions.append([self.eventhandler.interactor, "model-specific interactor"])
      code='\
  def runInteractor(self):\n\
\n\
    self.DefaultInterpreter.runsource("from Tkinter import *")\n\
    self.runActionCode(%d)\n\
    self.runEnterActionsForStates(self.StatesEntered, 1)\n\
\n' % interactor_num
    else:
      code=""
    return code

  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',
               '|self.runFinalizer()']})

  def svm_guard_2_scc_guard(self, condition):
    cond=strip(condition)
    head="EventHandler.vtest="
    if startswith(cond, head):
      newcond=escape(cond[len(head):])
      newcond=newcond[1:len(newcond)-1]
      cond='self.DefaultInterpreter.runsource("eventhandler.TestResult=%s")==0' % newcond
    return "%s and self.TestResult" % cond
