text: import sys, string, cStringIO
  import traceback
  #from Ft.Xml.Xslt import Processor
  from Ft.Xml.Xslt import XsltContext, parser
  from Ft.Xml.Xslt import AttributeValueTemplate, TemplateElement
  from Ft.Xml.XPath import Conversions, NAMESPACE_NODE, CompiletimeException, RuntimeException
  import Ft.Xml.XPath
  
  
  #try:
  #    import readline
  #except ImportError:
  #    pass
  
  import DebugCommands
  import DebugWriter, TerminalInput, TerminalOutput
  
  class DebugState:
      STOP_NEXT = 1
      RUN = 2
      STOP_TEMPLATE = 4
      STOP_END = 5
      TEST=100
  
  class DebugController:
  
      def __init__(self):
          self.stack = [('Root',[])]
  
          self.state = DebugState.STOP_NEXT
  
          self.writer = DebugWriter.DebugWriter()
  
          self.lastResult = None
  
          self.lastOutputs = []
  
          self.breakPoints = {}
  
          self.callCtr = 0
  
          self.outputHandler = TerminalOutput.TerminalOutputHandler()
          self.inputHandler = TerminalInput.TerminalInputHandler()
  
  
      def startCall(self,element,context):
  
          self.callCtr = self.callCtr + 1
          self.stack.append((element,[]))
          self.context = context
  
          nextCmd = None
  
          btest = (hasattr(element,'baseUri') and (element.baseUri,element.lineNumber) in self.breakPoints.values())
  
  
          stop = ((self.state == DebugState.STOP_NEXT) or
                  (self.state == DebugState.STOP_TEMPLATE and isinstance(element,TemplateElement.TemplateElement)) or
                  btest
                  )
  
  
          returnValue = 0
          if stop:
              if btest:
                  for bNum, bValue in self.breakPoints.items():
                      if (element._4debug_fileName,element._4debug_lineNum)  == bValue:
                          break
                  self.outputHandler.display("Break at #%d" % bNum)
  
              self.lastOutputs = self.writer.getCurrent()
  
              nextCmd = self.getCommand()
  
              #Process the next command
              if nextCmd == DebugCommands.RUN:
                  self.state = DebugState.RUN
              elif nextCmd == DebugCommands.TEMPLATE:
                  self.state = DebugState.STOP_TEMPLATE
              elif nextCmd == DebugCommands.STEP:
                  self.state = DebugState.STOP_NEXT
              elif nextCmd == DebugCommands.NEXT:
                  self.state = DebugState.STOP_END
                  returnValue = DebugState.STOP_NEXT
          return returnValue
  
      def endCall(self,element,context,endState,result):
          self.lastResult = result
          cur = self.stack[-1]
          self.stack = self.stack[:-1]
  
          self.stack[-1][1].append(cur)
  
          if endState:
              self.state = endState
  
      def getCommand(self):
  
          self.outputHandler.display_currentPosition(self.getCurrentElement())
          while 1:
  
  
              cmd,args = self.inputHandler.getNextCommand(self.outputHandler)
  
              cmd = self.process(cmd,args,self)
              if cmd:
                  return cmd
  
  
      def process(self,cmd,args,dc):
  
          self.outputHandler.display_currentCommand(cmd)
  
          if cmd in DebugCommands.g_runCommands:
              return cmd
  
          if cmd == DebugCommands.QUIT:
              raise DebugCommands.ExitException()
          elif cmd == DebugCommands.PRINT:
              #Print the context
              self.doPrint(args)
          elif cmd == DebugCommands.LIST_SHEET:
              #Print the context
              self.listSheet(args)
          elif cmd == DebugCommands.LIST_TEMPLATE:
              #Print the template
              self.listTemplate(args)
          elif cmd == DebugCommands.BACK_TRACE:
              #Print a back trace
              self.backTrace(args)
          elif cmd == DebugCommands.TEST:
              #Print a back trace
              self.test(args)
          elif cmd == DebugCommands.EVAL:
              #Print a back trace
              self.eval(args)
          elif cmd == DebugCommands.MATCH:
              #Print match on XPattern
              self.match(args)
          elif cmd == DebugCommands.AVT:
              #Eval an AVT
              self.avt(args)
          elif cmd == DebugCommands.SET_BREAK:
              #Eval an AVT
              self.setBreak(args)
          elif cmd == DebugCommands.LIST_BREAK:
              #Eval an AVT
              self.listBreak(args)
          elif cmd == DebugCommands.DELETE_BREAK:
              #Eval an AVT
              self.deleteBreak(args)
          elif cmd == DebugCommands.HELP:
              #Eval an Help
              self.help(args)
          return None
  
  
      def deleteBreak(self,args):
  
          if len(args) != 1:
              self.outputHandler.write("'db' requires exactly one argument\n")
              return
  
          try:
              bNum = int(args[0])
          except:
              self.outputHandler.display_error("Invalid integer argument %s" % str(args[0]))
              return
  
  
          if self.breakPoints.has_key(bNum):
              self.outputHandler.display("Break Point #%d deleted" % bNum)
              del self.breakPoints[bNum]
          else:
              self.outputHandler.display_error("Unknown Break Point #%d" % bNum)
  
  
      def listBreak(self,args):
          if len(args):
              self.outputHandler.display("'lb' requires exactly no argument")
              return
  
          self.outputHandler.display_breakpoints(map(lambda x:(x[0],x[1][1],x[1][0]),self.breakPoints.items()))
  
  
      def setBreak(self,args):
          fileName = None
          lineNum = None
          if len(args) == 1:
              #Get them
              try:
                  lineNum = int(args[0])
              except:
                  self.outputHandler.display_error("Invalid integer argument %s" % str(args[0]))
                  return
          elif len(args) == 2:
              fileName = args[0]
              try:
                  lineNum = int(args[1])
              except:
                  self.outputHandler.display_error("Invalid integer argument %s" % str(args[1]))
                  return
          else:
              self.outputHandler.display_error("'break' requires one or two arguments")
              return
          if fileName is None:
              if hasattr(self.getCurrentElement(),'_4debug_fileName'):
                  fileName = self.getCurrentElement()._4debug_fileName
              else:
                  import FtDebug.Debugger
                  fileName =  FtDebug.Debugger.g_files.keys()[0]
  
          bps = self.breakPoints.keys()
          bps.sort()
          if len(bps) == 0:
              bNum = 0
          else:
              bNum = bps[-1] + 1
          self.outputHandler.display("Break point #%d set at line %d file %s" % (bNum,lineNum,fileName))
          self.breakPoints[bNum] = (fileName,lineNum)
  
      def getCurrentElement(self):
          return self.stack[-1][0]
  
  
      def backTrace(self,args):
          if len(args):
              self.outputHandler.display_error("'bt' requires exactly no argument")
              return
          tb = map(lambda x:x[0],self.stack)
  
  
          self.outputHandler.display_backTrace(tb)
  
  
  
      def avt(self,args):
          if not len(args):
              self.outputHandler.display_error("'avt' requires atleast one argument\n")
              return
  
          expr = string.join(args,',')
  
          con = self._copyContext(self.context)
          try:
              a = AttributeValueTemplate.AttributeValueTemplate(expr)
              rt = a.evaluate(con)
              self.outputHandler.display_expressionResults(expr,rt)
          except (CompiletimeException, RuntimeException):
              try:
                  etype, value, tb = sys.exc_info()
                  self.outputHandler.display_exception(etype,value,None)
              finally:
                  etype = value = tb = None
  
  
  
      def match(self,args):
          if not len(args):
              self.outputHandler.display_error("'match' requires atleast one argument")
              return
  
          expr = string.join(args,',')
  
          con = self._copyContext(self.context)
          try:
              pattern = parser.new().parse(expr)
              rt = pattern.match(con,con.node)
              self.outputHandler.display_expressionResults(expr,rt)
          except SyntaxError:
              try:
                  etype, value, tb = sys.exc_info()
                  self.outputHandler.display_exception(etype,value,None)
              finally:
                  etype = value = tb = None
  
      def test(self,args):
          if not len(args):
              self.outputHandler.display_error("'test' requires atleast one argument")
              return
  
          expr = string.join(args,',')
          rt = self._select(self.context,expr)
          if rt is None:
              return
          rt = Conversions.BooleanValue(rt)
          self.outputHandler.display_expressionResults(expr,rt)
  
      def eval(self,args):
          if not len(args):
              sys.stderr.write("'eval' requires atleast one argument\n")
              return
  
          expr = string.join(args,',')
  
          rt = self._select(self.context,expr)
  
          if rt is None:
              return
  
          self.outputHandler.display_selectResults(expr,rt)
  
  
      def _select(self,context,expr):
  
          #Copy the context
          con = self._copyContext(context)
          try:
              return Ft.Xml.XPath.Evaluate(expr,context = con)
          except (CompiletimeException, RuntimeException):
              try:
                  etype, value, tb = sys.exc_info()
                  traceback.print_exception(etype, value, None)
              finally:
                  etype = value = tb = None
  
      def _copyContext(self,inCon):
          return XsltContext.XsltContext(inCon.node,
                                         inCon.position,
                                         inCon.size,
                                         inCon.currentNode,
                                         inCon.varBindings,
                                         inCon.processorNss,
                                         inCon.stylesheet,
                                         inCon.mode)
  
  
      def listSheet(self,args):
          fileName = None
          start = None
          end = None
          if len(args) == 1:
              #Get them
              #[fileName:]start[-end]
              fields = string.split(args[0],':')
              if len(fields) == 1:
                  fileName = fields[0]
                  se = None
              elif len(fields) == 2:
                  fileName = fields[0]
                  se = fields[1]
              else:
                  self.outputHandler.display_error("Invalid argument %s" % str(args[0]))
                  return
              if se is not None:
                  fields = string.split(se,'-')
                  if len(fields) == 1:
                      try:
                          start = int(fields[0])
                      except:
                          self.outputHandler.display_error("Invalid integer argument %s" % str(fields[0]))
                          return
                  elif len(fields) == 2:
                      try:
                          start = int(fields[0])
                      except:
                          self.outputHandler.display_error("Invalid integer argument %s" % str(fields[0]))
                          return
                      try:
                          end = int(fields[1])
                      except:
                          self.outputHandler.display_error("Invalid integer argument %s" % str(fields[1]))
                          return
                  else:
                      self.outputHandler.display_error("Invalid argument %s" % str(args))
                      return
  
          elif len(args) != 0:
              self.outputHandler.display_error("'ls' requires zero or one arguments")
              return
          self.outputHandler.display_sheet(self.getCurrentElement(),start,end,fileName)
  
      def listTemplate(self,args):
          if len(args):
              self.outputHandler.display("'lt' requires exactly no argument")
              return
  
          tb = map(lambda x:x[0],self.stack)
          tb = filter(lambda x:isinstance(x,TemplateElement.TemplateElement),tb)
          if len(tb) == 0:
              self.outputHandler.display_error("No Templates Found")
          else:
              self.outputHandler.display_node(tb[-1])
  
      def help(self,args):
          if len(args) > 1:
              self.outputHandler.display("'help' requires no arguments")
              return
  
          self.outputHandler.display_help(args)
  
  
      def doPrint(self,args):
  
          if len(args) != 1:
              self.outputHandler.display("'print' requires exactly one argument\n")
              return
          arg = args[0]
  
          #Just make it look like a python instance
  
          if arg == 'con':
              self.outputHandler.display_context(self.context)
          elif arg == 'con.position':
              self.outputHandler.display_contextPosition(self.context.position)
          elif arg == 'con.size':
              self.outputHandler.display_contextSize(self.context.size)
          elif arg == 'con.node':
              self.outputHandler.display_contextNode(self.context.node)
          elif arg == 'con.mode':
              self.outputHandler.display_contextMode(self.context.mode)
          elif arg == 'con.currentNode':
              self.outputHandler.display_contextCurrentNode(self.context.currentNode)
          elif arg == '$':
              self.outputHandler.display_lastResult(self.lastResult)
          elif arg == '$$':
              self.outputHandler.display_lastOutputs(self.lastOutputs)
          else:
              self.outputHandler.display_error("Unknown Variable '%s'"%arg)
  
  
  