#!/usr/bin/env python
# XDSConv.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.
#
# A wrapper to run xdsconv
#

import os
import sys
import shutil

if not os.environ.has_key('XIA2CORE_ROOT'):
    raise RuntimeError, 'XIA2CORE_ROOT not defined'

if not os.environ.has_key('XIA2_ROOT'):
    raise RuntimeError, 'XIA2_ROOT not defined'

if not os.path.join(os.environ['XIA2CORE_ROOT'],
                    'Python') in sys.path:
    sys.path.append(os.path.join(os.environ['XIA2CORE_ROOT'],
                                 'Python'))
    
if not os.environ['XIA2_ROOT'] in sys.path:
    sys.path.append(os.environ['XIA2_ROOT'])

from Driver.DriverFactory import DriverFactory
from Handlers.Streams import Debug

def XDSConv(DriverType = None):

    DriverInstance = DriverFactory.Driver(DriverType)

    class XDSConvWrapper(DriverInstance.__class__):
        '''A wrapper for wrapping XDSCONV.'''

        def __init__(self):
            DriverInstance.__class__.__init__(self)
            self.set_executable('xdsconv')

            self._input_file = None
            self._cell = None
            self._symmetry = None
            self._output_file = None

            return

        def set_input_file(self, input_file):
            self._input_file = input_file
            return

        def set_cell(self, cell):
            self._cell = cell
            return

        def get_cell(self):
            return self._cell

        def get_symmetry(self):
            return self._symmetry

        def set_symmetry(self, symmetry):
            self._symmetry = symmetry
            return

        def set_output_file(self, output_file):
            self._output_file = output_file
            return

        def parse_xds_ascii(self, file):
            '''Parse the XDS ascii file for interesting things.'''

            results = { } 

            for line in open(file, 'r').readlines():
                if not line[0] == '!':
                    break

                if '!FORMAT' in line:
                    tokens = line.split()
                    for t in tokens:
                        if 'MERGED' in t:
                            if t.split('=')[-1].lower() == 'false':
                                raise RuntimeError, 'input unmerged'
                        if 'FRIEDEL' in t:
                            results['friedel'] = t.split('=')[-1].lower()

                if '!UNIT_CELL_CONSTANTS' in line:
                    results['cell'] = tuple(map(float,
                                                line.split()[1:]))

                if '!INCLUDE_RESOLUTION' in line:
                    results['resolution_range'] = map(float,
                                                      line.split()[1:])

                if '!SPACE_GROUP' in line:
                    results['spacegroup'] = int(line.split()[-1])

            return results

        def convert(self):
            if not self._input_file:
                raise RuntimeError, 'no input file specified'

            if not self._output_file:
                raise RuntimeError, 'no output file specified'

            # make the output file link a relative rather than
            # absolute path... FIXME this is unix specific!
            if self.get_working_directory() in self._output_file:
                self._output_file = self._output_file.replace(
                    self.get_working_directory(), './')

            # perhaps move input file to CWD

            if len(self._input_file) > 49:
                if len(os.path.split(self._input_file)[-1]) > 49:
                    raise RuntimeError, 'input file name too long'
                
                shutil.copyfile(
                    self._input_file,
                    os.path.join(self.get_working_directory(),
                                 os.path.split(self._input_file)[-1]))
                
                self._input_file = os.path.split(self._input_file)[-1]

            header = self.parse_xds_ascii(self._input_file)

            if not self._cell:
                self._cell = header['cell']

            if not self._symmetry:
                self._symmetry = header['spacegroup']

            if header.has_key('resolution_range'):
                self._resolution = header['resolution_range']
            else:
                self._resolution = [100.0, 0.1]
            self._resolution.sort()
            self._resolution.reverse()

            inp = open(os.path.join(
                self.get_working_directory(), 'XDSCONV.INP'), 'w')

            inp.write('SPACE_GROUP_NUMBER=%d\n' % self._symmetry)

            inp.write(
                'UNIT_CELL_CONSTANTS= %.2f %.2f %.2f %.2f %.2f %.2f\n' % \
                self._cell)

            inp.write('INPUT_FILE=%s XDS_ASCII %.2f %.2f\n' % \
                      (self._input_file, self._resolution[0],
                       self._resolution[1]))

            inp.write('OUTPUT_FILE=%s IALL FRIEDEL\'S_LAW=%s\n' % \
                      (self._output_file, header['friedel'].upper()))

            inp.close()

            self.start()
            self.close_wait()

            # should really parse the output

            return

    return XDSConvWrapper()

# need to add a test here...
