"""
     python/ui/model_fragment.py: CCP4MG Molecular Graphics Program
     Copyright (C) 2001-2008 University of York, CCLRC

     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.
"""

from utils import *
import os
import string
import re

from mgapp import *
from mmdb2 import *
from mmut import *
from dataobj import *
from model_selection import *
from moleculargraphicsmodel import *
from resources import *
from view import *
import build
from global_definitions import *
import pygl_coord
import mmut

#-----------------------------------------------------------------
#-----------------------------------------------------------------
#-----------------------------------------------------------------
class model_fragment(ModelAnalysis,DispObj):
#-----------------------------------------------------------------
#-----------------------------------------------------------------
#-----------------------------------------------------------------
  colour_commands = [ 'onecolour','atomtype','mainside']
  colour_code = [ ONECOLOUR, BYATOMTYPE, MAINSIDE]

#------------------------------------------------------------------
  def __init__(self,parent,name='',visible=1,master_application='', \
               duplicate_MMDB=0, **keywords):
#------------------------------------------------------------------
    global gui
    DispObj.__init__(self,'model_fragment',name, parent,visible=visible, \
                     master_application=master_application, \
                     display_table_visible=0)
    ModelAnalysis.__init__(self)
    self.name_label = self.name
    self.duplicate_MMDB = duplicate_MMDB
    if self.duplicate_MMDB:
      self.molHnd = CMMANManager(RESOURCES().SRS,RESOURCES().CMolBondParams)
    else:
      self.molHnd = self.parent.molHnd

    self.selHnd = -1
    self.nSelAtoms = 0
    self.selAtoms = ''
    self.update_atomRadii = 0

    self.one_colour='red'
    self.colour='onecolour'
    self.non_C_mode=-1
    self.atomColourVector = None

    self.style = 'SPHERES'
    self.update_atomRadii = 0
    self.sphere_radii_scale = 0.15
    
    self.Connectivity = Connectivity()
    self.CMolColour = CMolColour ( self.molHnd, self.selHnd, \
       RESOURCES().colourSchemes)
    

    # Flag to update display without updating any of the display
    # attributes - probably set because atom coordinates have
    # changed 
    self.do_updatedisplay = 0

    # Instantiate a a graphics object and assign some parameters
    import moleculargraphicsmodel
    import history
    import model
    self.graphmod = moleculargraphicsmodel.moleculargraphicsmodel(ui=self)
    self.graphmod.setparams(molHnd=self.molHnd, \
                            Connectivity = self.Connectivity, \
             diagnostic_timing = history.CHistory.insts.diagnostic['timing'])
    self.graphmod.setparams(parameters =  model.MolDisp.GraphicsParamsManager)
    self.atomRadii = pygl_coord.DoubleVector(2)
    self.graphmod.setparams(atomRadii=self.atomRadii)

#----------------------------------------------------------------------
  def define_selection_range(self,molHnd=None,pResidue=None,link=1,range=0):
#----------------------------------------------------------------------
    '''
    Return a selction command for a range of residues around a focus residue
    NB Does not handle insertion code and does not check thar residues are
    connected
    '''

    #seqNum = pResidue.seqNum
    indx = pResidue.index
    chn = pResidue.chain
    #print "define_selection_range",indx,chn
    resTable = newPPCResidue()
    nR = intp()
    pResidue.chain.GetResidueTable(resTable,nR)
    nRes = nR.value()
    ifres = max(indx-range,0)
    ilres = min(indx+range,nRes-2)
    #print "nRes,ifres,ilres",nRes,ifres,ilres
    range = '//'+chn.GetChainID()+'/'+str(getPCResidue(resTable,ifres).seqNum)+ \
            '-'+str(getPCResidue(resTable,ilres).seqNum)
    if link:
        #Add the linked C(i-1) and N(i+1) atoms
      if ifres>0:
        Nlink = '//'+chn.GetChainID()+'/'+str(getPCResidue(resTable,ifres-1).seqNum)+'/C'
      else:
        Nlink=''
      if ilres < nRes:
        Clink = '//'+chn.GetChainID()+'/'+str(getPCResidue(resTable,ilres+1).seqNum)+'/N'
      else:
        Clink=''
        
    #delPPCResidue(resTable)
    return [range,Nlink,Clink]

#--------------------------------------------------------------------
  def set_selection(self,defn=[],command='',extend=0):
#--------------------------------------------------------------------
    #print "set_selection",defn
    if self.duplicate_MMDB:
      if self.duplicate_MMDB == 2:
        del self.molHnd
        del self.CMolColour
        self.molHnd = CMMANManager(RESOURCES().SRS,RESOURCES().CMolBondParams)
        #print "duplicate_MMDB molHnd",self.molHnd 
        self.CMolColour = CMolColour ( self.molHnd, self.selHnd, \
            RESOURCES().colourSchemes)
        self.graphmod.setparams(molHnd=self.molHnd)
      rv = self.parent.parse_selection(defn=defn,command=command)
      if rv[0]: return 1
      selHnd = rv[1]
      self.parent.molHnd.PutSelectedAtoms (selHnd,self.molHnd)
      #print "Nof atoms in model_fragment",self.molHnd.GetNumberOfAtoms()
      self.duplicate_MMDB = 2
      print "FIXME (model_fragment.py) - A preference here for aromaticize."
      self.molHnd.GetMolBonds()
      self.parent.molHnd.DeleteSelection(selHnd)
      self.do_redraw = 1
      
    if extend:
      pass
    else:
      if self.selHnd: self.molHnd.DeleteSelection(self.selHnd)
      rv = self.parse_selection(defn=defn,command=command)
      #print "parse_selection rv",rv
      if rv[0]: return 1
      self.selHnd = rv[1]
      self.do_redraw = 1


    self.update_atomRadii = 1
    
#--------------------------------------------------------------------
  def set_colour(self,one_colour='',colour='',non_C_atomtype=''):
#--------------------------------------------------------------------
    if one_colour: self.one_colour = one_colour
    if colour: self.colour = colour
    if non_C_atomtype: self.non_C_atomtype = non_C_atomtype
    self.do_recolour = 1    


#--------------------------------------------------------------------
  def set_style(self,style=''):
#--------------------------------------------------------------------
    if style: self.style = style

#--------------------------------------------------------------------
  def delete(self,**keywords):
#--------------------------------------------------------------------
    DispObj.delete(self)
    if hasattr(self,'Connectivity') and self.Connectivity: del self.Connectivity
    if hasattr(self,'CMolColour') and self.CMolColour: del  self.CMolColour
    if (self.duplicate_MMDB):
      if self.molHnd:del self.molHnd
    else:
      if self.selHnd>=0:
        self.molHnd.DeleteSelection(self.selHnd)   
        self.selHnd = -1



#-------------------------------------------------------------------------
  def handle_atom_radii(self,ball_radii_scale='',sphere_radii_scale='',
                        **keywords):
#-------------------------------------------------------------------------
    if sphere_radii_scale:
      sphere_radii_scale = float(sphere_radii_scale)
      if sphere_radii_scale < 0.001 or sphere_radii_scale > 10.0: return
      diff = self.sphere_radii_scale - sphere_radii_scale
      self.sphere_radii_scale = sphere_radii_scale
      if (diff < -0.001 or diff > 0.001) and  self.style == "SPHERES":
         self.do_redraw = 1
         self.update_atomRadii = 1
       
    
#------------------------------------------------------------------------
  def update_connectivity(self):
#------------------------------------------------------------------------
    #print "model_fragment update_connectivity"
    self.Connectivity.Clear()
    if self.nSelAtoms <= 0: return
    self.Connectivity.AddBonds(self.molHnd,self.selHnd,
          self.selAtoms,self.nSelAtoms,0,0)

#------------------------------------------------------------------------
  def draw (self):
#------------------------------------------------------------------------
    '''
    Called at end of each cycle of a command loop
    Redraw the graphmod if necessary
    '''
    #print "model_fragment draw",self.do_redraw
    if self.do_redraw>0:

      if self.selHnd:
	"""
        if self.selAtoms:
           delPPCAtom(self.selAtoms)
	"""
        selindexp = pygl_coord.intp()
        self.selAtoms = newPPCAtom()
        #self.nSelAtoms =self.molHnd.GetSelIndex(self.selHnd,self.selAtoms)
        self.selAtoms = mmut.GetAtomSelIndex(self.molHnd,selHnd,selindexp)
        self.nSelAtoms = selindexp.value()
        #print "Number of selected atoms",self.nSelAtoms
      else:
        self.selHnd = self.molHnd.NewSelection()
	"""
        if self.selAtoms:
           delPPCAtom(self.selAtoms)
	"""
        self.selAtoms = newPPCAtom()
        self.nSelAtoms = 0
      self.update_connectivity()
      self.do_redraw = 0
      self.do_recolour = 1

    if self.do_recolour:
      self.CMolColour.SetSelHandle(self.selHnd)
      if self.colour_commands.count(self.colour) > 0:
        ic = self.colour_commands.index(self.colour)
        RC = self.CMolColour.SetMode (1,self.colour_code[ic],self.non_C_mode)
        if self.colour == 'onecolour':
          self.CMolColour.SetOneColour(MGCOLOUR().index(self.one_colour))
      self.CMolColour.ReColour()
      self.atomColourVector = self.CMolColour.GetAtomColourVector()
      self.do_recolour = 0
      
    if ['SPHERES','BALLSTICK','CIRCLES'].count(self.style):
      if self.update_atomRadii:
        #print "updating atomRadii"
        if self.atomRadii: del self.atomRadii
        if self.style == "SPHERES":
          scale = self.sphere_radii_scale
        elif self.style == "BALLSTICK" or self.style == 'CIRCLES':
          scale = self.ball_radii_scale
        self.atomRadii=self.molHnd.GetAtomRadii(self.selHnd,VDWRADIUS,scale)
        self.graphmod.setparams(atomRadii=self.atomRadii)
        self.update_atomRadii=0

      # Update graphmod parameters
    #print "calling setparams"
    self.graphmod.setparams(selHnd=self.selHnd, \
                              selAtoms = self.selAtoms, \
                              nSelAtoms = self.nSelAtoms, \
                              style = self.style, \
                              visible = self.visible, \
                              atomColourVector = self.atomColourVector, \
                              ifColourContinuous = 0 )
                        
    if not self.built:
      build.build.insts.append(self.graphmod)
      self.built = 1
    else:
      self.graphmod.rebuild()

    self.do_redraw = 0


#-----------------------------------------------------------------------
  def set_extent(self):
#-----------------------------------------------------------------------
    self.extent = [0.0,0.0,0.0,0.0,0.0,0.0]
    if self.nSelAtoms > 0:
      extptr = self.parent.molHnd.Extent(self.selHnd)
      tmp = doublea(1)
      ext=tmp.frompointer(extptr)
      if ext:
        self.extent = []
        for i in range(0,6): self.extent.append (ext[i])
    #print "extent",sel.extent
    self.origin = [ \
           (self.extent[3] + self.extent[0])/2.0,
           (self.extent[4] + self.extent[1])/2.0,
           (self.extent[5] + self.extent[2])/2.0 ]
    #print "sel.origin",sel.origin
    self.com = [0.0,0.0,0.0]

