"""
     python/ui/history.py: CCP4MG Molecular Graphics Program
     Copyright (C) 2001-2008 University of York, CCLRC
     Copyright (C) 2009-2011 University of York
     Copyright (C) 2012 STFC

     This library is free software: you can redistribute it and/or
     modify it under the terms of the GNU Lesser General Public License
     version 3, modified in accordance with the provisions of the 
     license to address the requirements of UK law.
 
     You should have received a copy of the modified GNU Lesser General 
     Public License along with this library.  If not, copies may be 
     downloaded from http://www.ccp4.ac.uk/ccp4license.php
 
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU Lesser General Public License for more details.
"""

import sys
import os
from PyQt4 import QtCore
from global_definitions import *
import hashlib
import itertools
import utils

def _unpickle_enum(arg1,arg2,arg3):
        import sip
	if arg1 == "PyQt4.QtCore":
		if arg2.find("Qt.") == 0:
			# Try with and with "Qt." module prepend
			try:
				arg2_new = arg2[3:]
				err = sip._unpickle_enum(arg1,arg2_new,arg3)
				return err
			except:
				return sip._unpickle_enum(arg1,arg2,arg3)
	return sip._unpickle_enum(arg1,arg2,arg3)
	

import pickle
class QtUnpickler(pickle.Unpickler):
    def __init__(self, file):
        pickle.Unpickler.__init__(self, file)
        import loadPlugins
        loadPlugins.setPluginsPath()
    def load_global(self):
        module = self.readline()[:-1]
        name = self.readline()[:-1]
        if module == "sip" and name == "_unpickle_enum":
           module = __name__
        klass = self.find_class(module, name)
        self.append(klass)
    pickle.Unpickler.dispatch[pickle.GLOBAL] = load_global

class CHistory(QtCore.QObject):
  insts = ''
  pluginsStatusChanged = QtCore.pyqtSignal()
  
#-------------------------------------------------------------------------  
  def __init__(self):
#-------------------------------------------------------------------------
    QtCore.QObject.__init__(self)
    CHistory.insts = self
    self.command_list = []
    self.n_commands = 0
    #handle recording
    self.recording_start = ''

    #handle_replay
    self.replay_comlist = []
    self.stepwise_replay_on = 0
    self.replay_line = -1
    self.selected_lines = []
    self.block_gui = 0

    # Editing the replay file
    self.insert_action = 0
    self.replay_file = ''

    #Debug handling
    self.diagnostic = {
      'command': 0,
      'opengl':0,
      'timing':0,
      'framerate':0 }

    self.test_ports = [8800,8820]
    self.master_ports = []
    self.save_to_project = ['view','COLOUR','data','applications']

    self.nAutoSaved = 0
    self.autoSavedStatus = []
    self.autoSavedPosition = 0
    self.update_gui = []
    self.autoSaveTimeFormat = '%a-%d-%b-%y-%H-%M'
    self.maxAutoSaved = 100   # Maximum number of status saved in memory
    self.delAutoSaved = 20    # Number of status deleted when reach maxAutoSaved
    self.diskAutoSaveFrequency = 0  # Fequency of saving status to disk (0 = no save)


    self.plugin_status = {}


  def GetSavedPluginStatus(self,name):
    pars = {}
    if  self.plugin_status.has_key(name):
      for key,value in self.plugin_status[name].items():
        pars[key] = value
    #print 'GetSavedPluginStatus',name,pars
    return pars

  def SavePluginStatus(self,name,params):
    self.plugin_status[name] = {}
    for key,value in params.items():
      self.plugin_status[name][key] = value
    #print 'SavePluginStatus',name,self.plugin_status[name]

#-----------------------------------------------------------------------
  def set_attribute(self,selected_lines='',**keywords):
#-----------------------------------------------------------------------
    #print "CHistory selected lines",selected_lines
    import re,string
    self.selected_lines = []
    sel_lines = selected_lines
    re.sub(r'\{','',sel_lines)
    re.sub(r'\}','',sel_lines)
    sel_lines = string.split(sel_lines)
    for ll in sel_lines:
      try:
        self.selected_lines.append(int(ll))
      except:
        pass
    #print "  self.selected_lines",self.selected_lines
    if len(self.selected_lines) == 0:
      mode = 'disabled'
    else:
      mode = 'normal'
    self.update_button_status(go_to_line=mode)
    self.update_button_status(delete_line=mode)
    self.update_button_status(save_lines=mode)
          
        

  def restore_params(self,restore_mode=''):
    if hasattr(self,restore_mode):
      return  getattr(self,restore_mode)
    else:
      import os
      params = {}
      filename = os.path.join (utils.get_CCP4MG(),'status', \
                             'last_exit_status.pkl')

      if os.path.exists(filename):
        status = self.load_pickle_file(filename=filename)
        if status.has_key(restore_mode):
          params.update(status[restore_mode])
      return params
      
#-----------------------------------------------------------------------
  def save_program_status (self,save_visible=0,**keywords):
#-----------------------------------------------------------------------
    import os
    save_visible = int(save_visible)
    current_project = CCP4DATABASE().get_current_project()
    filename = os.path.join (utils.get_CCP4MG(),'status', \
                             'last_exit_status.pkl')
    if os.path.exists(filename):
      bakname =  os.path.join (utils.get_CCP4MG(),'status', \
                             'prev_exit_status.pkl')
      if os.path.exists(bakname): os.remove(bakname)  
      os.rename(filename,bakname)
    self.save_status(filename=filename,overwrite='overwrite',save_visible=save_visible)

    if PM('save_session_options').get('save_projects') and current_project :
      filename = utils.get_filename( current_project , \
                 os.path.join('CCP4_DATABASE','mg_exit_status.pkl')) 
      #print "save_projects",filename
      #if os.path.exists(filename):
      #  bakname =  utils.get_filename( current_project , \
      #           os.path.join('CCP4_DATABASE','mg_prev_exit_status.pkl'))
      #  if os.path.exists(bakname): os.remove(bakname)  
      #  os.rename(filename,bakname)
      self.save_status(filename=filename,overwrite='overwrite', \
         save_list = self.save_to_project)
    
           
#-----------------------------------------------------------------------
  def check_data_valid_last_program_status (self,**keywords):
#-----------------------------------------------------------------------
    '''
    Check we can restore status from past/prev exit status
    '''
    import os

    filename = os.path.join (utils.get_CCP4MG(),'status','last_exit_status.pkl')
    if os.path.exists(filename):
      last_status = self.check_status_file(filename=filename)
      if last_status:
        return True

    """
    filename = os.path.join (utils.get_CCP4MG(),'status','prev_exit_status.pkl')
    if os.path.exists(filename):
      prev_status = self.check_status_file(filename=filename)
      if prev_status:
        return True
    """

    return False

#-----------------------------------------------------------------------
  def restore_program_status (self,restore_past_or_prev=True,**keywords):
#-----------------------------------------------------------------------
    '''
    Restore status from saved exit status
    '''
    import os

    # If project was set on the command line now is the time to
    # update the current_project in ccp4i
    if hasattr(self,'command_line_project'):
      CCP4DATABASE().set_current_project(self.command_line_project)
      del self.command_line_project
    

    if self.command_line_status:
      if not os.path.exists( self.command_line_status ):
        MGGUI().WarningMessage ("ERROR status file not found: "+ \
                            self.command_line_status)
        print "ERROR status file not found:", self.command_line_status
        
      else:
        status = self.restore_status(filename=self.command_line_status,
                        restore_data=self.command_line_restore)
        if not status:
          return 0
        else:
          MGGUI().WarningMessage ("ERROR reading status file: "+
                            self.command_line_status)
          print "ERROR reading status file: ", self.command_line_status
          

          
    # Should we be loading some data from a project specific file?
    project_filename = ''
    exclude_list = []
    if PM('save_session_options').get('save_projects'):
      project_filename = utils.get_filename(CCP4DATABASE().get_current_project(),os.path.join('CCP4_DATABASE','mg_exit_status.pkl'))
      if os.path.exists(project_filename):
        print "Restoring_program status for current project:",CCP4DATABASE().get_current_project()
        exclude_list = self.save_to_project
      else:
        project_filename = ''

    # Load the generic data
    filename = os.path.join (utils.get_CCP4MG(),'status', \
                             'last_exit_status.pkl')

    if os.path.exists(filename) and restore_past_or_prev:
      
      last_status = self.restore_status(filename=filename,
         restore_data=self.command_line_restore,exclude_list=exclude_list)
    elif os.path.exists(filename):
      last_status = self.restore_status(filename=filename,
         restore_data=0,exclude_list=exclude_list)
    else:
      print "ERROR no status file",filename
      last_status = 2

    if last_status == 1:
      MGGUI().WarningMessage ("Error restoring status from file\n"+
                 "May be due to change in format for new program version\n"+
                 "or previous program run crashed on exit?\n" +
                 "Will delete last save status and attempt to restore\n"+
                                "from previous status file")
      try:
        os.remove(filename)
      except:
        MGGUI().WarningMessage(
            "Error attempting to delete unreadable status file\n"+
             filename+"\nPlease remove this file")

      # Either no 'last' status file or failed to read it - so try for a
      # previous
      filename = os.path.join (utils.get_CCP4MG(),'status', 'prev_exit_status.pkl')
      if os.path.exists(filename) and restore_past_or_prev:
        prev_status = self.restore_status(filename=filename,restore_data=-1,
                                     exclude_list=exclude_list )
      elif os.path.exists(filename):
        prev_status = self.restore_status(filename=filename,restore_data=0,
                                     exclude_list=exclude_list )
      else:
        prev_status = 1

      # Do not report error if last_exit_status does not exists
      if prev_status and last_status != 2:
        MGGUI().WarningMessage ("Error restoring status from previous file\n"+
          "will revert to default program setup")
        try:
          if os.path.exists(filename): os.remove(filename)
        except:
          MGGUI().WarningMessage( \
           "Error attempting to delete unreadable status file\n"+
            filename+"\nPlease remove this file")

    if project_filename:
      self.restore_status(filename=project_filename,restore_data=-1)

     

#-----------------------------------------------------------------------
  def do_backup_data_files ( self,dir='',project='' ):
#-----------------------------------------------------------------------
    import shutil
    import dataobj

    if not dir:
      # Make an empty directory .CCP4MG/saved_data_files
      dir = os.path.join( utils.get_CCP4MG(),'saved_data_files' )
      # Delete the default backup directory - don't risk trying to delete
      # anything else
      if os.path.exists(dir): shutil.rmtree(dir)
    if not os.path.exists(dir):
      try:
        os.mkdir(dir)
      except:
        return (1,'Error creating directory'+dir)

    # Copy all data files to this directory
    errors = ''
    for obj in dataobj.get_dataobj():
      ret = obj.copy_data_files(dir=dir,project=project,overwrite=1)
      #print "copy_data_files ret",obj,ret
      if ret[0]:errors = errors + '\n'+ret[1][0]
    return
    if errors:
      return [1,errors]
    else:
      return [0,'']
          
    

#-----------------------------------------------------------------------
  def save_status(self,filename='',DIR_filename='',overwrite='Overwrite',
                  save_list=[],save_visible=0,copy_to_dir='',**keywords):
#-----------------------------------------------------------------------
    import dataobj
    import services
    import pickle
    import build
    
    #print "history.save_status",filename
    diagnostic = 0

    if filename:
      if DIR_filename:
        filename = utils.get_filename(DIR_filename,filename)
      f = utils.openFile(filename,'w',overwrite=overwrite)
      if not f: return 1
    else:
      f = 0

    save_visible = int(save_visible)
    #print "save_status save_visible",save_visible
    if not save_list:
      save_all = 1
    else:
      save_all = 0

    #print "save_status",save_visible,save_list,save_all

    status = {}
    import version
    status['version'] = version.ccp4mg_version


    if save_all or save_list.count('pick_labels'):
      if diagnostic: print "saving pick_labels"
      status['pick_labels'] = PICKLABEL().getparams()
            
    if save_all or save_list.count('picture_wizard'):
      if diagnostic: print "saving picture_wizard"
      status['picture_wizard']=PICTUREWIZARD().getparams()
      
    if save_all or save_list.count('gui_params'):
      if diagnostic: print "saving gui"
      status['gui_params']=MAINWINDOW().getParams()

    if save_all or save_list.count('mouse_bindings'):
      if diagnostic: print "saving mouse_bindings"
      status['mouse_bindings']=MAINWINDOW().mouseBindings()

    if save_all or save_list.count('view'):
      if diagnostic: print "saving view",MAINWINDOW().getViewParams()
      status['view2']=MAINWINDOW().getViewParams()
      
    if save_all or save_list.count('fonts'):
      if diagnostic: print "saving fonts"
      status['fonts']=FONTMANAGER().getparams()
      
    if save_all or save_list.count('file_viewer'):
      if diagnostic: print "saving file viewer"
      import mgFileViewer
      status['file_viewer']=mgFileViewer.getParams()


    if save_all or save_list.count('params'):
      if diagnostic: print "saving params"
      status['params2']=PM_MANAGER().save()
    elif save_list.count('picture_definition_params'):
      status['params2']=PM_MANAGER().save(picture_definition=1)


    if save_all or save_list.count('ModelInfo'):
      if diagnostic: print "saving ModelInfo"
      MODELINFO().save_user_files()
      status['ModelInfo']=MODELINFO().getparams()
      ModInf = {}
      for obj in dataobj.get_dataobj(object_type='MolData'):
        info = MODELINFO().get_set(obj.name_label)
        if info: ModInf[obj.name_label] = info
      status['AllModelInfo'] = ModInf

    #if save_all or save_list.count('movie'):
    #  status['movie'] = Appl('movie').getparams()

    if save_all or save_list.count('COLOUR'):
      if diagnostic: print "saving COLOUR"
      status['COLOUR'] = MGCOLOUR().getparams()
      
    if save_all or save_list.count('light'):
      if diagnostic: print "saving lights"
      status['light'] = MAINWINDOW().getLightParams()

    if save_all or save_list.count('windowGeometry'):
      mainwin = MAINWINDOW()
      if mainwin:
        from PyQt4 import QtCore
        settings = QtCore.QSettings("CCP4","CCP4MG")
        settings.setValue("mainwindow/geometry",QtCore.QVariant(mainwin.saveGeometry()))
        status['windowGeometry'] = settings.value("mainwindow/geometry").toByteArray()

    if save_all or save_list.count('data'):
      # Save the DataObj - make sure CrystalData saved last
      # as it has references to other types of DataObj which
      # might foul up on restore
      crystal_list = []
      Data_list = []
      not_model_list = []
      for obj in dataobj.DataObj.dataobj_insts:
        if not save_visible or obj.visible:
          if diagnostic: print "saving DataObj",obj.name
          shadowobj = dataobj.DataObjShadow()
          rv = shadowobj.save(obj,save_visible=save_visible)
          if rv:
            del shadowobj
          else:
            status[obj.name]=shadowobj
          #if obj.object_type == 'CrystalData':
          #  CrystalData_list.append(obj.name)
          #  #print "CrystalData", obj.name, status[obj.name]
          #else:
          if obj.object_type == 'MolData':
            Data_list.append(obj.name)
          elif obj.object_type == 'CrystalData':
            crystal_list.append(obj.name)
          else:
            not_model_list.append(obj.name)
      Data_list.extend(not_model_list)
      Data_list.extend(crystal_list)
      #status['CrystalData_list']=CrystalData_list
      status['Data_list']=Data_list

    if save_all or save_list.count('applications'):
      if diagnostic: print "saving applications"
      import Application
      status['applications'] = Application.getparams()
      
    if save_all or save_list.count('plugins'):
      if diagnostic: print "saving plugins"
      status['plugins'] = {}
      for key,value in self.plugin_status.items():
        status['plugins'][key] = value
   
    if f:
      if copy_to_dir:
        print "Dumping to",copy_to_dir
        nLost,objList,fileDef,nFound = self.copy_data_files_from_status(status,copy_to_dir)
        print fileDef
        s2 = self.edit_status_data_files_from_status(status,1,objList,fileDef)
        status = s2
      pickle.dump(status,f)
      f.close()
      return 0
    else:
      return status


#-----------------------------------------------------------------
  def write_pickle_file(self,filename='',status = {}):
#-----------------------------------------------------------------
    import pickle
    if not filename: return 1
    f = utils.openFile(filename,'w',overwrite='Overwrite')
    if not f: return 1
    try:
      print 'write_pickle_file',status['Data_list'],status[status['Data_list'][0]].get_filename()
      pickle.dump(status,f)
      f.close()
    except:
      return 1
    
    return 0

#-----------------------------------------------------------------
  def load_pickle_file(self,filename='',DIR_filename=''):
#-----------------------------------------------------------------
    import pickle
    status = {}
    if DIR_filename:
      filename = utils.get_filename(DIR_filename,filename)
    try:
      f = open(filename,'U')   
    except:
      return status

    #status = pickle.load(f)
    #status = QtUnpickler(f).load()
    try:
      #status = pickle.load(f)
      status = QtUnpickler(f).load()
    except:
      pass
    
    try:
      f.close()
    except:
      pass

    return status

#-----------------------------------------------------------------------
  def get_status_transparency(self,status):
#-----------------------------------------------------------------------
    ntransparent = 0
    for dataobj in status['Data_list']:
      if status.has_key(dataobj):
        for dispobj in getattr(status[dataobj],'objinsts',[]):
          #print 'get_status_transparency',dispobj,getattr(dispobj,'params')
          if getattr(dispobj,'params',{}).get('opacity',1.0)<0.99: ntransparent = ntransparent + 1
    return ntransparent

  
#-----------------------------------------------------------------------
  def get_status_data_files(self,filename='',hint_dirs=[]):
#-----------------------------------------------------------------------
    import os
    status = self.load_pickle_file(filename=filename)
    if not status:
      print "Error reading status file",filename
      return [-1,"Error reading status file "+filename]
    return self.get_status_data_files_from_status(status,hint_dirs)

#-----------------------------------------------------------------------
  def get_status_data_files_from_status(self,status,hint_dirs=[]):
#-----------------------------------------------------------------------
    import os
    if not status:
      print "Error reading status"
      return [-1,"Error reading status"]

    #print 'history.get_status_data_files',status['Data_list'],status.keys(),hint_dirs
    
    fileList = []
    fileDef = {}
    objList = []
    nLost = 0
    nFound = 0
    for mode in status['Data_list']:
      if not status.has_key(mode):
        print 'WARNING reading status file - no key:',mode
      elif status[mode].object_type == 'GL2dScreen':
        # Need to add the image data files to the files
        for dobj in status[mode].objinsts:
          if 'Image' in dobj.object_type:
            filn = dobj.get_filename()
            check_filn = utils.check_filename(filn)
            if not os.path.exists(check_filn[2]):
              found = 0
              for hint in hint_dirs:
                test_path = os.path.join(hint,os.path.basename(check_filn[1]))
                if os.path.exists(test_path):
                  check_filn = ['FULLPATH',test_path,test_path]
                  found = 1
                  nFound = nFound + 1
                  break
              nLost = nLost + 1
              objList.append(dobj.name)
              fileDef[dobj.name] = check_filn
          
      elif not ['CrystalData'].count(status[mode].object_type):
        filn = status[mode].get_filename()
        #print 'get_status_data_files filn',filn
        check_filn = utils.check_filename(filn)
        #print 'get_status_data_files check_filn',check_filn
        if not os.path.exists(check_filn[2]):
          found = 0
          for hint in hint_dirs:
            test_path = os.path.join(hint,os.path.basename(check_filn[1]))
            #print "Trying hint",test_path
            if os.path.exists(test_path):
              check_filn = ['FULLPATH',test_path,test_path]
              found = 1
              nFound = nFound + 1
              break
          nLost = nLost + 1
          objList.append(mode)
          #print "setting fileDef",mode,"to",check_filn
          fileDef[mode] = check_filn
        else:
          nFound = nFound + 1
          nLost = nLost + 1
          objList.append(mode)
          #print "setting fileDef",mode,"to",check_filn
          fileDef[mode] = check_filn
    #print 'get_status_data_files',nLost,fileList
    return [nLost,objList,fileDef,nFound]

#-----------------------------------------------------------------------
  def copy_data_files_from_status(self,status,target_dir):
#-----------------------------------------------------------------------
    import shutil
    import os
    if not status:
      print "Error reading status"
      return [-1,"Error reading status"]

    #print 'history.get_status_data_files',status['Data_list'],status.keys()
    
    if not os.path.exists(target_dir):
      try:
        os.mkdir(target_dir)
      except:
        return (1,'Error creating directory'+target_dir)

    fileList = []
    fileDef = {}
    objList = []
    nLost = 0
    nFound = 0
    for mode in status['Data_list']:
      if not status.has_key(mode):
        print 'WARNING reading status file - no key:',mode
      elif status[mode].object_type == 'GL2dScreen':
        # Need to add the image data files to the files
        for dobj in status[mode].objinsts:
          if 'Image' in dobj.object_type:
            filn = dobj.get_filename()
            check_filn = utils.check_filename(filn)
            print "check_filn 1",check_filn
            if os.path.exists(check_filn[2]) and ((not os.path.exists(os.path.join(target_dir,os.path.basename(check_filn[1])))) or (not utils.samefile(check_filn[2],os.path.join(target_dir,os.path.basename(check_filn[1]))))):
              theFile = os.path.join(target_dir,os.path.basename(check_filn[1]))

              if os.path.exists(theFile):
                print "File already exists!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",theFile
                print "Need to compare"
                hash1 = hashlib.sha256(open(theFile).read()).hexdigest()
                hash2 = hashlib.sha256(open(check_filn[2]).read()).hexdigest()
                if hash1 != hash2:
                  print "Need to do something!!!!!!!!?????????"
                  path, name = os.path.split(theFile)
                  name, ext = os.path.splitext(name)
                  make_fn = lambda i: os.path.join(path, '%s_%d%s' % (name, i, ext))
                  for i in itertools.count(1):
                    uniqueFile = make_fn(i)
                    if os.path.exists(uniqueFile):
                      print "Probably ought to check",uniqueFile
                      hash1 = hashlib.sha256(open(uniqueFile).read()).hexdigest()
                      if hash1 == hash2:
                        print "The same no need to copy",uniqueFile
                        theFile = uniqueFile
                        break
                    else:
                      print "Use",uniqueFile
                      theFile = uniqueFile
                      shutil.copyfile(check_filn[2],theFile)
                      break
                else:
                  print "Not copying, no need to"
              else:
                shutil.copyfile(check_filn[2],theFile)

              found = 0
              test_path = os.path.join(target_dir,os.path.basename(check_filn[1]))
              if os.path.exists(test_path):
                check_filn = ['FULLPATH',test_path,test_path]
                found = 1
                nFound = nFound + 1
              nLost = nLost + 1
              objList.append(dobj.name)
              fileDef[dobj.name] = check_filn
          
      elif not ['CrystalData'].count(status[mode].object_type):
        filn = status[mode].get_filename()
        check_filn = utils.check_filename(filn)
        print "check_filn 2",check_filn
        if os.path.exists(check_filn[2]) and ((not os.path.exists(os.path.join(target_dir,os.path.basename(check_filn[1])))) or (not utils.samefile(check_filn[2],os.path.join(target_dir,os.path.basename(check_filn[1]))))):
          theFile = os.path.join(target_dir,os.path.basename(check_filn[1]))
          if os.path.exists(theFile):
            print "File already exists!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",theFile
            print "Need to compare"
            hash1 = hashlib.sha256(open(theFile).read()).hexdigest()
            hash2 = hashlib.sha256(open(check_filn[2]).read()).hexdigest()
            if hash1 != hash2:
              print "Need to do something!!!!!!!!?????????"
              path, name = os.path.split(theFile)
              name, ext = os.path.splitext(name)
              make_fn = lambda i: os.path.join(path, '%s_%d%s' % (name, i, ext))
              for i in itertools.count(1):
                uniqueFile = make_fn(i)
                if os.path.exists(uniqueFile):
                  print "Probably ought to check",uniqueFile
                  hash1 = hashlib.sha256(open(uniqueFile).read()).hexdigest()
                  if hash1 == hash2:
                    print "The same no need to copy",uniqueFile
                    theFile = uniqueFile
                    break
                else:
                  print "Use",uniqueFile
                  theFile = uniqueFile
                  shutil.copyfile(check_filn[2],theFile)
                  break
            else:
              print "Not copying, no need to"
          else:
            shutil.copyfile(check_filn[2],theFile)
          found = 0
          test_path = theFile
          if os.path.exists(test_path):
            check_filn = ['FULLPATH',test_path,test_path]
            found = 1
            nFound = nFound + 1
          nLost = nLost + 1
          objList.append(mode)
          fileDef[mode] = check_filn
    #print 'get_status_data_files',nLost,fileList
    return [nLost,objList,fileDef,nFound]

#-----------------------------------------------------------------------
  def edit_status_data_files(self,filename,removeLost=1,objList=[],fileDefn={}):
#-----------------------------------------------------------------------
    '''
    Edit the status in file filename to change data filenames to those in fileDefn
    If any of the files do not exist then remove from the status Data_list
    '''
    status = self.load_pickle_file(filename)
    return self.edit_status_data_files_from_status(status,removeLost,objList,fileDefn)

#-----------------------------------------------------------------------
  def edit_status_data_files_from_status(self,status,removeLost=1,objList=[],fileDefn={}):
#-----------------------------------------------------------------------
    '''
    Edit the status to change data filenames to those in fileDefn
    If any of the files do not exist then remove from the status Data_list
    '''
    import os
    for objname in objList:
      if status.has_key(objname):
        if os.path.exists(fileDefn[objname][2]):
          #print "Setting",fileDefn[objname]
          status[objname].set_filename(fileDefn[objname])
        elif removeLost:
          if status.has_key(objname):
            del status[objname]
            if status['Data_list'].count(objname): status['Data_list'].remove(objname)
          else:
            pass
            # Beware could be Image file
      else:
        for mode in status['Data_list']:
          if status[mode].object_type == 'GL2dScreen':
            #print "GL2dScreen"
            for dobj in status[mode].objinsts:
              #print dobj
              if 'Image' in dobj.object_type:
                #print dobj.name, objname, str(dobj.name) == str(objname)
                if str(dobj.name) == str(objname):
                  #print "Setting",fileDefn[objname]
                  dobj.set_filename(fileDefn[objname])
          
    return status


   
#-----------------------------------------------------------------------
  def restore_view(self,status={},filename='',DIR_filename=''):
#-----------------------------------------------------------------------
    if filename:
      status = self.load_pickle_file(filename=filename,DIR_filename=DIR_filename)
    if not status:
      print "Error reading status file",filename
      return 1
    
    if status.has_key('view_options'):
      #print 'history.restore_status',status['view_options']
      pars = {}
      for item in ['fog_strength','slab_width','slab_offset']:
        if status['view_options'].has_key(item): pars[item] = status['view_options'][item]
      for item in ['fog','slab']:
        if status['view_options'].has_key(item+'_on'):
          pars[item+'_enabled'] = status['view_options'][item+'_on']
      #print 'history.restore_status view_options',pars
      MAINWINDOW().setViewParams(pars)

    if status.has_key('view2'):
      MAINWINDOW().setViewParams(status['view2'])
    elif status.has_key('view'):
      status['view'].restore()
    else:
      return 2
    return 0

#-----------------------------------------------------------------------
  def check_status_file(self,filename=''):
#-----------------------------------------------------------------------
    '''
    Check that we can load status from the pickle file filename
    '''
    if filename:
      status = self.load_pickle_file(filename=filename)
    if status and hasattr(status,"has_key") and status.has_key("Data_list") and len(status["Data_list"])>0:
      #print status["Data_list"]
      onlyCrystal = True
      for s in status["Data_list"]:
        if s!='CrystalData':
          onlyCrystal = False
          break
      if onlyCrystal:
        for s in status["Data_list"]:
          if hasattr(status[s],"get_filename"):
             if status[s].get_filename():
               return True
        return False
      return True
    return False

#-----------------------------------------------------------------------
  def restore_status(self,status={},filename='',
          restore_data=-1,exclude_list=[],**keywords):
#-----------------------------------------------------------------------
    '''
    Restore the status from the pickle file filename
    '''
    #print "history.restore_status",filename,exclude_list
    #print "restore_data",restore_data
    import dataobj
    import services
    import Crystal
    import pickle
    import types
    import os
    import model
    message = ''
    complete_reselection = 1

    # restore_classes is a list of the classes to restore -
    # any empty list implies all classes
    if filename:
      status = self.load_pickle_file(filename=filename)
    if not status:
      print "Error reading status file",filename
      return 1

    ccp4mg_version = 0
    old_colours=False
    if status.has_key('version'):
      ccp4mg_version = utils.parseVersion(status['version'])
      print 'Reading status file from version',status['version'],ccp4mg_version
      if ccp4mg_version[0] >= 2 and ccp4mg_version[1] <= 5 and ccp4mg_version[2] < 3:
        #print "Need to use old colours"
        old_colours=True
    
    # input restore_data = -1 -> take restore_data parameter
    # from the restored status
    if restore_data < 0:
      if status.has_key('params2') and status['params2'].has_key('save_session_options') and status['params2']['save_session_options'].has_key('restore_data'):
        restore_data = status['params2']['save_session_options']['restore_data']
      else:
        restore_data = PM('save_session_options').get('restore_data')
    
    if not exclude_list.count('params'):
      if status.has_key('params'):
         status['params'].restore()
         del services.ParamsManagerShadow.insts
      elif status.has_key('params2'):
        PM_MANAGER().restore(data=status['params2'])

    if restore_data:
    # Make copy of list of objects - otherwise gets confused

      if complete_reselection:
        obj_list = []
        for obj in dataobj.DataObj.dataobj_insts: obj_list.append(obj)
        for obj in obj_list: obj.delete()
        model.MolData.last_MolData_number = 0
      

    # Need colours loaded to correctly interpret ColourManager
    MGCOLOUR().usingOldColours = False
    if not exclude_list.count('COLOUR') and status.has_key('COLOUR'):
      #print "Setting", MGCOLOUR(),status['COLOUR']
      if old_colours:
        MGCOLOUR().rgbreps = []
        MGCOLOUR().n_standard_rgbreps = 0
        MGCOLOUR().RGBReps.clear()
        MGCOLOUR().usingOldColours = True
      else:
        MGCOLOUR().rgbreps = []
        MGCOLOUR().n_standard_rgbreps = 0
        MGCOLOUR().RGBReps.clear()
        MGCOLOUR().load_default()
      MGCOLOUR().setparams(params=status['COLOUR'])
    else:
      pass # Restore default colours ??


    if not exclude_list.count('gui_DISParams') and status.has_key('gui_params'):
      MAINWINDOW().setParams(params=status['gui_params'])
      
    if not exclude_list.count('mouse_bindings') and status.has_key('mouse_bindings'):
      MAINWINDOW().setMouseBindings(params=status['mouse_bindings'])

    if not exclude_list.count('light') and status.has_key('light'):
      import display_table
      if isinstance(status['light'],display_table.LightShadow):
        status['light'].restore()
      else:  
        MAINWINDOW().setLightParams(params=status['light'])
      
    if not exclude_list.count('pick_labels'):
      if status.has_key('pick_labels'):
        PICKLABEL().setparams(params=status['pick_labels'])

    if not exclude_list.count('fonts'):
      if status.has_key('fonts'):
        FONTMANAGER().setparams(params=status['fonts'])     
      if status.has_key('view_options'):
        FONTMANAGER().setparams(params=status['view_options'])

    if (not exclude_list.count('file_viewer')) and status.has_key('file_viewer'):
      import mgFileViewer
      mgFileViewer.setParams(status['file_viewer'])
   
  
    if not exclude_list.count('ModelInfo') and status.has_key('ModelInfo'):
      MODELINFO().setparams(params=status['ModelInfo'])
    if not exclude_list.count('AllModelInfo') and status.has_key('AllModelInfo') and status['AllModelInfo']:
      for set in status['AllModelInfo'].keys():
        MODELINFO().set_set(set=set,ModInfo=status['AllModelInfo'][set])

    if not exclude_list.count('windowGeometry') and status.has_key('windowGeometry'):
      try:
        mainwin = MAINWINDOW()
        if mainwin:
           mainwin.restoreGeometry(status['windowGeometry'])
      except:
        print "Failed to restore main window geometry"

    if not exclude_list.count('data') and status.has_key('Data_list'):

      if not complete_reselection:
        self.update_data_status(status=status)

      else:
        data_old_colours = False
        #print " status['Data_list']", status['Data_list']
        default_dir = os.path.dirname(filename)
        for mode in status['Data_list']:
          if restore_data and status.has_key(mode):
            #print 'history.restore_status',status[mode]
            if hasattr(status[mode],"dataparams"):
              if not status[mode].dataparams.has_key("ccp4mg_creator_version"):
                 status[mode].dataparams["ccp4mg_creator_version"] = status['version']
              #print status[mode].dataparams["ccp4mg_creator_version"]
              ccp4mg_creator_version = utils.parseVersion(status[mode].dataparams["ccp4mg_creator_version"])
              #print 'Reading status file from version',status['version'],ccp4mg_version
              if ccp4mg_creator_version[0] >= 2 and ccp4mg_creator_version[1] <= 5 and ccp4mg_creator_version[2] < 3:
                #print "Need to use old colours because object needs them."
                data_old_colours = True
              #print data_old_colours, old_colours, status.has_key('COLOUR')
              if data_old_colours and not old_colours and status.has_key('COLOUR'):
                MGCOLOUR().rgbreps = []
                MGCOLOUR().n_standard_rgbreps = 0
                MGCOLOUR().RGBReps.clear()
                MGCOLOUR().setparams(params=status['COLOUR'])
                MGCOLOUR().usingOldColours = True
                old_colours = True # only do this once.
            #print mode,status[mode]
            rv = status[mode].restore(version=ccp4mg_version,default_dir=default_dir)
            if rv[0]: del status[mode]
            if rv[1]: message = message+rv[1]+'\n'

        for mode in status['Data_list']:
          if restore_data and status.has_key(mode):
            rv = status[mode].restore_display_objects(override_visible=1,version=ccp4mg_version)
            if rv[1]: message = message+rv[1]+'\n'

        if status.has_key('CrystalData_list') and len(status['CrystalData_list'])>0:      
          import rebuild 
          rebuild.UpdateDisplay()
          #print "history",status['CrystalData_list']
          for mode in status['CrystalData_list']:
            if status.has_key(mode):
              if restore_data:
                rv = status[mode].restore()
                rv = status[mode].restore_display_objects(override_visible=1,version=ccp4mg_version)
                if rv[1]: message=message+rv[1]+'\n'
      
    if not exclude_list.count('view'):
      self.restore_view(status=status)

    if not exclude_list.count('applications'):
      if status.has_key('applications'):
        import Application
        Application.setparams(params=status['applications'])

    if not exclude_list.count('plugins'):
      if status.has_key('plugins'):
        for key,value in status['plugins'].items():
          self.plugin_status[key] = value
      self.pluginsStatusChanged.emit()

    if not exclude_list.count('jobcontrol') and status.has_key('jobcontrol'):
      JOBCONTROL().setparams(params=status['jobcontrol'])

    if message:
      #print "message",message
      MGGUI().WarningMessage(message)

    return 0
    
#-----------------------------------------------------------------------
  def update_data_status(self,status={},filename='',DIR_filename='', \
             exclude_list=[],override_visible=1,delay_delete=0,**keywords):
#-----------------------------------------------------------------------
    '''
    Restore the data status from the pickle file filename
    Attempt to minimise deleting and adding new objects
    '''
    import dataobj
    import Crystal
    import pickle
    self.update_gui = []
    #print "update_data_status, start",self.update_gui
    
    message = ''
    default_dir = ''

    #print "history.update_data_status status",status

    if not status:
      status = self.load_pickle_file(filename=filename,DIR_filename=DIR_filename)
      if not status or not status.has_key('Data_list'):
        #return []
        pass
    if filename:
      import os
      default_dir = os.path.dirname(filename)
   
    # Get list of current dataobj which are not in the
    # updated status and therefor should be deleted
    current_dataobj = dataobj.get_dataobj()
    current_dataobj_names = []
    for obj in current_dataobj:
      current_dataobj_names.append(obj.name)
      
    #print "current_dataobj",current_dataobj
    delete_list = []
    for obj in current_dataobj:
      if not status['Data_list'].count(obj.name) or 'Legends&Images' in obj.name or \
         not status.has_key(obj.name) or \
         not obj.isSameData(status[obj.name]):
        delete_list.append(obj)

    for item in delete_list:
        self.update_gui.append(['delete_DataObj',item.name])
        item.delete()
    del delete_list

    add_list = []
    changed_list = []
    for data_name in status['Data_list']:
      if status.has_key(data_name):
        if not current_dataobj_names.count(status[data_name].name):
          add_list.append(data_name)
        else:
          d_obj = current_dataobj[current_dataobj_names.index(status[data_name].name)]
          if not d_obj.isSameData(status[data_name]):
            add_list.append(data_name)
          else:
            rv = d_obj.update_data_status(status[data_name])
            if rv:
               self.update_gui.append(['update_DataObj',data_name])

    #print "history.update_data_status add_list",add_list

    for data_name in add_list:
      theName = data_name
      rv = status[data_name].restore(default_dir=default_dir)
      if len(rv)>2 and hasattr(rv[2],"name"):
        if rv[2].name != data_name:
          theName = rv[2].name
      rv = status[data_name].restore_display_objects(override_visible=override_visible)
      if rv[1]:
        message=message+rv[1]+'\n'
      else:
        self.update_gui.append(['add_DataObj',theName])
      
    if status.has_key('COLOUR'):
      MGCOLOUR().update_data_status(status['COLOUR'])

    # *** Issues with reading pre-2.0 status files - view options probable
    #     not important except for lighting
    #if status.has_key('view_options'):
    #  DT().viewmenu.update_data_status(status['view_options'])
      
    #print "history.update_data_status edited_list",edited_list
    
    if status.has_key('params'):
      self.update_gui.extend(PM_MANAGER().update_data_status(data=status['params'].data))
            
    if status.has_key('params2'):
      self.update_gui.extend(PM_MANAGER().update_data_status(data=status['params2']))

    if message:
      #print "message",message
      MGGUI().WarningMessage(message)
  
#------------------------------------------------------------------------
  def AppendRetryCommands(self,command=[]):
#------------------------------------------------------------------------
    #Applications/objects can add a command to the retry list
    #This list is processed on program restart after all dataobjs/dispobj
    #have been recreated and again after all applications have been opened
    #command is a list with arguments for the apply command
    if not hasattr(self,'retry_commands'): self.retry_commands = []
    self.retry_commands.append(command)


#------------------------------------------------------------------------
  def apply_retry_commands(self):
#------------------------------------------------------------------------
    # Retry all commands 
    if not hasattr(self,'retry_commands'): return
    for item in self.retry_commands:
      #print "retrying",item
      try:
        apply(item[0],item[1],item[2])
      except:
        #print "failed"
        pass
    del self.retry_commands
    

#-----------------------------------------------------------------------
  def Exit(self):
#-----------------------------------------------------------------------
    import Application
    for app in Application.Application.application_insts:
      app.Exit()

    saved = 0
    if DEVELOPER():
    	self.save_program_status()
	saved = 1
    	if PM('save_session_options').get('backup_data_files'): self.do_backup_data_files()
    else:      
      try:
      	self.save_program_status()
	saved = 1
    	if PM('save_session_options').get('backup_data_files'): self.do_backup_data_files()
      except:
	print "Error saving status"
	exc_type, exc_value,exc_tb = sys.exc_info()[:3]
	sys.stderr.write(str(exc_type)+'\n')
	sys.stderr.write(str(exc_value)+'\n')
        import traceback
        traceback.print_stack()

    if saved:
      # If status file successfully saved then cleanup the autoSaved backups
      self.autoSaveCleanup()
      
#--------------------------------------------------------------------
  def status_difference(self,initial_status,final_status):
#--------------------------------------------------------------------
    import dataobj
    Data_list = []
    add_Data_list = []
    minus_Data_list = []
    for dataname in initial_status['Data_list']:
      if dataname in initial_status and dataname in final_status and \
       initial_status[dataname].object_type==final_status[dataname].object_type :
        tmp = dataobj.DataObjShadow(name=dataname,object_type=initial_status[dataname].object_type,filename=initial_status[dataname].filename)
        diff = tmp.difference(initial_status[dataname],final_status[dataname])
        if not diff:
          del tmp
        else:
          Data_list.append(tmp)
      else:
        minus_Data_list.append(dataname)
    

    for dataname in final_status['Data_list']:
     if dataname in initial_status and dataname in final_status:
      if not initial_status['Data_list'].count(dataname) or initial_status[dataname].object_type!=final_status[dataname].object_type:
        tmp =  dataobj.DataObjShadow()
        tmp.save(final_status[dataname])
        add_Data_list.append(tmp)

    return [Data_list,add_Data_list,minus_Data_list]

#-------------------------------------------------------------------
  def status_add(self,status,Data_list,add_Data_list,minus_Data_list):
#-------------------------------------------------------------------
    #print "status_add",status['Data_list'],status.keys()
    import dataobj
    for dataname in  minus_Data_list:
      if status['Data_list'].count(dataname) and status.has_key(dataname):
        #print "status_add remove", dataname
        status['Data_list'].remove(dataname)
        del status[dataname]
        
    for dobj in  Data_list:
      dataname = dobj.name
      #print "status_add edit",dataname
      if status['Data_list'].count(dataname) and status.has_key(dataname):
        status[dataname].add(dobj)
        

    for dobj in add_Data_list:
      dataname = dobj.name
      if not status['Data_list'].count(dataname):
        #print "status_add create", dataname
        tmp = dataobj.DataObjShadow()
        tmp.save(dobj)
        status['Data_list'].append(dataname)
        status[dataname] = tmp

    return status

       
  #--------------------------------------------------------------------
  def get_presentation_menu(self):
  #--------------------------------------------------------------------
    if not hasattr(self,'presentation_running'):
      self.presentation_running = 0
    #print "get_presentation_menu",self.presentation_running
    if self.presentation_running:
      menu = []
      i = 1
      for item in  self.current_presentation:
        menu.append(['rb1','presentation_scene','scene'+str(i),item[2]])
        i = i+1
      menu.append(['com','presentation_close'])
      return ['cas','Presentation',menu,['TEAROFF','1']],'scene'+str(self.presentation_running)
    else:
      return ['pr','_presentation'],''
    


#---------------------------------------------------------------------------
  def autoSave(self):
#---------------------------------------------------------------------------
    import time
    self.nAutoSaved = self.nAutoSaved + 1
    #if self.autoSavedPosition < len(self.autoSavedStatus)-1:
    #  del self.autoSavedStatus[self.autoSavedPosition+1:]
    self.autoSavedStatus.append(self.save_status(save_list=['data','picture_definition_params']))
    self.autoSavedPosition = len(self.autoSavedStatus)-1

    '''
    #Disable trimming number of saved status in memory and saving to disk
    if len(self.autoSavedStatus)>self.maxAutoSaved:
      del self.autoSavedStatus[0:self.delAutoSaved]
      self.autoSavedPosition = self.autoSavedPosition - self.delAutoSaved


    if self.diskAutoSaveFrequency and self.nAutoSaved%self.diskAutoSaveFrequency==0:
      #t = int(time.ctime())
      time_label = time.strftime(self.autoSaveTimeFormat,time.localtime())
      self.autoSaveToFile(time_label)
      #self.autoSaveToFile(str(self.nAutoSaved))
    '''
    
    #print "history.autoSave nAutoSaved,autoSavedPosition,len ",self.nAutoSaved,self.autoSavedPosition,len(self.autoSavedStatus)
    #import inspect
    #print "history.autoSave",inspect.stack()

    
#---------------------------------------------------------------------------
  def autoRestore(self,increment=0):
#---------------------------------------------------------------------------
    if increment<=0:
      new=max(0,self.autoSavedPosition+increment)
    else:
      new = min(len(self.autoSavedStatus)-1,self.autoSavedPosition+increment)

    #print "history.autoRestore",new
    if new != self.autoSavedPosition:
      self.autoSavedPosition = new
      self.update_data_status(status=self.autoSavedStatus[self.autoSavedPosition], restore_all_visible=1)
      

#---------------------------------------------------------------------------
  def autoSaveToFile(self,label=''):
#---------------------------------------------------------------------------
      # Save a status file to auto_save directory.  The file name includes
      # the label 'label'
      import os
      filename = os.path.join (utils.get_CCP4MG(),'auto_save','auto_save_'+label+'.pkl')
      self.save_status(filename=filename,overwrite='overwrite')
      print 'history.autoSaveToFile',filename

#---------------------------------------------------------------------------
  def autoSaveCleanup(self):
#---------------------------------------------------------------------------
    # Called on program exit (after regular save_status) to delete the auto_save
    # directory
    import os,shutil
    # Deleting whole directory probably more efficient than file by file
    if os.path.exists(os.path.join(utils.get_CCP4MG(),'auto_save')):
      try:
        shutil.rmtree(os.path.join(utils.get_CCP4MG(),'auto_save'))
      except:
        print 'ERROR in history.autoSaveCleanup cleaning up auto saved status files.'
        pass

#---------------------------------------------------------------------------
  def recoveryFileAvailable(self):
#---------------------------------------------------------------------------
    import glob,os
    file_list = glob.glob(os.path.join(utils.get_CCP4MG(),'recover','auto_save_*.pkl'))
    if file_list:
      return 1
    else:
      return 0

#---------------------------------------------------------------------------
  def recoverAutoSave(self):
#---------------------------------------------------------------------------
    # This is called on program startup
    # If there are files in the auto_save directory (implies last program run crashed)
    # move the last one to recovery directory.
    # The 'Recover status' gui option accesses files in the recovery directory.
    # Then delete all of auto_save files.
    import shutil,os

    last_auto_save = self.autoSaveLastFile()
    if last_auto_save:
      shutil.copyfile(last_auto_save,
		      os.path.join(utils.get_CCP4MG(),'recover',os.path.split(last_auto_save)[-1]))
      # Remove remaining files - so don't get confused with current program run
      self.autoSaveCleanup()
      
#---------------------------------------------------------------------------
  def getRecoverFiles(self):
#---------------------------------------------------------------------------
    # Return a list of the data/time labels from the files in recover directory
    # These are in reverse time order

    import glob,os

    date_list = []
    file_list = glob.glob(os.path.join(utils.get_CCP4MG(),'recover','auto_save_*.pkl'))
    #print 'history.autoSaveLastFile',file_list
    if not file_list: return []
    # Sort in to revser date order
    file_list.sort(sortAutoSaveFiles)
    file_list.reverse()
    for file in file_list:
      date_list.append(os.path.basename(os.path.splitext(file)[0])[10:])
    return date_list



#---------------------------------------------------------------------------
  def recover(self,label=''):
#---------------------------------------------------------------------------
    import os
    #print 'history.recover label',label
    filename = 	os.path.join(utils.get_CCP4MG(),'recover','auto_save_'+label+'.pkl')
    if os.path.exists(filename):
      rv = self.restore_status(filename=filename)
      return rv
    else:
       return 2
    return 0
       
#---------------------------------------------------------------------------
  def autoSaveLastFile(self):
#---------------------------------------------------------------------------
    # Test for files in the auto_save directory and return the last one.
    # This directory should have been deleted on program exit so if there
    # is a file it implies that last program run crashed.
    
    import glob,os

    # Beware get_CCP4MG() may recreate auto_save directory (but it will contain
    # no files.
    file_list = glob.glob(os.path.join(utils.get_CCP4MG(),'auto_save','auto_save_*.pkl'))
    #print 'history.autoSaveLastFile',file_list
    if not file_list: return ''

    
    last_file = 0
    t = os.path.getmtime(file_list[0])
    for ii in range(1,len(file_list)):
      t2 = os.path.getmtime(f)
      if t2>t:
        t = t2
	last_file = ii
	
    '''
    last_file = 0
    t = int(os.path.basename(os.path.splitext(file_list[0])[0]))   
    for ii in range(1,len(file_list)):
      t2 = int(os.path.basename(os.path.splitext(file_list[ii])[0]))   
      if t2>t:
        t = t2
	last_file = ii
    '''

    return file_list[last_file]
    
#-----------------------------------------------------------------------
  def parse_program_command_line(self):
#-----------------------------------------------------------------------
    # Parse the program command line
    self.command_line_script = ''
    self.command_line_status = ''
    self.command_line_picture = ''
    self.command_line_datafiles = []
    self.command_line_restore = -1
    self.command_line_other_files = []

    
    if len(sys.argv) <= 1: return ""
    import re
    i=1
    while i < len(sys.argv):
      if re.match('-h',sys.argv[i]):
        helpfile = os.path.join(os.environ["CCP4MG"],'python','etc','help.txt')
        f=openFile(helpfile,'r',1)
        if f: 
          helptext=f.read()
          f.close()
          print helptext
          sys.exit()
      elif re.match('-r',sys.argv[i]):
        self.command_line_restore = 1
      elif re.match('-nore',sys.argv[i]):
        self.command_line_restore = 0
      elif re.match('-scr',sys.argv[i]):
        i=i+1
        if not os.path.exists(sys.argv[i]):
          print "Script file does not exist: "+sys.argv[i]
          return "Script file does not exist: "+sys.argv[i]
        self.command_line_script = os.path.abspath(sys.argv[i])
      elif re.match('-st',sys.argv[i]):
        i=i+1
        if not os.path.exists(sys.argv[i]):
          print "Status file does not exist: "+sys.argv[i]
          return "Status file does not exist: "+sys.argv[i]
        self.command_line_status = os.path.abspath(sys.argv[i])
      elif re.match('-pi',sys.argv[i]):
        i=i+1
        if not os.path.exists(sys.argv[i]):
          print "Picture file does not exist: "+sys.argv[i]
          return "Picture file does not exist: "+sys.argv[i]
        self.command_line_picture = os.path.abspath(sys.argv[i])
      elif re.match('-dr',sys.argv[i]):
        #Set the drawing style
        i = i+1
        self.command_line_datafiles.append(['drawing_style',sys.argv[i]])
      elif re.match('-mo',sys.argv[i]) or  re.match('-pd',sys.argv[i]) or \
         (not re.match('-',sys.argv[i]) and re.search('\.pdb$',sys.argv[i])) :
        if re.match('-mo',sys.argv[i]) or  re.match('-pd',sys.argv[i]):i=i+1
        filn = sys.argv[i]
        print "command line pdb",filn
        if os.path.exists(filn):
          self.command_line_datafiles.append(['model',os.path.abspath(filn)])
        else:
          filn1 = os.path.splitext(filn)[0] + '.pdb'
          if not os.path.exists(filn1):            
            print "Model file does not exist: "+sys.argv[i]
            return "Model file does not exist: "+sys.argv[i]
          self.command_line_datafiles.append(['model',os.path.abspath(filn1)])

      elif re.match('-map',sys.argv[i]):
        i = i+1
        filn = sys.argv[i]  
        if not os.path.exists(filn):
          filn = filn + '.map'
          if not os.path.exists(filn):
            print "Map file does not exist: "+sys.argv[i]
            return "Map file does not exist: "+sys.argv[i]
        self.command_line_datafiles.append(['map',os.path.abspath(filn)])

      elif re.match('-mt',sys.argv[i]) or \
        (not re.match('-',sys.argv[i]) and re.search('\.mtz$',sys.argv[i])):
        if re.match('-mt',sys.argv[i]): i=i+1
        filn = sys.argv[i]  
        if not os.path.exists(filn):
          filn = filn + '.mtz'
          if not os.path.exists(filn):
            print "MTZ file does not exist: "+sys.argv[i]
            return "MTZ file does not exist: "+sys.argv[i]
        # Read the MTZ column info - 3 possible extra arguments
        # and make a dictionary for the info
        fileinfo = {}
        fileinfo['filename'] = os.path.abspath(filn)
        args = ['f','phi','wt','difference']
        """
        # FIXME ?, this stuff is wrong if one passes two mtzs on comamnd line
        # and ignored in apply_program_command_line and openMTZ. But noone uses it ...
        j = -1
        while i+1 < len(sys.argv) and not re.match('-',sys.argv[i+1]):
          i = i + 1
          j = j+1
          fileinfo[args[j]]=(sys.argv[i])
        j = j+1
        while j < len(args):
           fileinfo[args[j]]=''
           j = j+1
        """
        self.command_line_datafiles.append(['mtz',fileinfo])
      elif re.match('-ve',sys.argv[i]) or ( not re.match('-',sys.argv[i]) \
          and re.search('\.vector$',sys.argv[i])) :
        if re.match('-ve',sys.argv[i]):i=i+1
        filn = sys.argv[i]
        if not os.path.exists(filn):
          filn = filn + '.vector'
          if not os.path.exists(filn):
            print "Vector file does not exist: "+sys.argv[i]
            return "Vector file does not exist: "+sys.argv[i]
        self.command_line_datafiles.append(['vector',os.path.abspath(filn)])
      elif re.match('-i',sys.argv[i]):
        i=i+1
        if not os.path.exists(sys.argv[i]):
          print "Image file does not exist: "+sys.argv[i]
          return "Image file does not exist: "+sys.argv[i]
        self.command_line_datafiles.append(['image',os.path.abspath(sys.argv[i])])
      elif re.match('-de',sys.argv[i]):
        while i+1<len(sys.argv) and \
            ['command','opengl','timing','framerate'].count(sys.argv[i+1]):
          self.diagnostic[(sys.argv[i+1])]=1
          i=i+1
      # Set the project to use
      elif re.match('-pr',sys.argv[i]):
        i=i+1
        if CCP4DATABASE().get_project_dir(sys.argv[i]):
           self.command_line_project = sys.argv[i]
        else:
          print "ERROR project name "+sys.argv[i]+" is not recognised"
          return "ERROR project name "+sys.argv[i]+" is not recognised"
      elif re.match('-psn_',sys.argv[i]):
        i=i+1
      elif re.match('-po',sys.argv[i]) or re.match('-mast',sys.argv[i]):
        if i+2<len(sys.argv):
          try:
            ports = [ int(sys.argv[i+1]), int(sys.argv[i+2]) ]
            i=i+2
          except:
            print "ERROR interpreting '-port' argument"
            return "ERROR interpreting '-port' argument"
        else:
          print "ERROR insufficient qualifiers for '-port' command"
          print "should be '-port first last'"
          return "ERROR insufficient qualifiers for '-port' command\nshould be '-port first last'"
        if ports[0]<1000 or ports[0]>10000 or \
           ports[1]<ports[0] or  ports[1]>10000:
          print "ERROR ports not in range 1000-10000 or end range less than start"
          return "ERROR ports not in range 1000-10000 or end range less than start"
        if re.match('-po',sys.argv[i-2]):
          self.test_ports = ports
        else:
          self.master_ports = ports
      elif re.match('-q',sys.argv[i]):
        if not sys.platform == 'win32':
          if not re.match('-quit',sys.argv[i]):
            utils.redirectOutput()
      else:
        # Is it a file?
        filn = sys.argv[i]
        if os.path.exists(filn):
          filn0,ext=os.path.splitext(filn)
          if ['.pkl'].count(ext):
            self.command_line_status = os.path.abspath(sys.argv[i])
          elif ['.py'].count(ext):
            if os.path.splitext(filn0)[1] == '.mgpic':
              self.command_line_picture = os.path.abspath(sys.argv[i])
          else:
            self.command_line_other_files.append(os.path.abspath(filn))
                                
        else:
          #print "Input command not recognised by main program: "+sys.argv[i]
    	  #self.command_line_script = ''
    	  #self.command_line_status = ''
    	  #self.command_line_picture = ''
    	  #self.command_line_datafiles = []
    	  #self.command_line_restore = 0
          return sys.argv[i:]
      i = i + 1

    return ""

#-----------------------------------------------------------------------
  def apply_program_command_line(self):
#-----------------------------------------------------------------------

    rc = 0
    # Load picture definition files
    if self.command_line_picture:
      rcpd = PD().restore_picture_definition(filename=self.command_line_picture)
      rc = rc + rcpd[0]
      if DISPLAYTABLE(): DISPLAYTABLE().loadAllDataObj()

    # Load data files
    if self.command_line_datafiles:
      for filetype,filename in self.command_line_datafiles:
        if filetype == 'drawing_style':
          PICTUREWIZARD().set_default_drawing_style(filename)
        elif filetype == 'mtz':
          MAINWINDOW().openFile(filename['filename'],use_current_style=1)
        else:
          MAINWINDOW().openFile(filename,use_current_style=1)
    for filename in self.command_line_other_files:
      MAINWINDOW().openFile(filename,use_current_style=1)
    return rc

#-----------------------------------------------------------------------
  def run_command_line_script(self):
#-----------------------------------------------------------------------
    
    if not self.command_line_script: return 0
    globs = {}
    message = ''
    try:
      execfile(self.command_line_script,globs)
    except  StandardError, e:
      message = message + 'Error running script '+self.command_line_script
      print message
      print e.args
      return 1
    return 0

#------------------------------------------------------------------
def createParamsManager():
#------------------------------------------------------------------
  import services
 
  pm = services.ParamsManager ( \
          name="save_session_options",
          help="program_status.html",
          title='Saving session options', \
          gui=['restore_data','interpret_old_selections','backup_data_files','save_projects'],
       default = { 'restore_data' : 1,
                  'ask_restore_data' : 0,
                  'backup_data_files' : 0,
                  'interpret_old_selections' : 1,
                  'save_projects': 0 },
      definition = {
         'restore_data' : dict(type=bool, label='Restore status on restart', style='checkbox' ),
         'ask_restore_data' : dict(type=bool, label='Ask before restoring', style='checkbox' ),
         'backup_data_files' : dict(type=bool, label='Backup data files on exit', style='checkbox' ),
         'interpret_old_selections' : dict(type=bool, label='Attempt to parse old style selections', style='checkbox' ),
          'save_projects' : dict(type=bool, label='Save separate status for each CCP4i project', style='checkbox' )
             })

  return pm

#------------------------------------------------------------------
def sortAutoSaveFiles(file1,file2):
#------------------------------------------------------------------
  # Sorting function for auto save files by date
  import os,time
  try:
    label1 = os.path.split(file1)[-1][10:-4]
    t1 = time.mktime(time.strptime(label1,HISTORY().autoSaveTimeFormat))
    label2 = os.path.split(file2)[-1][10:-4]
    t2 = time.mktime(time.strptime(label2,HISTORY().autoSaveTimeFormat))
    #print 'sortAutoSaveFiles',label1,t1,label2,t2
    if t1<t2:
      return -1
    elif t2>t1:
      return 1
    else:
      return 0	
  except:
    return 0	
