#!/usr/bin/python
import os,sys,shutil
from program import program
import common

class shelxe(program):
  name="SHELXE"
  binary="shelxe"
  modif='-'
  arg_divided=False
  never_merge=True
  stat={}
  stat['cycle'] = common.stats(name='cycle', regexp=r"dens.mod.\s+cycle\s+(\d+)")
  stat['contrast'] = common.stats(name='contrast',
                                  regexp=r"<wt>\s+=\s+\S+,\s+Contrast\s+=\s+(\S+?)\,")
  stat['connect'] = common.stats(name='connectivity',
                                 regexp=r"<wt>\s+=\s+\S+,\s+Contrast\s+=\s+\S+?\,\s+Connect.\s+=\s+(\S+)")
  stat['res_built'] = common.stats(name='number of residues built', regexp=r"\s+(\d+)\s+residues left after pruning")
  stat['cc'] = common.stats(name='correlation coefficient after building',
                            regexp=r'CC for partial structure against native data =\s+(\S+)\s*\%')
  stat['best_cc'] = common.stats(name='best correlation coefficient after building', 
                                 regexp=r'Best trace \(cycle\s+\S+\s+with CC\s+(\S+)\%\)')
  stat['untraceable'] = common.stats(name='unable to trace the map', regexp=r'(Unable to trace map)', accept_none=True)
  references = ( "Sheldrick GM (2010) Experimental phasing with SHELXC/D/E:" +
                 " combining chain tracing with density modification.  Acta Cryst. D66, 479-485.", )


  def Interact_output(self, line, popen, empty):
    self.process.UpdateInfo(line,self)

  def TreatInput(self):
    # we only support cases when experimental phase information is available with either substructure or MR model
    # the res file seems compulsory for the experimental phasing from scratch... a pdb->res convertor might be useful?
    self.res=self.inp.Get('model', typ='substr', filetype='res')
    if self.res:
      if self.res.GetFileName('res').endswith('.res'):
        self.project_fa=self.res.GetFileName('res')[:-4]
      else:
        self.project_fa=self.res.GetFileName('res')
        shutil.copy(self.project_fa, self.project_fa+'.res')
        self.res.GetFile('res').name+='.res'
    # SAD after MR case
    else:
      self.pdb=self.inp.Get('model', typ=('partial','partial+substr'), filetype='pdb')
      if self.pdb:
        if self.pdb.GetFileName('pdb').endswith('.pda'):
          self.project=self.pdb.GetFileName('pdb')[:-4]
        else:
          self.project=self.pdb.GetFileName('pdb')
          shutil.copy(self.project, self.project+'.pda')
          self.pdb.GetFile('pdb').name+='.pda'
    if not self.res and not self.pdb:
      common.Error('Neither substructure model (in .res) nor partial model (in .pda) inputted to {0}'.format(self.name))
    # fnat can be either inputted as an object or at least the corresponding filename must exist
    fnat=self.inp.Get('fsigf', typ='average', filetype='hkl', try_convert=False)
    if fnat:
      self.project = fnat.GetFileName('hkl')[:-4]
    else:
      if os.path.isfile(self.project_fa[:-3]+'.hkl'):
        self.project = self.project_fa[:-3]
      else:
        fnat=self.inp.Get('fsigf', typ='average', filetype='hkl')
        if not fnat:
          common.Error('F/SIGF (native) not inputted to {0}'.format(self.name))
    # fa can be either inputted as an object or at least the corresponding filename must exist
    fa=self.inp.Get('fsigf', typ='fa', filetype='hkl', try_convert=False)
    if not fa and not os.path.isfile(self.project_fa+'.hkl'):
      fa=self.inp.Get('fsigf', typ='average', filetype='hkl')
      if not fa:
        common.Error('FA values not inputted to {0}'.format(self.name))
    if fa and os.path.realpath(self.fa.GetFileName('hkl')) != os.path.realpath(self.project_fa+'.hkl'):
      shutil.copy(fa.GetFileName('hkl'), self.project_fa+'.hkl')
      fa.GetFile('hkl').name+='.hkl'
    ins=self.inp.Get('datafile', filetype='ins')
    # ins can be either inputted as an object or at least the corresponding filename must exist
    if not ins and not os.path.isfile(self.project_fa+'.ins'):
      common.Error('.ins file not inputted to {0}'.format(self.name))
    if ins and os.path.realpath(ins.GetFileName('ins')) != os.path.realpath(self.project_fa+'.ins'):
      shutil.copy(ins.GetFileName('ins'), self.project_fa+'.ins')
      ins.GetFile('ins').name+='.ins'
    # we need to do the relative path manually here as such a file does not exist...
    self.project_path = os.path.relpath(self.project, self.rundir)
    self.project_path_fa = os.path.relpath(self.project_fa, self.rundir)
    self.SetArg( self.project_path, ignore_modif=True )
    self.SetArg( self.project_path_fa, ignore_modif=True )


  def TreatParams(self):
    if self.process.GetParam('solvent_content') and not self.IsArg('s'):
      self.SetArg('s', self.process.GetParam('solvent_content'))
    if self.process.GetParam('dmcyc') and not self.IsArg('m'):
      self.SetArg('m', self.process.GetParam('dmcyc'))
    if self.process.GetParam('bigcyc') and not self.IsArg('a'):
      self.SetArg('a', self.process.GetParam('bigcyc'))
    if self.process.nick=='phdmmb' and not self.IsArg('a'):
      self.SetArg('a')
    program.TreatParams(self)


  def DefineOutput(self):
    out_path = self.project_path
    if self.GetArg('i'):
      out_path += '_i'
    self.out.AddNew('mapcoef', out_path+'.phs', filetype='phs', typ='best')
    self.out.AddNew('model', out_path+'.hat', filetype='hat', typ='substr')
    if self.IsArg('a'):
      self.out.AddNew('model', out_path+'.pdb', typ='partial', filetype='pdb')
    # this is just a very bad hack: we take the input substr. pdb as output instead of the refined one!
    # this code *must* be removed - as soon as a hat->pdb convertor is implemented in crank2.
    pdbin = self.inp.Get('model',typ='substr',filetype='pdb')
    if pdbin:
      self.out.AddCopy(pdbin)
