"""
     python/ui/model_colour.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 os
import dataobj
import mmdb2 as mmdb
import mgapp,mmut
import resources,utils,services
from global_definitions import *


#------------------------------------------------------------------
class model_colour(dataobj.Dependency):
#------------------------------------------------------------------
  colour_menu = ['One colour','Atom type','Residue type','By chain',
                  'Main/side chain','Secondary structure','Blend through model',
                  'Temperature factor','Occupancy', 'Alternate location','Charge', 'User defined',
                  'Residue solvent access', 'Atom solvent access','Interface',
                  'Position in chain', 'By model' , 'By molecule']
  colour_commands = [ 'one_colour','atomtype','restype','bychain',
                      'mainside','secstr','blend','bvalue','occupancy','altloc','charge','rules',
                      'res_sas','atom_sas', 'interface',
                      'thru_chain','bymodel', 'bymol']
  colour_commands_icons = {'atomtype':'byatom.svg','blend':'blendthrough.svg','atom_sas':'atomsolventaccess.svg',
                           'res_sas':'residuesolventaccess.svg','bychain':'bychain.svg','charge':'charge.svg',
                            'interface':'interface.svg','mainside':'mainside.svg','occupancy':'occupancy.svg',
                            'restype':'residuetype.svg','secstr':'secstr.svg','bvalue':'tempfactor.svg',
                            'electrostatic':'electrostatic.svg', 'altloc':'altloc.svg', 'bymodel':'bymodel.svg'
                          }
  custom_colour_commands_methods = {}
  custom_colour_commands_labels = {}
  colour_code = [ mgapp.ONECOLOUR, mgapp.BYATOMTYPE, mgapp.BYRESTYPE, mgapp.BYCHAIN, \
                  mgapp.MAINSIDE, mgapp.SECSTR, mgapp.BLENDTHRU, mgapp.BVALUE, mgapp.OCCUPANCY, mgapp.ALTLOC, mgapp.CHARGE, \
                  mgapp.USER_SCHEME,mgapp.SASRES,mgapp.SASATOM, mgapp.CONTACTRES,mgapp.CONTACTATOM, \
                  mgapp.THRU_CHAIN, mgapp.BYMODEL ]
  blend_group_menu = ['residue', 'SSE']
  blend_group_code = [ mgapp.BLEND_RESIDUE, mgapp.BLEND_SECSTR ]

  colour_initialisation = {
    'colour_mode' : 'atomtype',
    'non_C_atomtype' : 0,
    'one_colour' : '',
    'user_scheme' : ['Edited scheme'],
    'colour_rules' : [],
    'stick_colour' : 'ATOM',
    'interface_style' : 'RESIDUE',
    'interface_selection' : '',
    'interface_MolData_name' : '' }
  
  colour_blend_initialisation = {
    'group' : 'residue',
    'default_colour' : 'white',
    'type' : 'all',
    'selection_command' : ['peptide'],
    'colours':[['blue','red']],
    'direction' : ['anti-clockwise'] }
  
  colour_initialisation_order =  \
            ['colour_mode','one_colour','non_C_atomtype','stick_colour',
             'user_scheme','colour_rules','colour_legend',
             'interface_style','interface_selection', 'interface_MolData_name' ]
  colour_blend_order = [
             'selection_command','colours','default_colour',
             'direction','group','type']

#------------------------------------------------------------------
  def __init__(self,colparams={},MolData=None,SelHandle=None):
#------------------------------------------------------------------
    dataobj.Dependency.__init__(self)
    import loadPlugins
    loadPlugins.loadPlugins('initializeColouringPlugin')
    self.atomColourVector = None
    self.ifColourContinuous = 0
    self.MolData = MolData
    self.SelHandle = SelHandle
    self.legend_object = None

    self.do_recolour = 0
    self.colour_mode = ''
    self.colour_label=''
    self.colour_icon=None
    self.colour_legend=''
    self.user_colour_objects=[]
    self.user_colour_id=0
    self.user_selHnds=[]
    self.colour_blend = {}


    for key,value in model_colour.colour_initialisation.items():
      setattr(self,key,value)
    for key,value in model_colour.colour_blend_initialisation.items():
      self.colour_blend[key] = value
    if not self.MolData.molecule_type.count('PROTEIN'):
      if  self.MolData.molecule_type.count('NUCLEIC'):
        self.colour_blend['selection_command'] = ['nucleic']

    self.CMolColour = mgapp.CMolColour ( self.MolData.molHnd, -1 , services.getCColourSchemes())

    # Beware initialisation colour rules may have selection rules in the old 'nested list' format
    #if colparams.has_key('colour_rules') and len(colparams['colour_rules'])>1:
    
    self.set_colour(colparams=colparams)


#------------------------------------------------------------------
  def commandColourRules(self,rules):
#------------------------------------------------------------------
      import types,model_selection
      parser= None
      new_rules = [rules[0]]
      for rule in rules[1:]:
        if isinstance(rule[1],types.ListType):
          if not parser: parser= model_selection.SelectionParser()
          tmp = [rule[0],parser.list_to_command(rule[1])[1]]
          for item in rule[2:]: tmp.append(item)
          new_rules.append(tmp)
        else:
          new_rules.append(rule)
      return new_rules


#------------------------------------------------------------------
  def colparams(self,all=1):
#------------------------------------------------------------------
    col = {}

    if all:
      for item in model_colour.colour_initialisation_order:
        if hasattr(self,item): col[item] = getattr(self,item)
      col['colour_blend'] = {}
      if hasattr(self,'colour_blend'):
        col['colour_blend'].update(self.colour_blend)
    else:
      for item in model_colour.colour_initialisation_order[2:]:
        value = getattr(self,item)
        if not model_colour.colour_initialisation.has_key(item) or value != model_colour.colour_initialisation[item]:
          col[item]=value
      if col:
        col['colour_mode']= getattr(self,'colour_mode')
        if  getattr(self,'one_colour'):
          col['one_colour']= getattr(self,'one_colour')
        if col['colour_mode']== 'blend':
          col['colour_blend'] = {}
          col['colour_blend'].update(self.colour_blend)
        if col.has_key('user_scheme') and \
           col['user_scheme'] == ['Edited scheme']:
          del col['user_scheme']
          

    #print "model_colour.colparams col",col
    return col


#------------------------------------------------------------------
  def getIcon(self):
#------------------------------------------------------------------
    return self.colour_icon

#------------------------------------------------------------------
  def getLabel(self):
#------------------------------------------------------------------
    return self.colour_label


#------------------------------------------------------------------
  def set_do_recolour(self,**args):
#------------------------------------------------------------------
    self.do_recolour = 2
        
#------------------------------------------------------------------
  def set_colour ( self, colparams={},colour_mode='',non_C_atomtype='',
      colour_blend = {}, one_colour = '', stick_colour='', **keywords):
#-----------------------------------------------------------------
    #print "model_colour.set_colour colparams",colour_mode,colparams,one_colour

    col = ''

    if colour_blend:
      self.colour_blend.update(colour_blend)
      #print "set_colour colour_blend",self.colour_blend
    if stick_colour:
      self.stick_colour = stick_colour
       
    if colparams:

      # Update from pre-2.0 'atom_buried' or 'res_buried' become 'interface' mode
      if ['res_buried','atom_buried'].count(colparams.get('colour_mode','')):
        colparams['colour_mode'] = 'interface'
        colparams['interface_style'] = ['ATOM','RESIDUE'][colparams['colour_mode']=='res_buried']
        obj_list = get_dispobj(name=colparams.get('contact_MolDisp',''))
        if obj_list:                      
          colparams['interface_selection'] = obj_list[0].SelHandle.getCommand()
          colparams['interface_MolData'] = obj_list[0].parent.name
        #print "model_colour.init colparam after buried updated",colparams
                                          
      
      # Updating to use colour_blend attribute
      if colparams.has_key('colour_blend_ranges_first'):
        for key in model_colour.colour_blend_order:
          if colparams.has_key('colour_blend_'+key):
            self.colour_blend[key] = colparams['colour_blend_'+key]
            del colparams['colour_blend_'+key]

      # Updating to v2.0 - use selection_command instead of ranges
      if colparams.has_key('colour_blend') and colparams['colour_blend'].has_key('ranges_first'):
        colour_blend = {}
        colour_blend.update(model_colour.colour_blend_initialisation)
        colour_blend.update(colparams['colour_blend'])
        colour_blend['selection_command'] = []
        for ii in range(0,len(colour_blend['ranges_first'])):
          # convert to a cid
          rv = self.MolData.interpretRanges(
            ranges_first=colour_blend['ranges_first'][ii],
            ranges_last= colour_blend['ranges_last'][ii])
          #print "colour_blend ranges",ii,colour_blend['ranges_first'][ii],colour_blend['ranges_last'][ii],rv
          if rv[1]:
            colour_blend['selection_command'].append(rv[1])
          else:
            colour_blend['selection_command'].append('all')
        colparams['colour_blend'] = colour_blend
        
      #one colour
      if not colparams.get('colour_mode','') and colparams.get('one_colour',''):
        colparams['colour_mode'] = 'one_colour'

      if colparams.has_key('user_colour_rules') and not colparams.has_key('colour_rules'):
        colparams['colour_rules'] = colparams['user_colour_rules']
        del colparams['user_colour_rules']

      if ['user','colour_rules'].count(colparams.get('colour_mode','')):
        colparams['colour_mode'] = 'rules'
            
      for item in colparams.keys():
        if item == 'colour_blend':
          self.colour_blend.update(colparams['colour_blend'])
        elif item == 'force_recolour_bymol':
          pass
        else:
          setattr(self,item,colparams[item])

      # stick colour
      if not stick_colour: stick_colour = colparams.get('stick_colour')

 
    #print "non_C_atomtype",non_C_atomtype,"self",self.non_C_atomtype
    # Beware restoring from pickle file from before colour_blend_direction
    if len(self.colour_blend['selection_command']) > len(self.colour_blend['direction']):
      for i in range(len(self.colour_blend['direction']),len(self.colour_blend['selection_command'])+1):
        self.colour_blend['direction'].append('clockwise')
    if ( non_C_atomtype != '' and int(non_C_atomtype) != self.non_C_atomtype):
      self.non_C_atomtype = int(non_C_atomtype)
      self.do_recolour = max(1,self.do_recolour)

       

    elif colour_mode:
      self.colour_mode = colour_mode
      self.one_colour = ''
        
    if one_colour:
      #print "set_colour",one_colour
      if MGCOLOUR().index(one_colour)>=0:
        self.colour_mode = 'one_colour'
        self.one_colour = one_colour
      else:
        self.colour_mode = 'one_colour'
        self.one_colour = 'default'
      self.colour_legend = self.html_span('All atoms',one_colour)
      self.do_recolour = 2
      
# If colouring bymol make sure we have colours defined
# for this molecule
    if self.colour_mode == 'bymol' and self.MolData:
      self.colour_mode = 'one_colour'
      force_recolour_bymol = colparams.get('force_recolour_bymol',False)
      self.one_colour = self.MolData.get_attribute('molecule_colour',force_recolour_bymol=force_recolour_bymol)
      self.colour_legend = self.html_span(self.MolData.name_label,self.MolData.mol_colour,newline=1)

          
    if self.colour_mode == 'one_colour':
      import copy
      self.colour_label=copy.deepcopy(self.one_colour)
    elif self.colour_mode in self.custom_colour_commands_methods and self.colour_mode in self.custom_colour_commands_labels:
         #print "Custom colouring method",self.colour_mode
         self.colour_label=self.custom_colour_commands_labels[self.colour_mode]
    elif self.colour_mode == 'electrostatic':
      self.colour_label='electrostatic'
    else:
      col = self.colour_mode
      alias = utils.equivKeyword(self.colour_mode, \
               self.colour_commands, self.colour_menu)
      self.colour_label=alias
       
    if col == 'rules':
        user_scheme = colparams.get('user_scheme','')
        if user_scheme: self.user_scheme = user_scheme
        #print "set_colour unravelling",self.user_scheme,self.colour_rules
        if self.user_scheme and self.user_scheme!=['Edited scheme']:
          if self.colour_rules:
          # Make sure these rules are in ModelInfo - might not be
          # if loaded from pic def etc.
            #print "loading user_colour_schemes",self.user_scheme
            status=MODELINFO().add_info(set=self.user_scheme[1], 
              info='user_colour_schemes',key=self.user_scheme[0],
                                            value=self.colour_rules)
          else:
            # Try getting scheme out of ModelInfo
            rv,scheme = MODELINFO().get_info(set=self.user_scheme[1],
               info='user_colour_schemes',key=self.user_scheme[0],first=1)
            #print "testing user_scheme",rv,scheme
            if not rv and scheme.has_key(self.user_scheme[0]):
              self.colour_rules = scheme[self.user_scheme[0]]
            else:
              self.colour_mode = 'atomtype'

        if self.user_scheme:
          self.colour_label = self.user_scheme[0]
        else:
          self.colour_label = 'Edited scheme'
        self.do_recolour = max(1,self.do_recolour)

    self.colour_icon = None
    if self.colour_mode == 'one_colour':
       self.colour_icon = self.one_colour
    if self.colour_mode and self.colour_mode in self.colour_commands_icons:
      #print 'self.colour_mode',self.colour_commands_icons[self.colour_mode]
      self.colour_icon = self.colour_commands_icons[self.colour_mode]
    if self.colour_icon:
      if os.path.exists(os.path.join(os.environ['CCP4MG'],'qticons','disptab','colour',self.colour_icon)):
         self.colour_icon = os.path.join(os.environ['CCP4MG'],'qticons','disptab','colour',self.colour_icon)
      #self.colour_icon = None

    self.do_recolour = 2


#----------------------------------------------------------------------
  def create_user_colour_definitions(self):
#----------------------------------------------------------------------

      if ['atomtype','bychain','bymodel','restype','mainside','secstr','altloc'].count(self.colour_mode) or self.one_colour:
        self.user_scheme = ['Edited scheme']
        rv =  self.generate_colour_rules( ifcommand=1,
          mode=self.colour_mode, non_C_atomtype=self.non_C_atomtype)
        #print "apply_colour generate_colour_rules",rv
        if rv:
          self.colour_rules,self.colour_legend = rv
       
      if not self.colour_rules:
          self.colour_rules = [['grey','']]
          self.colour_legend = ''

#----------------------------------------------------------------------
  def get_colour_schemes(self,set='',label=''):
#----------------------------------------------------------------------
    pars = {}
    retval,defn = MODELINFO().get_info(set = self.MolData.name_label,info='user_colour_schemes')
    if retval: pars[self.MolData.name_label] = defn.keys()
    retval,defn = MODELINFO().get_info(set = 'generic',info='user_colour_schemes')
    if retval: pars[generic] = defn.keys()
    return pars
  
#----------------------------------------------------------------------
  def save_colour_scheme(self,set='',label='',rules=[]):
#----------------------------------------------------------------------
    if not set: set = self.MolData.name_label
    
    status=MODELINFO().add_info(set=set,info='user_colour_schemes',
                                key=label,value=rules)
    return status
  
#----------------------------------------------------------------------
  def restore_colour_scheme(self,set=[],label='',ifapply=1):
#----------------------------------------------------------------------

    if not set: set = [self.MolData.name_label,'generic']
    retval,defn = MODELINFO().get_info(set = set,info='user_colour_schemes',key=label)
    #print 'restore_colour_scheme',retval,defn 

    if ifapply and not retval:
      self.set_colour(colour_mode='rules',colparams={
        'user_scheme' : [label,set],
        'colour_rules' : defn[label] } )
      
       
#----------------------------------------------------------------------
  def remove_colour_scheme(self,set=[],label=''):
#----------------------------------------------------------------------

    if not set: set = [self.MolData.name_label]
    status =  MODELINFO().delete_info(info='user_colour_schemes',
          set=set,key=label)

  def colour_data_listable(self):
    return ['atom_sas','res_sas','interface','secstr'].count(self.colour_mode)
 
    
#----------------------------------------------------------------------
  def list_colour_data(self,**keywords):
#----------------------------------------------------------------------
    #print "list_colour_data"
    if not ['atom_sas','res_sas','interface','secstr'].count(self.colour_mode):
      return [1,'No listing for ',self.colour_mode]

    title = self.colour_menu[self.colour_commands.index(self.colour_mode)]+' '+os.path.splitext(os.path.split(self.MolData.filename[2])[1])[0]
    text = self.colour_menu[self.colour_commands.index(self.colour_mode)]  + " for " + self.MolData.filename[2] + '\n\n'
    
    if ['res_sas','atom_sas'].count(self.colour_mode):
      text = text + self.MolData.CSASArea.Print(0)
      
      
      selHnd_1 = -1
      selHnd_2 = -1
      selection_1 = PM('SASArea_param').get('list_selection_1')
      selection_2 = PM('SASArea_param').get('list_selection_2')
      if selection_1:
        rv = self.MolData.parse_selection(command=selection_1)
        if not rv[0]: selHnd_1=rv[1]
      if selection_2:
        rv = self.MolData.parse_selection(command=selection_2)
        if not rv[0]: selHnd_2=rv[1]      
      text = text + self.MolData.CSASArea.Print(0,selection_1,selHnd_1,selection_2,selHnd_2)
      if selHnd_1>=0: self.MolData.molHnd.DeleteSelection(selHnd_1)
      if selHnd_2>=0: self.MolData.molHnd.DeleteSelection(selHnd_2)
      
      
    elif self.colour_mode=='interface':
      
      # !!!! Needs SORTING !!!!!!
      text = self.interface.list_colour_data()
    elif self.colour_mode == "secstr":
      text = text + self.MolData.molHnd.PrintSecStructure()
    else:
      return [1,'No listing for ',self.colour_mode]
    
    return [0,text,title]
    
#------------------------------------------------------------------
  def apply_colour(self):
#------------------------------------------------------------------
    # If no atoms selected then just reset and return

    if not self.do_recolour: return 0
    failed = 0

    if len(self.user_selHnds)>0:
      for sel in self.user_selHnds: self.MolData.molHnd.DeleteSelection(sel)
      self.user_selHnds = []
    if self.colour_mode == 'rules':
      # If rules currently being editted they are held in self.colour_rules
      rules = []
      if hasattr(self,'colour_rules'):
        rules = self.colour_rules
      else:
        status,user_colour_schemes=MODELINFO().get_info( \
          set=self.user_scheme[1],info='user_colour_schemes', \
                    key=self.user_scheme[0])
        #print "from get_info",status,user_colour_schemes
        if not status and user_colour_schemes:
          rules = user_colour_schemes[self.user_scheme[0]]
      if rules:                  
        self.apply_colour_rules(rules)
        self.colour_legend = self.colour_rules_legend(rules)
      else:
        failed = 1
        self.colour_mode = 'atomtype'


    elif self.colour_mode == 'blend':
      rv = self.apply_colour_blend(
            selection_command = self.colour_blend['selection_command'],
            colours = self.colour_blend['colours'],
            direction = self.colour_blend['direction'],
            default_colour=self.colour_blend['default_colour'],
            type=self.colour_blend['type'],group=self.colour_blend['group'])
      
      if not rv:
        self.colour_legend = 'Blend through model'
      else:
        self.colour_mode = 'atomtype'
        failed = 1
        
    # beware possiblity of failure of user colour (eg deleted .ccp4mg
    if self.colour_mode != 'rules':
      if self.non_C_atomtype:
        non_C_mode = mgapp.BYATOMTYPE
      else:
        non_C_mode = -1
      #print "apply_colour non_C_mode",non_C_mode


      # Calculate SAS/Contact area or load charge
      if ['res_sas','atom_sas'].count(self.colour_mode):
        if self.do_recolour>=2:
          rv = self.MolData.update_sasarea(reapply=0)
          # return 0=OK, 1=interrupted 2=failed
          if rv:
            if rv>1: MGGUI().WarningMessage( \
              'Error calculating SAS for '+self.MolData.name)
            failed = 1
            self.colour_mode = 'atomtype'
          else:
            udd_atom = self.MolData.molHnd.GetUDDHandle( mmdb.UDR_ATOM,"atom_sas")
            udd_res = self.MolData.molHnd.GetUDDHandle( mmdb.UDR_RESIDUE,"residue_sas")
            #print "SetUDD",udd_atom,udd_res
            self.CMolColour.SetUDD(udd_atom,udd_res)
            code =  self.colour_code[self.colour_commands.index(self.colour_mode)]
            #print "CMolColour.SetMode code",code
          RC = self.CMolColour.SetMode (2, code,  non_C_mode)
        
      elif self.colour_mode in self.custom_colour_commands_methods:
         #print "Custom method", self.colour_mode, self.custom_colour_commands_methods[self.colour_mode]
         #self.atomColourVector = self.CMolColour.GetAtomColourVector()
    
         ret = self.custom_colour_commands_methods[self.colour_mode](self)
         self.do_recolour = 0

         if hasattr(ret,'has_key') and ret.has_key('success') and ret['success']:
           self.atomColourVector = ret['atom_colour_vector']

           #This is probably the right time to update dependent object
           try:
             self.update_dependents('colour')
           except:
             pass

           return 1
         else:
           failed = 1
           self.colour_mode = 'atomtype'
           self.colour_label = 'Atom type'

      elif self.colour_mode == 'interface':
        if self.do_recolour>=2:
          if not hasattr(self,'interface'):
            self.interface = Interface(name='contact',MolData_name=self.MolData.name)
            
          self.interface.set(selection=self.SelHandle.getCommand(),contact_selection=self.interface_selection,contact_MolData_name=self.interface_MolData_name)
          rv = self.interface.calculate()
          if (not rv[0]) and self.interface.contact_UDD:
            self.CMolColour.SetUDD(self.interface.contact_UDD[0],self.interface.contact_UDD[1])
            RC = self.CMolColour.SetMode (self.do_recolour-1,
             [mgapp.CONTACTRES,mgapp.CONTACTATOM][['RESIDUE','ATOM'].index(self.interface_style)] ,non_C_mode)
          else:
            print "ERROR calculating interface "+rv[1]
            failed = 1
            self.colour_mode = 'atomtype'
      elif ['charge'].count(self.colour_mode):
        if not self.MolData.charge_loaded:
          self.MolData.molHnd.LoadCharge("surface_potential_charge")
          self.MolData.charge_loaded = 1
        RC = self.CMolColour.SetMode (self.do_recolour-1,mgapp.CHARGE,non_C_mode)
      elif['atomtype','bychain','bymodel','restype','mainside','secstr','altloc'].count(self.colour_mode):
          rv = self.generate_colour_rules(mode=self.colour_mode,
                                        non_C_atomtype=self.non_C_atomtype)
          if not rv:
            failed = 1
            self.colour_mode = 'atomtype'
          rules,self.colour_legend = rv
          self.apply_colour_rules(rules)
      elif self.colour_mode == 'one_colour':
      # Does the colour command correspond to a recognised colour
        ic = MGCOLOUR().index(self.one_colour)
        if ic>=0:
          self.CMolColour.SetOneColour(ic)
          RC = self.CMolColour.SetMode (self.do_recolour-1, \
             mgapp.ONECOLOUR,non_C_mode)
        else:
          failed = 1
      elif model_colour.colour_commands.count(self.colour_mode):
        try:
          mode = model_colour.colour_code[model_colour.colour_commands.index(self.colour_mode)]
          #print "other mode",self.colour_mode,mode
          RC = self.CMolColour.SetMode (self.do_recolour-1,mode,0)
        except:
          failed = 1

    # If failed revert to atom type colour
    if failed:
      self.colour_mode = 'atomtype'
      self.colour_label='Atom type'
      self.CMolColour.SetMode(1,mgapp.BYATOMTYPE,0)

    self.CMolColour.ReColour()
    self.atomColourVector = self.CMolColour.GetAtomColourVector()
    #print "apply_colour atomColourVector",self.atomColourVector
    
    self.do_recolour = 0

    #This is probably the right time to update dependent object
    try:
      self.update_dependents('colour')
    except:
      pass

    return 1

#----------------------------------------------------------------------
  def colour_rules_legend ( self, rules=[]):
#---------------------------------------------------------------------
    import types,model_selection
    parser = model_selection.SelectionParser()
    legend = self.html_span('User colour rules','',newline=1)
    for rule in rules[1:]:
      if isinstance(rule[1],types.ListType):
        rv,com = parser.list_to_command(rule[1])
      else:
        com = rule[1]
      #print 'colour_rules_legend',com
      legend = legend + self.html_span(com[0:min(25,len(com))],rule[0],newline=1)
    return legend
        
#----------------------------------------------------------------------
  def apply_colour_rules ( self, rules=[]):
#---------------------------------------------------------------------
    '''
    Apply a selection based colour rules
    '''
    #print "apply_colour_rules",rules
    import pygl_coord,types
    #for rule in rules: print "RULE:",rule
    colours = []
    for rule in rules[1:]:
      if rule[1]:
        if isinstance(rule[1],types.ListType):
          status,sel = self.MolData.parse_selection(defn=rule[1])
        else:
          status,sel = self.MolData.parse_selection(command=rule[1])
        #print "model_colour.apply_colour_rules status,sel",rule[1],status,sel, self.MolData.nAtoms(sel)
        if status:
          print "ERROR parsing ",rule[1]
        else:
          self.user_selHnds.append(sel)
          import cprim
          #colours.append(MGCOLOUR().index(rule[0]))
          colours.append(cprim.RGBReps.GetColourNumber(rule[0]))

    #print 'model_colour.apply_colour_rules colours',colours
    # Beware may exclude rules with no selection
    nrules = len(self.user_selHnds)
    
    ptr_selHnds = pygl_coord.inta(nrules)
    ptr_colour =  pygl_coord.inta(nrules)
    i = -1
    for sel in self.user_selHnds:
      i = i + 1
      ptr_selHnds[i] = sel
    i = -1
    for col in colours:
      i = i + 1
      ptr_colour[i] = col

    RC = self.CMolColour.SetMode (1,0,-1)
    #print rules
    self.CMolColour.SetScheme(nrules,MGCOLOUR().index(rules[0][0]), \
                                          ptr_selHnds,ptr_colour)

#----------------------------------------------------------------------
  def apply_colour_blend ( self,default_colour='white',selection_command=[],
                           colours=[],direction=[],
                           group='residue',type='amino_acid'):
#---------------------------------------------------------------------
    '''
    Apply a selection based colour rules - logically part of apply_colour method
    '''
    import atom_util

    #print "apply_colour_blend selection_command",selection_command,colours
  
    if ['amino_acid','nucleic'].count(type):
      status,sel_type = self.MolData.parse_selection(defn=[None,type])
      if status: sel_type = None 
      #print "apply_colour_blend status,sel_type",status,type,sel_type,self.parent.nAtoms(sel_type)
    else:
      sel_type = None

    cols = [MGCOLOUR().index(default_colour)]
    selHnds = [-1]
    direction = [atom_util.COLOUR_WHEEL_CLOCK]
    for i in range(0,min(len(selection_command),len(colours))):
      sel = -1
      if selection_command[i]:
        rv = self.MolData.parse_selection(command=selection_command[i],test=1)
        if not rv[0] and rv[1]>0:
          rv = self.MolData.parse_selection(command=selection_command[i])
          sel = rv[1]
          #if sel_type:
          #  self.MolData.molHnd.Select(sel,mmdb.STYPE_ATOM,sel_type,mmdb.SKEY_AND)
          #  nat = self.MolData.nAtoms(sel)

      if sel>0:
        self.user_selHnds.append(sel)
        selHnds.append(sel)
        if self.colour_blend['direction'][i] == 'clockwise':
          direction.append(atom_util.COLOUR_WHEEL_CLOCK)
        else:
          direction.append(atom_util.COLOUR_WHEEL_ANTICLOCK)
        cols.append(MGCOLOUR().index(colours[i][0]))
        for col in colours[i][1:]:
          if col:
            cols.append(MGCOLOUR().index(col))
            selHnds.append(-1)
            if self.colour_blend['direction'][i] == 'clockwise':
              direction.append(atom_util.COLOUR_WHEEL_CLOCK)
            else:
              direction.append(atom_util.COLOUR_WHEEL_ANTICLOCK)
            
    if sel_type: self.MolData.molHnd.DeleteSelection(sel_type)

    # Do we actually have some selected residues
    if len(selHnds)<=1: return 1
    
    cols.append(MGCOLOUR().index(default_colour))
    selHnds.append(-1)
    #print "cols",cols,'selHnds',selHnds
    
    # Beware may exclude rules with no selection
    nrules = len(selHnds)
    import pygl_coord
    ptr_selHnds = pygl_coord.inta(nrules)
    ptr_colour =  pygl_coord.inta(nrules)
    i = -1
    for sel in selHnds:
      i = i + 1
      ptr_selHnds[i] = sel
    i = -1
    for col in cols:
      i = i + 1
      ptr_colour[i] = col

    
    if self.blend_group_menu.count(group):
      group_code = self.blend_group_code[self.blend_group_menu.index(group)]
    else:
      group_code = mgapp.BLEND_RESIDUE
    #print "apply_colour_blend nrules",nrules,'group_code',group_code,'BLEND_RESIDUE',BLEND_RESIDUE
    
    self.CMolColour.SetColourWheelDirection(direction)
    self.CMolColour.SetScheme(nrules,MGCOLOUR().index(default_colour), \
                                      ptr_selHnds,ptr_colour,group_code)
    RC = self.CMolColour.SetMode (1,mgapp.BLENDTHRU,-1)
    return 0
  
#-------------------------------------------------------------------
  def handle_colour_change (self,name='',standard=0,rename='',delete=0):
#-------------------------------------------------------------------
    # Handle a redefinition of the colour with name 'name'
    # If the changed colour is one of the 'standard' colours
    # then just need to refresh the display
    # If the colour is user defined then it will only be used in
    # a user defined colour scheme - addition/deletion of colours
    # would require apply_colour

    if delete:
      rename = 'grey'
      
    if rename:
      #print "handle_colour_change",self,name,'*',rename,delete
      #print "self",self.one_colour,self.colour_mode
      if self.one_colour and self.one_colour == name:
        self.set_colour(one_colour=rename)
      elif self.colour_mode == 'blend' and self.colour_blend['colours']:
        jmax = len(self.colour_blend['colours'][0])
        for i in range(0,len(self.colour_blend['colours'])):
          for j in range(0,jmax):
            if self.colour_blend['colours'][i][j]==name:
              #print "handle_colour_change blend",i,j
              apply(self.set_colour_blend,[],{ \
                'widget' : 'colour'+str(j+1)+'_'+str(i+1),
                'colour'+str(j+1)+'_'+str(i+1) : rename } )
      elif  self.colour_mode == 'rules':
        if not hasattr(self,'colour_rules'):return
        #print "colour_rules",self.colour_rules
        for ii in range(0,len(self.colour_rules)):
          if self.colour_rules[ii][0] == name:
            #print "handle_colour_change ii",ii,self.user_colour_insts(str(ii))
            try:
              self.user_colour_insts(str(ii)).set_colour(colour=rename)
            except:
              pass
            
        
    else:
      #print "handle_colour_change do_updatedisplay",self
      self.do_updatedisplay = 1
      #if ['rules','blend'].count(self.colour):
      #Force the CMolColour class to redo colour
      if ['bvalue','occupancy','altloc','charge','res_sas','atom_sas', \
          'res_buried','atom_buried','thru_chain' ].count(self.colour_mode):
        self.CMolColour.SetMode(1)
        self.do_recolour = max(1,self.do_recolour)

    
#---------------------------------------------------------------------
  def update_contact(self,master = '',**keywords):
#---------------------------------------------------------------------
    self.do_recolour = 2



#-------------------------------------------------------------------------
  def generate_colour_rules ( self, mode='',non_C_atomtype=0,ifcommand=0):
#-------------------------------------------------------------------------
    '''
    Generate the rules for standard colouring schemes applied to this model
    '''
    #print "generate_colour_rules mode",mode,self.molecule_type
    if model_colour.colour_commands.count(mode):
      legend_title = model_colour.colour_menu[model_colour.colour_commands.index(mode)]
      legend = '<p>' + self.html_span(legend_title,'',1)
    else:
      legend = '<p>'
    ifcom = ifcommand
    if ifcom:
      rules = [['grey', 'all', {'select':'all'} ] ]
    else:
       rules = [['grey', [None,'all'], {'select':'all'} ] ]
    col = 'yellow'
    if mode == 'bychain':
      peptides = self.MolData.peptides
      if not hasattr(MGCOLOUR(),"usingOldColours") or not MGCOLOUR().usingOldColours:
         col = 'default'
      if len(peptides)>0:
        for n in range(0,len(peptides)):
          col = MGCOLOUR().next(col, \
                    exclude=['black','white','red','blue','green'])
          sel = peptides[n]
          if not sel : sel=sel+' /*'
          if ifcom:
            rules.append ( [  col,
                       '//'+sel,
                       { 'select' : 'amino_acid' , \
                         'chains' : ['//'+peptides[n]] }  ] )
          else: 
            rules.append ( [  col,
                       [None,'//'+sel],
                       { 'select' : 'amino_acid' , \
                         'chains' : ['//'+peptides[n]] }  ] )
          legend = legend + self.html_span(peptides[n],col)
        legend=legend+ self.html_span('Not peptide','grey')

      nucleics = self.MolData.nucleics
      if len(nucleics)>0:
        for n in range(0,len(nucleics)):
          col = MGCOLOUR().next(col, \
                       exclude=['black','white','red','blue','green'])
          if ifcom:
            rules.append ( [  col,
                       'nucleic and //'+nucleics[n]+'/*.*/*:*',
                       { 'select' : 'nucleic' , 'strands' : ['//'+nucleics[n]] }  ] )
          else:
            rules.append ( [  col,
                       ['and', [None,'nucleic'],[None,'//'+nucleics[n]+'/*.*/*:*' ]],
                       { 'select' : 'nucleic' , 'strands' : ['//'+nucleics[n]] }  ] )
          legend=legend+self.html_span(nucleics[n],col)
        #rules.append(['white',
        #          ['not',[None,'nucleic_acid']],
        #          { 'select' : 'nucleic' , 'notselect' : 1 } ] )
        
    elif mode == 'bymodel':
      col = ''
      #generate rules for the number of nmr models
      nmr_models = self.MolData.nmr_models
      if nmr_models:
        n_models = nmr_models
      else:
        n_models = 1
      for m in range(self.MolData.first_nmr_model,n_models+1):
        col = MGCOLOUR().next(col, \
                    exclude=['black','white','red','blue'])
        sele = '/'+str(m)+'/*/*,*/*:*'
        if ifcom:
          rules.append([ col,
                     sele,
                     { 'select' : 'nmr_models', 'nmr_models' : ['/'+str(m)] } ] )
        else:
           rules.append([ col,
                     [None,sele],
                     { 'select' : 'nmr_models', 'nmr_models' : ['/'+str(m)] } ] )
        legend=legend+self.html_span(str(m),col)
      # rules for symmetry models
      symmetry_models = self.MolData.model_symmetry.get_symmetry_models()
      if symmetry_models:
        symmetry_colours = self.MolData.model_symmetry.get_symmetry_colours()
        nn = 0
        for m in symmetry_models:
          sele = m+'/*/*,*/*:*'
          if nn<len(symmetry_colours):
            colour = symmetry_colours[nn]
          else:
            colour = 'grey'
          if ifcom:
            rules.append([ colour,
                   sele,
                   { 'select' : 'nmr_models', 'nmr_models' : [m] } ] )
          else:
             rules.append([ colour,
                   [None,sele],
                   { 'select' : 'nmr_models', 'nmr_models' : [m] } ] )
           
          legend=legend+self.html_span(str(m), colour)
          n_models = n_models + 1
          nn = nn + 1

    elif mode == 'restype':
      import services,string
      colobj = services.colourschememanager('restype')
      if not colobj: return []
      ntype,typelist,collist = colobj.GetColourScheme()

      if  typelist.count('*'):
        ii =  typelist.index('*')
        typelist.pop(ii)
        collist.pop(ii)

      # Aggregate all res of same colour into one selection
      ty = []
      cl = []
      for i in range(0,len(collist)):
        if cl.count(collist[i]):
          j = cl.index(collist[i])
          ty[j].append(typelist[i])
        else:
          cl.append(collist[i])
          ty.append([typelist[i]])

      for i in range(0,len(cl)):
        res = string.strip(ty[i][0])
        if len(ty[i])>1:
          for item in ty[i][1:]:
            res = res+','+ string.strip(item)
        if ifcom:
          rules.append ( [ cl[i],
                       '('+res+')',
              { 'select' : 'restypes' , 'restypes' : ty[i]}  ] )
        else:
          rules.append ( [ cl[i],
                       [None,'('+res+')'],
              { 'select' : 'restypes' , 'restypes' : ty[i]}  ] )
     
        legend=legend+self.html_span(res,cl[i])
      '''  
      for col,reslist in [
           [ 'magenta' , ['PHE','TRP','TYR'] ],
           ['coral', ['PRO','VAL','ALA','ILE','LEU']],
           ['cyan',['SER','THR','ASN','GLN']],
           ['blue',['ARG','LYS']],
           ['red',['ASP','GLU']],
           ['yellow',['CYS','MET']],
           ['grey',['GLY']],
           ['light blue',['HIS']],
           ['red',['A']],
           ['yellow',['T']],
           ['green',['G']],
           ['blue',['C']],
           ['magenta',['U']] ]:
        sele = reslist[0]
        for res in reslist[1:]: sele = sele + ','+res
        rules.append ( [ col,
                       [None,'('+sele+')'],
                       { 'select' : 'restypes' , 'restypes' : reslist }  ] )
        '''
    elif mode == 'mainside':
      if self.MolData.molecule_type.count('PROTEIN'):
        if hasattr(MGCOLOUR(),"usingOldColours") and MGCOLOUR().usingOldColours:
          if ifcom:
            rules.extend( [ [ 'yellow', 'main', { 'select' : 'main' } ],
                        [ 'cyan', 'side', { 'select' : 'side' } ] ])
          else:
            rules.extend( [ [ 'yellow', [None,'main'], { 'select' : 'main' } ],
                        [ 'cyan', [None,'side'], { 'select' : 'side' } ] ])
          
          legend=legend+self.html_span('main chain','yellow')
          legend=legend+self.html_span('side chain','cyan')
        else:
          if ifcom:
            rules.extend( [ [ 'lemon', 'main', { 'select' : 'main' } ],
                        [ 'ice blue', 'side', { 'select' : 'side' } ] ])
          else:
            rules.extend( [ [ 'lemon', [None,'main'], { 'select' : 'main' } ],
                        [ 'ice blue', [None,'side'], { 'select' : 'side' } ] ])
          
          legend=legend+self.html_span('main chain','lemon')
          legend=legend+self.html_span('side chain','ice blue')

      elif self.MolData.molecule_type.count('NUCLEIC'):
        if ifcom:
          rules.extend( [ \
          [ 'lemon', 'backbone', { 'select' : 'backbone' } ],
          [ 'ice blue', 'bases', { 'select' : 'bases' } ] ])
        else:
          rules.extend( [ \
          [ 'lemon', [None,'backbone'], { 'select' : 'backbone' } ],
          [ 'ice blue', [None,'bases'], { 'select' : 'bases' } ] ])
        legend=legend+self.html_span('backbone','lemon')
        legend=legend+self.html_span( 'bases','ice blue')
        
    elif mode == 'secstr':
      import services
      import model
      colobj = services.colourschememanager('secstr')
      if not colobj: return []
      scheme = colobj.GetColourScheme()
      #print scheme
      for i in range(scheme[0]):
       if i < len(model.MolData.secstr_alias) and i<len(model.MolData.secstr_menu):
        alias = model.MolData.secstr_alias[i]
        name = model.MolData.secstr_menu[i]
        #rules.extend( [ [ scheme[2][i], [None,'SEC == '+str(scheme[1][i])],
        #                { 'select' : 'amino_acid', 'secstr' : [alias] } ]
        #                ])
        if ifcom:
          rules.extend( [ [ scheme[2][i], 'SEC == '+alias,
                        { 'select' : 'amino_acid', 'secstr' : [alias] } ]
                        ])
        else:
          rules.extend( [ [ scheme[2][i], [None,'SEC == '+alias],
                        { 'select' : 'amino_acid', 'secstr' : [alias] } ]
                        ])
        legend=legend+self.html_span(name,scheme[2][i])

    elif mode == 'altloc':
      alt_loc_col = ['cyan','pink','lemon','tan']
      for ii in range(0,len(self.MolData.alt_locs)):
        if ifcom:
          rules.extend( [ [ alt_loc_col[ii], '/*/*/*.*/*:'+self.MolData.alt_locs[ii],
                        { 'select' : 'all', 'alt_locs' : [self.MolData.alt_locs[ii]] } ]
                        ])
        else:
          rules.extend( [ [ alt_loc_col[ii], [None,'/*/*/*.*/*:'+self.MolData.alt_locs[ii]],
                        { 'select' : 'all', 'alt_locs' : [self.MolData.alt_locs[ii]] } ]
                        ])
        legend=legend+ self.html_span(self.MolData.alt_locs[ii],alt_loc_col[ii])
      
    elif MGCOLOUR().colour_index(mode,safe=0)>=0:
      # Mode is one colour
      if ifcom:
        rules.append ( [ mode ,'all', { 'select':'all' }] )
      else:
        rules.append ( [ mode , [None,'all'], { 'select':'all' }] )
        
    if mode == 'atomtype' or non_C_atomtype:
      import services,string
      colobj = services.colourschememanager('atomtype')
      if not colobj: return []
      ntype,elelist,collist = colobj.GetColourScheme()
      if  elelist.count('*'):
        ii =  elelist.index('*')
        elelist.pop(ii)
        collist.pop(ii)
      if mode != 'atomtype' and elelist.count(' C'):
        ii =  elelist.index(' C')
        elelist.pop(ii)
        collist.pop(ii)
      if len(self.MolData.alt_locs):
        alt = ':*'
      else:
        alt = ''
      for i in range(0,len( elelist)):
        ele = elelist[i].strip('[] ')
        if ifcom:
          rules.append ( [ collist[i],
                       '['+ele+']'+alt,
              { 'select' : 'elementtypes' , 'elementtypes' : [ele]}  ] )
        else:
          rules.append ( [ collist[i],
                       [None,'/*/*/*,*/*['+ele+']'+alt],
              { 'select' : 'elementtypes' , 'elementtypes' : [ele]}  ] )
        legend=legend+self.html_span(ele+' ',collist[i])

    # The end
    #print "generate_colour_rules",rules
    return [rules,legend+'</p>']
  
#-------------------------------------------------------------------------
  def html_span(self,text,colour='',newline=0):
#-------------------------------------------------------------------------
    open_span0='<span style="color:'
    open_span1=';">'
    close_span='</span>\n'
    text = open_span0+colour+open_span1+text+' '+close_span
    if newline: text = text + '</p><p>'
    return text

#--------------------------------------------------------------------
  def getLegend(self):
#--------------------------------------------------------------------
    legend = \
'''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" />
<style type="text/css">
p { white-space: pre-wrap; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;}
</style>
</head><body><p>''' + self.colour_legend +'</p></body></html>'
    print 'model_colour.getLegend',legend
    return legend

#--------------------------------------------------------------------
class Interface:
#--------------------------------------------------------------------

  def __init__(self,name='',MolData_name='',selection='',contact_MolData_name='',contact_selection=''):
    # MolData_name is the name of 'self'
    self.name = name
    self.MolData_name = MolData_name
    self.selection = selection
    self.contact_MolData_name=contact_MolData_name
    self.contact_selection=contact_selection
    self.contact_UDD = []

#------------------------------------------------------------------------
  def delete(self):
#------------------------------------------------------------------------
    pass
    # Possibly clean up UDDs?

#------------------------------------------------------------------------
  def set(self,contact_selection='XXX',selection='XXX',contact_MolData_name=''):
#------------------------------------------------------------------------
    if contact_selection!='XXX':
      self.contact_selection = contact_selection
    if selection!='XXX':
      self.selection = selection
    if contact_MolData_name:
      self.contact_MolData_name = contact_MolData_name
    
#----------------------------------------------------------------------
  def calculate(self,**keywords):
#----------------------------------------------------------------------
    # Updated selection of the contacting object
    # NB called from dependency master with arguments so needs keywords
    selHnd = -1
    contact_selHnd = -1
    
    #print "Interface.calculate",self.selection,'*',self.contact_selection
    # Get the molHnd for 'self'
    obj = get_dataobj(name=self.MolData_name)
    if not obj: return [1,'Invalid model '+self.MolData_name]
    MolData = obj[0]
    molHnd = obj[0].molHnd

    #Get the molHnd for other
    if self.contact_MolData_name:
      obj = get_dataobj(name=self.contact_MolData_name)
      if not obj: return [1,'Invalid model '+self.contact_MolData_name]
      contact_MolData = obj[0]
      contact_molHnd = obj[0].molHnd
    else:
      contact_MolData = MolData
      contact_molHnd = molHnd


    if MolData == contact_MolData:
      # 'Other' set of atoms is in same model - get the set of atoms not in other
      if not self.selection and not self.contact_selection:
        return [1,'No atom selection']
      elif not self.selection:
        rv = MolData.parse_selection(command=self.contact_selection)
        if rv[0]: return [1,'Invalid selection '+self.contact_selection]
        contact_selHnd = rv[1]
        selHnd = molHnd.NewSelection()
        molHnd.SelectAtoms(selHnd, 1,"*",mmdb.ANY_RES,"*",mmdb.ANY_RES,"*",
                               "*","*","*","*", mmdb.SKEY_NEW)
        molHnd.Select(selHnd,mmdb.STYPE_ATOM,contact_selHnd,mmdb.SKEY_XOR)
        
      elif not self.contact_selection:
        rv = MolData.parse_selection(command=self.selection)
        if rv[0]: return [1,'Invalid selection '+self.selection]
        selHnd = rv[1]
        contact_selHnd = molHnd.NewSelection()
        molHnd.SelectAtoms(contact_selHnd, 1,"*",mmdb.ANY_RES,"*",mmdb.ANY_RES,"*",
                               "*","*","*","*", mmdb.SKEY_NEW)
        molHnd.Select(contact_selHnd,mmdb.STYPE_ATOM,selHnd,mmdb.SKEY_XOR)
      else:
        rv = MolData.parse_selection(command=self.selection)
        if rv[0]: return [1,'Invalid selection '+self.selection]
        selHnd = rv[1]
        rv = MolData.parse_selection(command=self.contact_selection)
        if rv[0]: return [1,'Invalid selection '+self.contact_selection]
        contact_selHnd = rv[1]
    else:
      #Contact to different model - just make surewe have some atoms selected
      if not self.selection:
        self.selection = 'all'
      rv = contact_MolData.parse_selection(command=self.selection)
      if rv[0]: return [1,'Invalid selection '+self.selection]
      selHnd = rv[1]

      if not self.contact_selection:
        self.contact_selection = 'all'
      rv = contact_MolData.parse_selection(command=self.contact_selection)
      if rv[0]: return [1,'Invalid selection '+self.contact_selection]
      contact_selHnd = rv[1]
        
    
    #print "Interface.calculate",MolData,MolData.nAtoms(selHnd),contact_MolData,contact_MolData.nAtoms(contact_selHnd)
    if MolData.nAtoms(selHnd)<0:
      return [1,"No atoms selected for ",self.selection]
    if contact_MolData.nAtoms(contact_selHnd)<0:
      return [1,"No atoms selected for ",self.contact_selection]

    if not self.contact_UDD:
      udd_atom = molHnd.RegisterUDReal(mmdb.UDR_ATOM,"atom_contact"+ self.name )
      udd_res = molHnd.RegisterUDReal(mmdb.UDR_RESIDUE,"residue_contact"+ self.name)
      self.contact_UDD=[udd_atom,udd_res]

    
    if not hasattr(self,'contact_CSASArea'):
      import mmut
      self.contact_CSASArea = mmut.CSASArea( molHnd,selHnd,contact_molHnd,contact_selHnd)
      self.contact_CSASArea.SetUDD(self.contact_UDD[0],self.contact_UDD[1])
    else:
      self.contact_CSASArea.SetSelHandle(1,contact_selHnd,contact_molHnd)
      self.contact_CSASArea.SetSelHandle(selHnd)

      
    #GUI.insts.StartInterrupt(gui='Stop area calculation')
    rv = self.contact_CSASArea.Calculate_Contact()
    #print "Interface.Calculate_Contact rv",self.name,rv
    #print self.contact_CSASArea.Print(0)
    #GUI.insts.EndInterrupt(gui='Stop area calculation')

    if selHnd>=0: molHnd.DeleteSelection(selHnd)
    if contact_selHnd>=0: contact_molHnd.DeleteSelection(contact_selHnd)
    
    if rv:
      return [1,'Error in calculation']
    else:
      return [0]
 
#----------------------------------------------------------------------
  def list_colour_data(self):
#----------------------------------------------------------------------
    if not self.contact_CSASArea:
      return ''
    text = '\nInterface to '+self.contact_selection+'\n'
        #text = text+"Buried area "  +selobj[1].MolData.filename[2]+ " :: " + \
          #[1].selection_label + "\nFull selection command: "+cid+"\n"
    text = text + self.contact_CSASArea.Print(0)
    return text
