#!/usr/bin/env python
#
#   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 of the Driver class which writes scripts, which are run
# and the results piped to an output file. The content of this output file
# is then returned through the output() method.
# 
# Applicability: Windows/OS X/UNIX
# 
# FIXME 23/AUG/06 this probably shouldn't have it's own record of input
#                 and output records beyond what is already stored in the
#                 DefaultDriver - this is why the hack for reset() below
#                 is needed. This should be unified!
# 
# 

import os
import subprocess

from DefaultDriver import DefaultDriver
from DriverHelper import script_writer

# Workings on Windows:
# 
# Write input to a .input file
# Write a script to run scala < foo.xin > foo.xout
# 
# Workings on UNIX:
#
# Write a script to run
# scala << eof > foo.output
# input
# eof
#
# in both cases these can be initiated by os.system() calls e.g.
# os.system('bash myscript') on UNIX or os.system('myscript.bat') on Windows
# 
# Would also be useful to be able to get the script-level status out - so
# when the script is being written ensure that the return codes from the
# commands are stored and the first to fail is returned.
#
# On UNIX these will be /bin/bash scripts - I will just assume that this works
# since I am supporting only recent linux and OS X installations.
# 
# Specifications:
# 
# This will make an input .xin and output .xout file.

class ScriptDriver(DefaultDriver):

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

        self._script_command_line = []
        self._script_standard_input = []

        self._script_name = self._name

        self._script_status = 0

        # this is opened by the close() method and read by output
        # from self._script_name.xout
        
        self._output_file = None

        return

    def reset(self):
        DefaultDriver.reset(self)

        self._script_command_line = []
        self._script_standard_input = []

        self._script_status = 0

        # this is opened by the close() method and read by output
        # from self._script_name.xout
        
        self._output_file = None

        return

    def set_name(self, name):
        return self.setName(name)

    def setName(self, name):
        '''Set the name to something sensible.'''
        self._script_name = name
        
        return

    def start(self):
        '''This is pretty meaningless in terms of running things through
        scripts...'''
        
        for c in self._command_line:
            self._script_command_line.append(c)

    def check(self):
        '''NULL overloading of the default check method.'''
        return True

    def _input(self, record):
        self._script_standard_input.append(record)

        return

    def _output(self):
        return self._output_file.readline()

    def _status(self):
        return self._script_status

    def close(self):
        '''This is where most of the work will be done - in here is
        where the script itself gets written and run, and the output
        file channel opened when the process has finished...'''

        script_writer(self._working_directory,
                      self._script_name,
                      self._executable,
                      self._script_command_line,
                      self._working_environment,
                      self._script_standard_input)

        if os.name == 'posix':
            pipe = subprocess.Popen(['bash', '%s.sh' % self._script_name],
                                    cwd = self._working_directory)

        else:
            pipe = subprocess.Popen(['%s.bat' % self._script_name],
                                    cwd = self._working_directory,
                                    shell = True)
            
        self._script_status = pipe.wait()

        # at this stage I should read the .xstatus file to determine if the
        # process has indeed finished - though it should have done...

        try:
            xstatus_file = os.path.join(self._working_directory,
                                        '%s.xstatus' % self._script_name)
            self._script_status = int(open(xstatus_file, 'r').read())
        except:
            # this could happen on windows if the program in question
            # is a batch file...
            self._script_status = 0

        self._output_file = open(os.path.join(self._working_directory,
                                              '%s.xout' % self._script_name),
                                 'r')

        return

    def kill(self):
        '''This is meaningless...'''

        pass

    
