#!/usr/bin/env python
# InteractiveDriver.py
#
#   Copyright (C) 2006 CCLRC, Graeme Winter
#
#   This code is distributed under the BSD license, a copy of which is
#   included in the root directory of this package.
#
# 24th May 2006
#
# An implementation based on the simplest Driver type - the one which
# just wraps the subprocess.Popen class. Note well: this will require
# Python 2.4. However, this adds timeouts and job control to the mix -
# a better use of the interactive interface.
#
# Applicability: Windows/OS X/UNIX
#

import subprocess

from DefaultDriver import DefaultDriver
from DriverHelper import kill_process

class InteractiveDriver(DefaultDriver):

  def __init__(self):
    DefaultDriver.__init__(self)

    self._popen = None

    return

  def start(self):
    if self._executable is None:
      raise RuntimeError, 'no executable is set.'

    command_line = []
    command_line.append(self._executable)
    for c in self._command_line:
      command_line.append(c)

    self._popen = subprocess.Popen(command_line,
                                   bufsize = 1,
                                   stdin = subprocess.PIPE,
                                   stdout = subprocess.PIPE,
                                   stderr = subprocess.STDOUT,
                                   cwd = self._working_directory,
                                   universal_newlines = True,
                                   shell = True)

    # somehow here test for failure - oh, you can't because
    # the shell spawned is probably still ok

    # check here anyway - sometimes this failure can be trapped

    if not self.check():
      # do something useful here - need to look for signs that the
      # program has stopped unexpectedly not just been instant
      pass

    return

  def check(self):
    '''Overload the default check method.'''

    if self._popen.poll() is None:
      return True

    return False

  def _input(self, record):

    if not self.check():
      raise RuntimeError, 'child process has termimated'

    self._popen.stdin.write(record)

    return

  def _output(self):
    # need to put some kind of timeout facility on this...
    # in particular for the interactive version

    # 31/MAY/06
    # oh - looks like there isn't a portable way of doing this -
    # select does not work with file descriptors on Windows
    return self._popen.stdout.readline()

  def _status(self):
    # get the return status of the process

    return self._popen.poll()

  def close(self):
    if not self.check():
      raise RuntimeError, 'child process has termimated'

    self._popen.stdin.close()

    return

  def kill(self):
    kill_process(self._popen)

    return

if __name__ == '__main__':
  # run a test for segmentation fault

  d = InteractiveDriver()

  d.set_executable('EPSegv')
  d.start()
  d.close()
  while True:
    line = d.output()
    if not line:
      break

  d.check_for_errors()
