#
#     Copyright (C) 2013 David Waterman
#
#     This code is distributed under the terms and conditions of the
#     CCP4 Program Suite Licence Agreement as a CCP4 Application.
#     A copy of the CCP4 licence can be obtained by writing to the
#     CCP4 Secretary, Daresbury Laboratory, Warrington WA4 4AD, UK.
#
"""Initialisation for the CCP4Dispatchers package"""

import os, string

envlist = [('CCP4I_TCLTK', '/public2/ftp/pub/ccp4/6.5/ccp4-6.5/bin'), ('CCP4_HELPDIR', '/public2/ftp/pub/ccp4/6.5/ccp4-6.5/help/'), ('MANPATH', '/public2/ftp/pub/ccp4/6.5/ccp4-6.5/share/man:/public2/ftp/pub/ccp4/6.5/ccp4-6.5/share/man'), ('CHTML', '/public2/ftp/pub/ccp4/6.5/ccp4-6.5/html'), ('GFORTRAN_UNBUFFERED_PRECONNECTED', 'Y'), ('CCP4', '/public2/ftp/pub/ccp4/6.5/ccp4-6.5'), ('CLIB', '/public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib'), ('CEXAM', '/public2/ftp/pub/ccp4/6.5/ccp4-6.5/examples'), ('CCP4I_TOP', '/public2/ftp/pub/ccp4/6.5/ccp4-6.5/share/ccp4i'), ('PATH', '/public2/ftp/pub/ccp4/6.5/ccp4-6.5/etc:/public2/ftp/pub/ccp4/6.5/ccp4-6.5/bin:/public2/ftp/pub/ccp4/6.5/ccp4-6.5/share/xia2/Applications:/public2/ftp/pub/ccp4/6.5/ccp4-6.5/etc:/public2/ftp/pub/ccp4/6.5/ccp4-6.5/bin:/public2/ftp/pub/ccp4/6.5/ccp4-6.5/share/xia2/Applications:/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/levedev/bin'), ('CCP4_OPEN', 'UNKNOWN'), ('CETC', '/public2/ftp/pub/ccp4/6.5/ccp4-6.5/etc'), ('CLIBD_MON', '/public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/data/monomers/'), ('CCP4_SCR', '/tmp/lvi05883'), ('SHLVL', '1'), ('CRANK', '/public2/ftp/pub/ccp4/6.5/ccp4-6.5/share/ccp4i/crank'), ('CLIBD', '/public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/data'), ('CBIN', '/public2/ftp/pub/ccp4/6.5/ccp4-6.5/bin'), ('CINCL', '/public2/ftp/pub/ccp4/6.5/ccp4-6.5/include'), ('CCP4_MASTER', '/public2/ftp/pub/ccp4/6.5'), ('MMCIFDIC', '/public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/ccp4/cif_mmdic.lib')]

prog_to_dispatcher = {'mapdiff': 'mapdiff', 'mat2symop': 'mat2symop', 'stnet': 'stnet', 'prosmart': 'prosmart', 'angles': 'angles', 'ccp4um': 'ccp4um', 'distang': 'distang', 'fft': 'fft', 'phistats': 'phistats', 'pdbcur': 'pdbcur', 'ecalc': 'ecalc', 'cfft': 'cfft', 'zeroed': 'zeroed', 'axissearch': 'axissearch', 'phaser.ensembler': 'phaser_ensembler', 'mini-rsr': 'mini-rsr', 'afro': 'afro', 'cmapcoeff': 'cmapcoeff', 'crunch2': 'crunch2', 'mtztona4': 'mtztona4', 'ccp4i_condorsub': 'ccp4i_condorsub', 'rebatch': 'rebatch', 'pdb_pack': 'pdb_pack', 'domain2chain': 'domain2chain', 'fsearch': 'fsearch', 'get_heavy': 'get_heavy', 'bp3': 'bp3', 'makedict': 'makedict', 'extends': 'extends', 'make-shelx-restraints': 'make-shelx-restraints', 'hklplot': 'hklplot', 'findligand-real': 'findligand-real', 'density-score-by-residue': 'density-score-by-residue', 'getax': 'getax', 'dmmulti': 'dmmulti', 'sc': 'sc', 'detwin': 'detwin', 'prelyscar_ccp4.pl': 'prelyscar_ccp4_pl', 'tclsh8.4': 'tclsh8_4', 'refmac5': 'refmac5', 'density-score-by-residue-real': 'density-score-by-residue-real', 'secstr': 'secstr', 'ample': 'ample', 'coot': 'coot', 'chooch': 'chooch', 'vectors': 'vectors', 'xplot84driver': 'xplot84driver', 'freerflag': 'freerflag', 'ffjoin': 'ffjoin', 'fix-nomenclature-errors': 'fix-nomenclature-errors', 'worms': 'worms', 'prosmart_align': 'prosmart_align', 'chainsaw': 'chainsaw', 'balls': 'balls', 'sapi': 'sapi', 'get-residue-stats.pl': 'get-residue-stats_pl', 'cif2mtz': 'cif2mtz', 'f2cif': 'f2cif', 'align_DB': 'align_DB', 'create_docs': 'create_docs', 'cphasecombine': 'cphasecombine', 'stereo3d': 'stereo3d', 'cctbx.python': 'cctbx_python', 'get_trans': 'get_trans', 'f2mtz': 'f2mtz', 'geomcalc': 'geomcalc', 'almn': 'almn', 'buccaneer_pipeline': 'buccaneer_pipeline', 'rapper': 'rapper', 'gensym': 'gensym', 'bltsh24': 'bltsh24', 'mtz2sca': 'mtz2sca', 'feckless': 'feckless', 'astex_viewer': 'astex_viewer', 'mapro': 'mapro', 'wish': 'wish', 'shelx2map': 'shelx2map', 'rmsdev': 'rmsdev', 'compare-dictionaries': 'compare-dictionaries', 'rings3d': 'rings3d', 'p842asc': 'p842asc', 'cprodrg': 'cprodrg', 'mapmask': 'mapmask', 'find-blobs': 'find-blobs', 'findwaters': 'findwaters', 'professs': 'professs', 'mtzdiff': 'mtzdiff', 'hbond': 'hbond', 'cross_validate': 'cross_validate', 'rotamer': 'rotamer', 'sortwater': 'sortwater', 'sfcheck': 'sfcheck', 'ccp4iwish': 'ccp4iwish', 'chef': 'chef', 'pmf': 'pmf', 'multicomb': 'multicomb', 'doser': 'doser', 'zanuda': 'zanuda', 'cphasematch': 'cphasematch', 'check_cell_sg': 'check_cell_sg', 'ribbon': 'ribbon', 'vecref': 'vecref', 'binsort': 'binsort', 'rwcontents': 'rwcontents', 'alt_sg_list': 'alt_sg_list', 'cifdic_to_symtab': 'cifdic_to_symtab', 'cif2xml': 'cif2xml', 'loggraph': 'loggraph', 'compar': 'compar', 'scala': 'scala', 'icoefl': 'icoefl', 'pointless': 'pointless', 'symop2mat': 'symop2mat', 'mtzfix': 'mtzfix', 'pdb2s': 'pdb2s', 'cmaplocal': 'cmaplocal', 'abs': 'abs', 'dtrek2scala': 'dtrek2scala', 'csigmaa': 'csigmaa', 'refindex': 'refindex', 'sortmtz': 'sortmtz', 'JLogGraph.jar': 'JLogGraph_jar', 'ncont': 'ncont', 'phaser.sculptor': 'phaser_sculptor', 'stgrid': 'stgrid', 'add_heavy': 'add_heavy', 'qtrview': 'qtrview', 'mapdump': 'mapdump', 'cnautilus': 'cnautilus', 'cmapcut': 'cmapcut', 'solution_check': 'solution_check', 'ctruncate': 'ctruncate', 'automask': 'automask', 'mapreplace': 'mapreplace', 'gesamt': 'gesamt', 'mapsig': 'mapsig', 'theseus': 'theseus', 'check_zero_res.py': 'check_zero_res_py', 'pyrogen': 'pyrogen', 'acorn': 'acorn', 'amore': 'amore', 'cavenv': 'cavenv', 'map2fs': 'map2fs', 'del_heavy': 'del_heavy', 'save_seg_id': 'save_seg_id', 'pplot': 'pplot', 'unique': 'unique', 'rastep': 'rastep', 'ccp4mg': 'ccp4mg', 'watncs': 'watncs', 'mapexchange': 'mapexchange', 'percent-rank.pl': 'percent-rank_pl', 'proclean': 'proclean', 'csloop': 'csloop', 'mtz2hkl': 'mtz2hkl', 'mtzinfo': 'mtzinfo', 'mtz2various': 'mtz2various', 'tracer': 'tracer', 'na4tomtz': 'na4tomtz', 'topdraw': 'topdraw', 'scalepack2mtz': 'scalepack2mtz', 'maptona4': 'maptona4', 'act': 'act', 'cad': 'cad', 'fhscal': 'fhscal', 'revise': 'revise', 'othercell': 'othercell', 'bltwish': 'bltwish', 'dm': 'dm', 'sftools': 'sftools', 'toplist': 'toplist', 'render': 'render', 'sfall': 'sfall', 'pdbset': 'pdbset', 'rotgen': 'rotgen', 'bltsh': 'bltsh', 'superpose': 'superpose', 'comit': 'comit', 'balbes': 'balbes', 'phaser': 'phaser', 'asc2p84': 'asc2p84', 'overlapmap': 'overlapmap', 'tlsextract': 'tlsextract', 'dyndom': 'dyndom', 'areaimol': 'areaimol', 'prep_bulk': 'prep_bulk', 'truncate': 'truncate', 'molrep': 'molrep', 'lidia': 'lidia', 'ccp4-python': 'ccp4-python', 'hklview': 'hklview', 'jligand': 'jligand', 'pltdev': 'pltdev', 'mplot': 'mplot', 'znd_subs': 'znd_subs', 'tlsanl': 'tlsanl', 'reforigin': 'reforigin', 'cmodeltoseq': 'cmodeltoseq', 'postref': 'postref', 'mrbump': 'mrbump', 'viewhkl': 'viewhkl', 'cncsfrommodel': 'cncsfrommodel', 'pdb_extract': 'pdb_extract', 'pisa': 'pisa', 'anisoanl': 'anisoanl', 'hgen': 'hgen', 'cinvfft': 'cinvfft', 'watertidy': 'watertidy', 'polarrfn': 'polarrfn', 'mtzmnf': 'mtzmnf', 'baverage': 'baverage', 'havecs': 'havecs', 'anglen': 'anglen', 'symfit': 'symfit', 'peakmax': 'peakmax', 'difres': 'difres', 'csfcalc': 'csfcalc', 'crank': 'crank', 'rstats': 'rstats', 'chltofom': 'chltofom', 'vecsum': 'vecsum', 'symconv': 'symconv', 'extract': 'extract', 'mtz2cif': 'mtz2cif', 'iotbx.lattice_symmetry': 'iotbx_lattice_symmetry', 'bfactan': 'bfactan', 'check_file_DB': 'check_file_DB', 'coordconv': 'coordconv', 'scaleit': 'scaleit', 'avs2ps': 'avs2ps', 'ccp4_pipeline_simple': 'ccp4_pipeline_simple', 'pdb_extract_sf': 'pdb_extract_sf', 'diff2jpeg': 'diff2jpeg', 'mkdssp': 'mkdssp', 'crossec': 'crossec', 'matthews_coef': 'matthews_coef', 'imosflm': 'imosflm', 'logview': 'logview', 'nautilus_pipeline': 'nautilus_pipeline', 'pdbdiff': 'pdbdiff', 'cmtzsplit': 'cmtzsplit', 'cecalc': 'cecalc', 'ncsmask': 'ncsmask', 'privateer-validate': 'privateer-validate', 'csymmatch': 'csymmatch', 'cbuccaneer': 'cbuccaneer', 'normal3d': 'normal3d', 'solomon': 'solomon', 'convert2mtz': 'convert2mtz', 'bones2pdb': 'bones2pdb', 'omit': 'omit', 'lsqkab': 'lsqkab', 'cpirate': 'cpirate', 'spicker': 'spicker', 'surface': 'surface', 'csequins': 'csequins', 'sigmaa': 'sigmaa', 'printpeaks': 'printpeaks', 'prosmart_restrain': 'prosmart_restrain', 'bulking': 'bulking', 'fffear': 'fffear', 'idiffdisp': 'idiffdisp', 'ccp4i': 'ccp4i', 'acedrg': 'acedrg', 'rods': 'rods', 'OpenAstexViewer.jar': 'OpenAstexViewer_jar', 'search_DB': 'search_DB', 'qtpisa': 'qtpisa', 'dtrek2mtz': 'dtrek2mtz', 'rotmat': 'rotmat', 'wilson': 'wilson', 'maprot': 'maprot', 'mtzMADmod': 'mtzMADmod', 'mtzdump': 'mtzdump', 'ipmosflm': 'ipmosflm', 'dimple': 'dimple', 'nb': 'nb', 'cpatterson': 'cpatterson', 'rantan': 'rantan', 'bltwish24': 'bltwish24', 'diffdump': 'diffdump', 'oasis': 'oasis', 'cparrot': 'cparrot', 'mtzutils': 'mtzutils', 'gcx': 'gcx', 'findligand': 'findligand', 'pdb2to3': 'pdb2to3', 'tffc': 'tffc', 'npo': 'npo', 'libcheck': 'libcheck', 'rfcorr': 'rfcorr', 'combat': 'combat', 'tplot': 'tplot', 'watpeak': 'watpeak', 'libg': 'libg', 'gfac2pdb': 'gfac2pdb', 'seqwt': 'seqwt', 'tclsh': 'tclsh', 'findncs': 'findncs', 'r500ccp4': 'r500ccp4', 'get_structure_DB': 'get_structure_DB', 'mapslicer': 'mapslicer', 'pdb_merge': 'pdb_merge', 'cmakereference': 'cmakereference', 'get_chain': 'get_chain', 'helixang': 'helixang', 'wish8.4': 'wish8_4', 'r500': 'r500', 'mama2ccp4': 'mama2ccp4', 'reindex': 'reindex', 'caniso': 'caniso', 'volume': 'volume', 'stereo': 'stereo', 'aimless': 'aimless', 'mlphare': 'mlphare', 'pdbhtf': 'pdbhtf', 'cmtzjoin': 'cmtzjoin', 'topp': 'topp', 'ccp4ish': 'ccp4ish', 'contact': 'contact', 'probplot': 'probplot', 'edstats': 'edstats', 'edstats.pl': 'edstats_pl', 'findwaters-real': 'findwaters-real', 'blend': 'blend', 'rsps': 'rsps', 'coord_format': 'coord_format'}

def dispatcher_builder(program, cmd_args = None, keywords = None,
                       capture_streams = True, stdout = None, stderr = None):
    """Convenience factory function to set up and return a dispatcher in one
    line, using the original program name"""

    try:
        modulename = prog_to_dispatcher[program]
    except KeyError:
        msg = program + " is not found in the mapping to dispatchers"
        raise KeyError, msg

    _temp = __import__(modulename, globals(), locals(), ["Dispatcher"], -1)
    Dispatch = _temp.Dispatcher(capture_streams, stdout, stderr)

    if cmd_args: Dispatch.set_cmd_args(cmd_args)
    if keywords: Dispatch.set_keywords(keywords)

    return Dispatch

def call_here(program, key, cmdline, workingDIR, function=""):
    """Convenience function to set up and call a dispatcher in one line,
    writing output to files, principally for MrBump"""

    logfile = os.path.join(workingDIR, "%s%s.log" % (program, function))
    errfile = os.path.join(workingDIR, "%s%s.err" % (program, function))

    # Generate a shell script for this job
    if os.name != "nt":
        scriptfile = os.path.join(workingDIR, "%s%s.script" % (program, function))
        s = open(scriptfile,"w")
        s.write("#!/bin/sh\n")
        s.write(program + " " + cmdline + " <<eof\n")
        s.write(key)
        s.write("eof\n")
        s.close()

    # Import Dispatcher from the program name (must remove '.exe' on Windows)
    Dispatch = dispatcher_builder(program, cmdline, key)
    Dispatch.call()

    # Write out the stdout to the log file
    log = open(logfile, "w")
    for line in Dispatch.stdout_data:
        log.write(line + "\n")
    log.close()

    # Write out the stderr to the error file
    err=open(errfile, "w")
    for line in Dispatch.stderr_data:
       err.write(line + "\n")
    err.close()

    return Dispatch

def set_environment():
    """Function to set the environment variables"""

    # Read current environment in order to do any dynamic substitutions required
    env_var_dict = os.environ.copy()

    # Set specified environment variables
    for (var, val) in envlist:

        val_template = string.Template(val)
        val_sub = val_template.safe_substitute(env_var_dict)

        # Remove any remaining $IDENTIFIERS, to behave like bash does.
        val = val_template.pattern.sub("",val_sub)
        os.environ[var]= val

    # Find the path to the CCP4Dispatcher package
    pkg_path = os.path.dirname(os.path.realpath(__file__))

    # Prepend dispatcher package to the PATH, if not included already
    try:
        curr_path = os.environ["PATH"]
    except KeyError:
        curr_path = ""
    if not pkg_path in curr_path:
        os.environ["PATH"] = (pkg_path + os.pathsep + curr_path)

    # Prepend dispatcher package to PYTHONPATH, if not included already
    try:
        curr_pythonpath = os.environ["PYTHONPATH"]
    except KeyError:
        curr_pythonpath = ""
    pkg_parent = os.path.dirname(pkg_path)
    if not pkg_parent in curr_pythonpath:
        os.environ["PYTHONPATH"] = (pkg_parent + os.pathsep + curr_pythonpath)

