"""
     python/ui/HBonds.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
import dataobj,model_selection
from global_definitions import *
import cprim,pygl_coord



#===================================================================
#===================================================================
#===================================================================
class HB_Contacts:
#===================================================================
#===================================================================
#===================================================================

  
#-----------------------------------------------------------------
  def __init__(self,selparams={'command':'all'},styleparams={},colparams={},params={},restore_from_version='',**kw):
#-----------------------------------------------------------------
    if not selparams: selparams['select']='all'
    if restore_from_version and restore_from_version[0]==1 and restore_from_version[1]<108:
          selparams = model_selection.fix_v108(selparams)
          styleparams = model_selection.fix_v108(styleparams)

    self.SelHandle1 = model_selection.SelHandle(self.parent.name,selparams=selparams,dispobj_name=self.name)
    if not styleparams: styleparams = { 'select' : 'same_as', 'same_as' : self.name }
    self.SelHandle2 = model_selection.SelHandle(self.parent.name,selparams=styleparams,dispobj_name=self.name)
    #print 'HBonds.init',selparams.get('chains'),styleparams.get('chains'),self.SelHandle1,self.SelHandle2
    self.Connectivity2 = None
    self.do_redraw = 2
    self.colour = 'complement'
    if colparams.has_key('colour'): self.colour = colparams['colour']

    pars = {}
    if params.has_key('line_width'):
      # This is from pre-2.0 when DrawingStylePM was introduced
      if params['line_width']<0:
        pars['line_width'] = 2
        pars['line_style'] = 'cylinders'
      else:
        pars['line_width'] = params['line_width']
        pars['line_style'] = 'lines'
      pars['label_mode'] = params.get('label_mode','')
      # Set drawing style if there is one    
    pm = self.getDrawingStylePM(name=params.get('drawing_style',''),params=pars)   
    pm.add_dependent(self.handleDrawingStylePM)

    import VectorsDispobj
    self.label_graphmod = VectorsDispobj.Vectorsgraphicsmodel()
    BUILD().append(self.label_graphmod)
    self.label_graphmod.obj.SetAlpha(self.opacity)
      
  def delete(self):
    self.closeDrawingStylePM(reset=0)    

  def set_reapply_selection(self,mode=2):
    #print 'HBContacts.set_reapply_selection',self
    self.do_redraw = mode

  def get_colour_icon(self):
    if os.path.exists(os.path.join(os.environ['CCP4MG'],'qticons','disptab','colour',self.colour+'.svg')):
       return os.path.join(os.environ['CCP4MG'],'qticons','disptab','colour',self.colour+'.svg') 
    if os.path.exists(os.path.join(os.environ['CCP4MG'],'qticons','disptab','colour',self.colour+'.png')):
       return os.path.join(os.environ['CCP4MG'],'qticons','disptab','colour',self.colour+'.png') 
    return self.colour

#------------------------------------------------------------------
  def params(self,all=1):
#------------------------------------------------------------------
    pars = dataobj.DispObj.params(self,all=all)
    if hasattr(self,'drawingStylePM'):
      pars['drawing_style'] = self.drawingStylePM.name
    return pars

#-----------------------------------------------------------------
  def styleparams(self,all=1):
#-----------------------------------------------------------------
    pars = self.SelHandle2.getSaveParams(all=all)
    #print 'HBonds.styleparams',self.SelHandle2,pars.get('name'),pars.get('chains'),pars.get('command')
    return pars

#-----------------------------------------------------------------
  def selparams(self,all=1):
#-----------------------------------------------------------------
    pars= self.SelHandle1.getSaveParams(all=all)
    #print 'HBonds.selparams',self.SelHandle1,pars.get('name'),pars.get('chains'),pars.get('command')
    return pars

#-----------------------------------------------------------------
  def colparams(self,all=1):
#-----------------------------------------------------------------
    pars = {}
    pars['colour'] = self.colour
    return pars

#------------------------------------------------------------------
  def update_data_status(self,shadowdisp):
#------------------------------------------------------------------
    import utils
    rv = 0

    diffs = utils.dict_diffs(self.selparams(),shadowdisp.selparams)[1]
    #print "selparams diffs",diffs
    if diffs:
      rv = 1
      self.do_redraw = 2
      self.SelHandle1.setSaveParams(diffs)
            
    if self.colour != shadowdisp.colparams['colour']:
      rv = 1
      self.set_colour(shadowdisp.colparams['colour'])

    diffs =  utils.dict_diffs(self.styleparams(),shadowdisp.styleparams)[1]
    #print "HBonds.styleparams diffs",diffs
    if diffs:
      rv = 1
      self.do_redraw = 2
      self.SelHandle2.setSaveParams(diffs)
      
    rv,diffs,undiffs = utils.dict_diffs(self.params(),shadowdisp.params)
    #"HBOnds.update_data_status",diffs,undiffs
    if diffs.has_key('drawing_style'):
        #Add a drawing style PM
        pm = self.getDrawingStylePM(name=diffs['drawing_style'],custom=1)
        #print "diffs drawing_style",pm.name,pm.params
        pm.add_dependent(self.handleDrawingStylePM)
        if self.label_graphmod: self.label_graphmod.setparams(parameters=pm)
        self.do_redraw = 1
        HISTORY().update_gui.append(['add_PM',diffs['drawing_style']])
        rv = 1

    if undiffs.has_key('drawing_style'):
      HISTORY().update_gui.append(['delete_PM',undiffs['drawing_style']])
      self.closeDrawingStylePM()
      self.do_redraw = 1
      rv = 1

    rv = max(rv,dataobj.DispObj.update_data_status0(self,shadowdisp))
    if rv: self.update_gui.append(['update'])
    return rv
    
#------------------------------------------------------------------------
  def canBeTransparent(self):
#------------------------------------------------------------------------
    return 1

 
#-------------------------------------------------------------------------
  def handle_moving_data(self,attribute='',master='',**keywords):
#-------------------------------------------------------------------------
    #print "HBond handle_moving",attribute
    if attribute == 'transform':
      #Beware  recalculation required for intermol bonds
      if hasattr(self,'Connectivity2') and self.Connectivity2:
        self.Connectivity2.UpdateCoordinates()
        self.do_redraw = 1
    else:
      self.do_redraw = 2
    
#-------------------------------------------------------------------------
  def set_visibility ( self, toggle_visibility='', visibility='', \
                       *args,**keywords):
#-------------------------------------------------------------------------
    #print "In HBOND::set_visibility",visibility
    dataobj.DispObj.set_visibility(self,toggle_visibility=toggle_visibility, \
                           visibility=visibility)
    if self.visible and not self.Connectivity2 and not self.do_redraw:
      self.do_redraw = 1
    if self.label_graphmod: self.label_graphmod.obj.visible = self.visible


#------------------------------------------------------------------
  def handleDrawingStylePM(self,ParamsManager='',updated={},**keywords):
#------------------------------------------------------------------
    #print 'handleDrawingStylePM',self,updated
    if updated:
      self.do_redraw = max(1,self.do_redraw)

#------------------------------------------------------------------------
  def getDrawingStylePM(self,custom=0,name='',auto_save=0,params={}):
#------------------------------------------------------------------------
    #print 'HBonds.getDrawingStylePM',name,params,custom
    if params:
      # Restored from pre-2.0 data
      #print 'HBond.getDrawingStylePM params',params
      name = 'HBond_drawing_style'+self.name
      self.drawingStylePM = createDrawingStylePM(name=name)
      self.drawingStylePM.setparams(params,do_rebuild=0)
    if name and (PM(name) or PM_MANAGER().get(name)):
      if PM(name):
        self.drawingStylePM = PM(name)
      else:
        self.drawingStylePM = createDrawingStylePM(name=name)
      self.drawingStylePM.add_dependent(self.handleDrawingStylePM)
      return self.drawingStylePM

    if custom and not hasattr(self,'drawingStylePM'):
      if not name: name = 'HBond_drawing_style'+self.name
      PM('HBond_drawing_style').remove_dependent(self.handleDrawingStylePM)
      self.drawingStylePM = createDrawingStylePM(name=name,copy_from=PM('HBond_drawing_style'))
      self.drawingStylePM.add_dependent(self.handleDrawingStylePM)
      if auto_save: HISTORY().autoSave()

    if hasattr(self,'drawingStylePM'):
      return self.drawingStylePM
    else:
      return PM('HBond_drawing_style')

#------------------------------------------------------------------------
  def closeDrawingStylePM(self,reset=1):
#------------------------------------------------------------------------
    if hasattr(self,'drawingStylePM'):
      #print "closeDrawingStylePM",self.drawingStylePM.name
      self.drawingStylePM.remove_dependent(self.handleDrawingStylePM)
      self.drawingStylePM.delete()
      del self.drawingStylePM
      if reset:
        if self.label_graphmod: self.label_graphmod.setparams(parameters=PM('HBond_drawing_style'))
        PM('HBond_drawing_style').add_dependent(self.handleDrawingStylePM)


#------------------------------------------------------------------
  def set_do_redraw(self,**keywords):
#------------------------------------------------------------------
    self.do_redraw = 2

#------------------------------------------------------------------
  def draw(self):
#------------------------------------------------------------------
    return 0

#------------------------------------------------------------------
  def unthreadedDraw (self ):
#------------------------------------------------------------------
    pm = self.getDrawingStylePM()
    if pm.get('line_style')== 'cylinders':
       line_style=cprim.DASHCYLINDER
    else:
       line_style=cprim.DASHLINE
    label_mode = int(pm.get('label_mode'))
    line_width = int(pm.get('line_width'))
    self.unthreadedDraw_main(line_style,line_width,label_mode)

#------------------------------------------------------------------
  def unthreadedDraw_main (self,line_style,line_width,label_mode):
#------------------------------------------------------------------
    #print "HBonds draw",self.name,self.do_redraw,self.do_update_opacity
    # Recolour requires a redraw
    # Stick it all in label_graphmod (the object for text)
    if self.do_recolour:
       if not self.do_redraw: self.do_redraw = 1
       self.do_recolour = 0
    
    if not self.do_redraw or not self.visible:
      if self.do_update_opacity:
         self.label_graphmod.obj.SetAlpha(self.opacity)
         self.do_rebuildGL.append('label_graphmod')
         self.do_update_opacity = 0
         return 1
      else:
         return 0

    if self.do_redraw == 2:
      rv = self.calculate()
      if rv: return 0

    if not self.Connectivity2: return 0


    self.label_graphmod.obj.clear_prims()
    self.label_graphmod.obj.DeleteText()
    col = MGCOLOUR().RGB(self.colour)
    colv = pygl_coord.DoubleVector(col)
    #self.label_graphmod.Connectivity2 = self.Connectivity2
    #print "HBonds.draw",line_style,line_width,label_mode,
    cprim.DrawSimpleConnection(self.label_graphmod.obj,
         self.Connectivity2.connected,colv,line_style,line_width,
         label_mode,self.colour)
    
    font =  FONTMANAGER().getFont('atom_label')
    self.label_graphmod.obj.SetTextFont( str(font['family']), str(font['weight']),
                                    str(font['slant']), font['size'],font['underline'])

    self.label_graphmod.rebuild()
    self.label_graphmod.obj.SetAlpha(self.opacity)
    self.do_redraw = 0
    self.do_rebuildGL.append('label_graphmod')

    import global_definitions
    mainwin = global_definitions.MAINWINDOW()
    rpm = global_definitions.PM('render_quality')
    useVBOopt = rpm.get('use_vbo')
    if useVBOopt and hasattr(mainwin,"glWidget") and hasattr(mainwin.glWidget,"format") and callable(mainwin.glWidget.format):
       if hasattr(mainwin.glWidget.format(),"directRendering") and callable(mainwin.glWidget.format().directRendering):
          useVA = True
          if sys.platform == "win32" and not sys.argv.count('-quit'):
            import opengl
            gl_renderer = opengl.glGetString(opengl.GL_RENDERER)
            useVAopt = rpm.get('force_use_va')
            if not useVAopt:
              if "Intel" in gl_renderer:
                print "Disabling use of VA on Windows with Intel GMA because of probable CCP4MG bug"
                useVA = False
          if mainwin.glWidget.format().directRendering()==True:
             if line_style == cprim.LINE or line_style == cprim.DASHLINE:
               self.label_graphmod.obj.SetAnchored(True)
               if useVA: self.label_graphmod.obj.SetUseVBO(True)
             else:
               self.label_graphmod.obj.SetAnchored(False)
               if useVA: self.label_graphmod.obj.SetUseVBO(False)

    return 1
 
#---------------------------------------------------------------------------
  def add_contact(self,selection_atom,style_atom):
#---------------------------------------------------------------------------
    #print "add_hbond",self.parent.molHnd.AtomLabel_atom(selection_atom), \
    #   self.parent.molHnd.AtomLabel_atom(style_atom)
    self.Connectivity2.AddConnection(selection_atom,style_atom)
    self.saved_edits.append([1,selection_atom,style_atom])
    self.do_redraw = 1

    ind = self.Connectivity2.FindConnections(selection_atom,style_atom)
    #print "FindConnection ind", ind

#-------------------------------------------------------------------------
  def delete_contact(self,selection_atom='',style_atom='',index=''):
#-------------------------------------------------------------------------

    #print "delete_hbond",selection_atom,style_atom
    if index:
      self.Connectivity2.DeleteConnection(index)
    else:
      self.Connectivity2.RemoveConnection(selection_atom,style_atom)
    if self.saved_edits.count([1,selection_atom,style_atom]):
      self.saved_edits.remove([1,selection_atom,style_atom])
    elif self.saved_edits.count([1,style_atom,selection_atom]):
      self.saved_edits.remove([1,style_atom,selection_atom])
    else:
      self.saved_edits.append([-1,selection_atom,style_atom])
    self.do_redraw = 1

#-----------------------------------------------------------------
  def export_data(self,filename='',comments=[]):
#-----------------------------------------------------------------
    import time

    # If DispObj object is not visible then Connectivity2 might
    # not be created
    if not self.Connectivity2:
      self.calculate()
      if not self.Connectivity2:
        return [1,'Can not calculate bonds']
    nV=self.Connectivity2.GetNofConnections()

    # Create the vectors loop first to find out, at the same time,
    # which MolData are referenced
    
    text='''loop_
_vector.start_model_id
_vector.start_atom
_vector.end_model_id
_vector.end_atom
_vector.label\n'''

    start_model_id = self.parent.name
    #if self.intermol_MolData:
    #  end_model_id =  self.intermol_MolData.name
    #else:
    end_model_id =  self.parent.name
    for iV in range(0,nV):
      atom1 = self.Connectivity2.GetAtom(iV,1)
      atom2 = self.Connectivity2.GetAtom(iV,2)
      #if iV==0: print "HBond atom1,atom2",atom1,atom2
      text=text+'"'+start_model_id+'"  "'+atom1.GetAtomID()[0]+'" ' \
             +'"'+end_model_id+'"  "'+atom2.GetAtomID()[0]+'"  ' \
             +'"'+self.Connectivity2.GetLabel(iV)+'" \n'

      #print "text",text

    # Create header
    head = '#Definition of vectors for display with CCP4mg\n'+ \
           '# Hydrogen bonds\n' + \
           '#Created on '+time.asctime(time.localtime(time.time()))+"\n"

    head = head+'\ndata_VECTORS\n'
    
    for item in comments:
      head = head+"# "+item+"\n"
    head = head+"\n\n"
    
    head = head+'''loop_
_model.id
_model.filename\n''' + \
      '"'+self.parent.name + '"   "'+self.parent.filename[2]+'"\n'
    #if self.intermol_MolData:
    #  head = head +  '"'+self.intermol_MolData.name + '"   "'+ \
    #         self.intermol_MolData.filename[2]+'"\n'
    #print "head",head

    pm = self.getDrawingStylePM()
    if pm.get('label_mode') ==cprim.LABELLEDCENTRE:
      labmo = ' "label centre" '
    else:
      labmo = ' "no label" '
      
    head = head+'''\n\nloop_
_display_objects.line_colour
_display_objects.line_style
_display_objects.line_width
_display_objects.label_mode
_display_objects.label_colour
"''' + self.colour + '" "dashed"  '+str(pm.get('line_width')) + labmo + '"'+self.colour+'"\n\n'

    if filename:
      # Handle request from user scripts
      import utils
      rv = utils.saveFile(filename=filename,text=head+text)

    return [rv,head+text]


#=============================================================== 
#=============================================================== 
#=============================================================== 
class HBonds(HB_Contacts,dataobj.DispObj):
#=============================================================== 
#=============================================================== 
#=============================================================== 

  edit_make_vector = None
  edit_test_atomtype = 0
  
  class_dependents = { } 
  
  def updateCrystal(self):
      dataobj.DispObj.updateCrystal(self)
      self.do_redraw = 2
  
  def __init__(self,parent='',visible=1,name='', \
               selection='',colour='',style='', \
               params={},selparams={'command':'all'},styleparams={},colparams={},**keywords):

    pars = { 'selection' : '',
             'colour' : 'complement',
             'style' : '' } 
    pars.update(params)
    
    dataobj.DispObj.__init__(self,'HBonds',name,parent= parent, \
                     visible=visible, params=pars)

    HB_Contacts.__init__(self,selparams=selparams,styleparams=styleparams,colparams=colparams,params=params)
    
    self.CHBond = None
    self.Connectivity2 = None
    
    self.set_colour(colour=self.colour,force=1)
    


    PM('HBond_param').add_dependent(self.set_do_redraw)
    self.update_dependents('create')
      
#------------------------------------------------------------------
  def list_data ( self,filename='',overwrite='query',**keywords ):
#------------------------------------------------------------------
    if not self.CHBond:
      if self.calculate(): return
    # Set up text to be listed
    text = "Hydrogen bonds between\nSet 1:" + \
           self.parent.filename[2] + "  ::  " + \
           self.SelHandle1.getLabel() +"\n" 
    if self.SelHandle1.getCommand() != self.SelHandle2.getCommand():
      text = text + "Set 2:" +  \
             self.parent.filename[2] + "  ::  " + \
             self.SelHandle2.getLabel() +"\n"
    text = text + "\n" + self.CHBond.Print()

    if filename:
      # Output to file - this is to handle requests from user scripts
      import utils
      utils.saveFile(filename,text=text,warning=1,overwrite=overwrite)

    return text    

#------------------------------------------------------------------
  def delete(self,**keywords):
#------------------------------------------------------------------
    import dataobj
    dataobj.DispObj.delete(self)
    HB_Contacts.delete(self)
    import dataobj
    PM('HBond_param').remove_dependent(self.set_do_redraw)
    

#------------------------------------------------------------------------
  def calculate ( self ):
#------------------------------------------------------------------------
    if self.CHBond: 
      del self.CHBond
      self.CHBond = None

    selHnd1 = self.SelHandle1.getSelHnd()
    selHnd2 = self.SelHandle2.getSelHnd()
    #print "HBonds calculate nofAtoms",self.SelHandle1.getNofAtoms(),self.SelHandle2.getNofAtoms()
    import mmut
    self.CHBond = mmut.CHBond(self.parent.molHnd,selHnd1,self.parent.molHnd,selHnd2)

    '''
    # Intermolecular HBonds
    if self.Selection2.as_MolDisp[2] and \
         hasattr(self.Selection2.as_MolDisp[2],'parent') and \
         self.Selection2.as_MolDisp[2].parent != self.parent:
      rv = self.Selection2.as_MolDisp[2].parent.parse_selection(self.Selection2.selection )
      if rv[0]: return 2
      if self.selHnd2: self.parent.molHnd.DeleteSelection(self.selHnd2)
      self.selHnd2 = rv[1]
      self.CHBond = CHBond(self.parent.molHnd,self.selHnd1, \
               self.Selection2.as_MolDisp[2].parent.molHnd,self.selHnd2)

    # Inter MolDisp HBonds
    elif self.Selection2.selection != self.selection:
      rv = self.parent.parse_selection (self.Selection2.selection )
      if rv[0]: return 2
      if self.selHnd2: self.parent.molHnd.DeleteSelection(self.selHnd2)
      self.selHnd2 = rv[1]
      self.CHBond = CHBond(self.parent.molHnd,self.selHnd1, \
                       self.parent.molHnd,self.selHnd2)
    '''


    self.Connectivity2 = self.CHBond.hbonds
    PM('HBond_param').update(self.CHBond.SetParams)

    #print "creating CHBond",self.CHBond,self.Connectivity2 
    if self.parent.nmr_models and (hasattr(self,"inter_model") and not self.inter_model):
      self.CHBond.Calculate(True)
    else:
      self.CHBond.Calculate(False)
    #print "from Calculate",self.Connectivity2.GetNofConnections()


    # Add/remove any saved_edits - beware user changed selection
    #for edit in self.saved_edits:
    #  if edit[0]:
    #    self.CHBond.hbonds.AddConnection(edit[1].edit[2])
    #  else:
    #    self.CHBond.hbonds.RemoveConnection(edit[1].edit[2])
        
    return 0

#--------------------------------------------------------------------------
def createDrawingStylePM(name='HBond_drawing_style',copy_from=''):
#--------------------------------------------------------------------------
  import services,mgPreferences
  return services.ParamsManager( name=name,
                    title='Hbond/contact drawing style',          
                    help = "_has_no_help_",
                    picture_definition = 1,
                    copy_from=copy_from,
                    gui= ['line_style','line_width','label_mode','contacts_line_style','contacts_line_width','contacts_label_mode'],
                    default = { 
                                 'line_style' : 'lines',
                                 'line_width' : 2,
                                 'label_mode' : 0,
                                 'contacts_line_style' : 'lines',
                                 'contacts_line_width' : 2,
                                 'contacts_label_mode' : 1,
                              },
                    definition = {
                       'line_style' : dict (type=str,label='HBond line style',
                          style = 'combobox', menu = ['lines','cylinders']),
                       'line_width' : dict (type = int, label = 'HBond line width',
                          style = 'spinbox', max = 10,min=1,step=1 ),
                       'label_mode' : dict (type='bool',label='HBond label with bond length',
                                            style='checkbox'),
                       'contacts_line_style' : dict (type=str,label='Contacts line style',
                          style = 'combobox', menu = ['lines','cylinders']),
                       'contacts_line_width' : dict (type = int, label = 'Contacts line width',
                          style = 'spinbox', max = 10,min=1,step=1 ),
                       'contacts_label_mode' : dict (type='bool',label='Contacts label with bond length',
                                            style='checkbox')
                       } )

#--------------------------------------------------------------------------
def HBondsParamsManager():
#--------------------------------------------------------------------------
  import services
  pm = services.ParamsManager( name='HBond_param',
              title='Hydrogen bond calculation parameters',
              picture_definition = 1,
              c_access = 1,
              gui=[ 'min_D_A','max_D_A','max_D_A_S','max_H_A','min_DD_D_A',
                 'min_D_A_AA','min_H_A_AA','min_D_H_A'],
              default = { 
                        'min_D_A': 2.0,
                        'max_D_A': 3.1,
                        'max_D_A_S': 3.9,
                        'max_H_A': 2.5,
                        'min_DD_D_A': 90.0,
                        'min_D_A_AA' : 90.0,
                        'min_H_A_AA' : 90.0,
                        'min_D_H_A' : 90.0 },
              definition={ 'min_D_A': dict (type =float,label='Min donor-acceptor distance',style='spinbox'),
                    'max_D_A': dict(type=float,label='Max donor-acceptor distance',style='spinbox',max=10.0,min=0.0,step=0.1),
                    'max_D_A_S': dict(type=float,label='Max donor-acceptor dist. with S',style='spinbox',max=10.0,min=0.0,step=0.1),
                    'max_H_A': dict(type=float,label='Max Hatom-acceptor distance',style='spinbox',max=10.0,min=0.0,step=0.1),
                    'min_DD_D_A': dict(type=float,label='Min neighbour-donor-acceptor angle',style='spinbox',max=180.0,min=0.0,step=1.0),
                    'min_D_A_AA' : dict(type=float,label='Min donor-acceptor-neighbour angle',style='spinbox',max=180.0,min=0.0,step=1.0),
                    'min_H_A_AA' : dict(type=float,label='Min Hatom-acceptor-neighbour angle',style='spinbox',max=180.0,min=0.0,step=1.0),             
                    'min_D_H_A' :  dict(type=float,label='Min donor-Hatom-acceptor angle',style='spinbox',max=180.0,min=0.0,step=1.0) },
                                                 help = 'analysis#hbonds')
  return pm
  

#---------------------------------------------------------------------
def define_hbond_popup_menu(**keywords):
#--------------------------------------------------------------------
  #print "IN define_hbond_popup_menu"
  params = [ ['PARAM','info_hbond',
             ['TYPE','_logical'],
             ['INITIAL',''],
             ['RETURN','handle_hbond_popup_menu'],
             ['LABEL','Hbond info'] ],
             ['PARAM','del_hbond',
             ['TYPE','_logical'],
             ['INITIAL',''],
             ['RETURN','handle_hbond_popup_menu'],
             ['LABEL','Delete Hbond']]
           ]
  display = [ ['com','info_hbond'],
              ['com','del_hbond']]
  return ['',params,display]

#----------------------------------------------------------------------
def define_atom_popup_menu(**keywords):
#----------------------------------------------------------------------
  # Define a portion of the pop-up menu to appear when
  # the user picks an atom
  last = ATOMPICKING().get_last_picked('atom')
  if not last: return
  molobj,dispobj,atomptr = last

  # Is this a HBondable atom
  if HBonds.edit_test_atomtype:
    atomhbtype = ''
    atomhbtype = molobj.molHnd.GetAtomHBondType(atomptr)
    #print "atomhbtype",atomhbtype
  
  # Loop over the HBonds objects and test this dispobj is
  # origin of any HBonds object
  hbobjs=get_dispobj(object_type='HBonds')
  if len(hbobjs)==0: return ['','','']

  ## ??? ### not handling inter-mol bond
  if molobj != self.parent:
    return ['','','']
  else:
    # Pull-down menu label dependent on if thisis first or second atom
    if HBonds.edit_make_vector:
      molobj1,dispobj1,atomptr1 = HBonds.edit_make_vector.first_atom
      #print "testing atomptr1 == atomptr",atomptr,atomptr1
      if str(atomptr1) == str(atomptr):
        label = 'Undo Hbond from '+ molobj1.molHnd.AtomLabel_atom(atomptr1)
      else:
        label = 'Add Hbond from '+ molobj1.molHnd.AtomLabel_atom(atomptr1)
    else:
      label = 'Add hydrogen bond'
    params = [ ['PARAM','add_hbond',
           ['TYPE','_logical'],
           ['INITIAL',''],
           ['RETURN','handle_hbond_popup_menu'],
           ['LABEL',label]]
        ]

    display = [ ['com','add_hbond']]

    return ['',params,display]


#----------------------------------------------------------------------
def handle_hbond_popup_menu(add_hbond='0',del_hbond='0',list_hbond='0',\
                            **keywords):
#----------------------------------------------------------------------
  add_hbond = int(add_hbond)
  del_hbond = int(del_hbond)
  list_hbond = int(list_hbond)

  if list_hbond:
    pass
  if add_hbond:
    #Find which dispobj was picked
    last =  ATOMPICKING().get_last_picked('atom')
    if not last: return
    molobj,dispobj,atomptr = last

  
    # Loop over the HBonds objects and test this dispobj is
    # origin of any HBonds object
    hbobjs=get_dispobj(object_type='HBonds')
    if len(hbobjs)==0: return ['','','']

    # Test that the picked atom is in a hydrogen bonded dispobj
    if molobj != self.parent:
      MGGUI().WarningMessage('Picked atom '+molobj.molHnd.AtomLabel_atom(atomptr)+ \
       ' is in display object '+dispobj.selection_label+ \
       ' which is not hydrogen bonded')
      return 0

    import services
  
    if not HBonds.edit_make_vector:
      HBonds.edit_make_vector = services.MakeVector( \
        first_atom=[molobj,dispobj,atomptr])
    else:
      molobj1,dispobj1,atomptr1 = HBonds.edit_make_vector.first_atom
      if ( str(atomptr) == str(atomptr1) ):
        #Picked same atom twice - assume intend to abort
        pass
      else:
        # Try making a HBond
        done = 0
        for hbobj in possible_hbobjs:
          if hbobj[1] == 'selection' and dispobj1 ==  hbobj[0].style_obj:
            hbobj[0].add_contact(atomptr,atomptr1)
            done = 1
          elif  hbobj[1] == 'style' and dispobj1 ==  hbobj[0].selection_obj:
            hbobj[0].add_contact(atomptr1,atomptr)
            done = 1
        if not done:
          MGGUI().WarningMessage('Picked atom '+molobj.molHnd.AtomLabel_atom(atomptr)+ \
            ' in display object '+dispobj.selection_label+ \
            '\n and atom '+molobj1.molHnd.AtomLabel_atom(atomptr1)+ \
            ' in display object '+dispobj1.selection_label+ \
            ' are not in hydrogen bonded display objects')
      HBonds.edit_make_vector.delete()
      HBonds.edit_make_vector = None

  elif del_hbond:
    if len(HBonds.last_picked_edge)<=0: return
    molobj,dispobj,index =  HBonds.last_picked_edge[0]
    #print "handle del hbond",index
    dispobj.delete_contact(index=index)

  return 0

