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

     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 dataobj
from global_definitions import *

#------------------------------------------------------------------------
#------------------------------------------------------------------------
#------------------------------------------------------------------------
class Annotation(dataobj.DispObj):
#------------------------------------------------------------------------
#------------------------------------------------------------------------
#------------------------------------------------------------------------

  class_dependents = {}
  
  def __init__(self,parent='',visible=1,name='', \
               params = {},restore_from_version=0,**keywords):

    # Set defaults
    #  'colour' : 'complement',
    # 'font' : {}
    font = FONTMANAGER().getHtmlFont('annotation')
    pars = {
      'text' :  '<span '+font+'>Annotation</span>',
      'position' : [0.0,0.0,0.0],
      'centered': False,
      'atom_position' : '' }
          

    # update from arguments
    pars.update(params)
    pars.update(keywords)

    # Check for pre-2.0 named parameters
    if pars.has_key('selection'):
      pars['text'] = pars['selection']
      del pars['selection']
    if pars.has_key('style'):
      pars['position'] = pars['style'][0:3]
      pars['atom_position'] =  pars['style'][3]
      del pars['style']

    # !!! HANDLE OLD FONT/COLOUR
    if  pars.has_key('colour'):
      pass
    if  pars.has_key('font'):
      pass
        
    dataobj.DispObj.__init__(self,'Annotation',name,parent=parent, \
                     visible=visible,params=pars )

      
    self.delta = [0.0,0.0,0.0]
    self.extent = ['-5.0','5.0']   
    self.moving = 0
    # Keep list of Text objects
    self.graph_objects = []

    
    # update params based on input params
    self.set_text(text=self.text)
    self.set_position(atom_position=self.atom_position)

    self.update_dependents('create')


#-----------------------------------------------------------------------
  def get_text_label(self):
#-----------------------------------------------------------------------
    import ParseHTMLTextString
    parser = ParseHTMLTextString.MyHTMLParser()
    parser.feed(str(self.text))
    data = parser.getAllData().strip().replace('\n',' ')
    return data[:min(15,len(data))]

  def get_selection_label(self):
    return self.get_text_label()
  
#-----------------------------------------------------------------------
  def get_position(self):
#-----------------------------------------------------------------------
    return self.position

#-----------------------------------------------------------------------
  def get_position_label(self):
#-----------------------------------------------------------------------
    if self.atom_position:
      return self.atom_position
    else:
      return '%.1f'%self.position[0]+' '+'%.1f'%self.position[1]+ \
                         ' '+'%.1f'%self.position[2]


#-----------------------------------------------------------------------
  def set_text(self,text=''):
#-----------------------------------------------------------------------
    self.text=text
    self.do_redraw = 2
    
#-------------------------------------------------------------------
  def transform(self,glwidget):
#-------------------------------------------------------------------
    '''
    Handle mouse input to translate objects
    '''
    if glwidget.transformDeltaMode() == 'translate':
      dx,dy,dz = glwidget.worldTranslate()
      #print "Annotation.transform", dx,dy,dz
      self.set_position(dx=dx,dy=dy,dz=dz)
    
#----------------------------------------------------------------------
  def set_position(self,atom_position='',x='',y='',z='', 
                dx='',dy='',dz='',zero=0,**keywords):
#----------------------------------------------------------------------
    '''
    x,y,z are world coords to set position of annotation
    dx,dy,dz are delta screen coords to apply to existing postion
    '''

    # Sort out the 'old' position - i.e. position before
    # application of any delta - is in world frame 
    if zero or not self.position:
      xold,yold,zold = 0.0,0.0,0.0
    else:
      xold,yold,zold = self.position
      

    if atom_position != '':
      rv = self.parent.get_centre(atom_position)
      #print 'set_position get_centre',rv
      if not rv[0]:
        xold,yold,zold = rv[1]
        self.atom_position = atom_position
      
    if x != '': xold = float(x)
    if y != '': yold = float(y)
    if z != '': zold = float(z)

    #print "Annotation.set_position old x,y,z",xold,yold,zold

    # Make sure deltas are converted to float or
    # are set to zero - deltas are in screen frame
    ddx,ddy,ddz = 0.0,0.0,0.0
    if dx: ddx = float(dx)
    if dy: ddy = float(dy)
    if dz: ddz = float(dz)
    self.delta = [ddx,ddy,ddz]
    self.atom_position = ''
    #print "delta ", self.delta

    self.position = [ xold+ddx, yold+ddy,zold+ddz]
    self.do_redraw = max(self.do_redraw,1)

#----------------------------------------------------------------
  def handle_moving_data(self,attribute='',master='',**keywords):
#----------------------------------------------------------------
    #print "Annotation handle_moving_data",attribute
    self.do_redraw = 1
    
#------------------------------------------------------------------
  def unthreadedDraw (self ):
#------------------------------------------------------------------
    #print "Annotation draw do_redraw", self.do_redraw,self.position
    # Recolour requires redraw

    # Put all drawing in the label_graphmod object since it is text and must be drawn in
    # unthreaded mode

    if not self.label_graphmod:
      import graphicsmodel
      self.label_graphmod = graphicsmodel.graphicsmodel( )
      BUILD().append(self.label_graphmod)
      self.do_redraw = 2
      
      
    if self.do_redraw > 1:

      # Delete all of the text objects from graphmod
      if len(self.graph_objects)>0 and self.label_graphmod: 
        import cprim
        for graph_object in self.graph_objects:
          #print "deleting ",graph_object,'from',obj.graphmod
          cprim.DeleteTextLabel(self.label_graphmod.obj,graph_object.GetID())
        self.graph_objects = []
      self.create_annotation()

    elif self.do_redraw:
      if self.graph_objects:
        import pygl_coord
        self.graph_objects[0].SetVertices([pygl_coord.Cartesian(self.position[0],self.position[1],self.position[2])])
        self.graph_objects[0].SetCentered(bool(self.centered))
        
    self.do_rebuildGL.append('label_graphmod')
    self.do_redraw = 0
    return 1

#-----------------------------------------------------------------
  def create_annotation(self):
#------------------------------------------------------------------
    import cprim,pygl_coord
    xyz = []

    qmat = MAINWINDOW().glWidgets[0].quat.getInvMatrix()

    cart = pygl_coord.Cartesian(self.delta[0],self.delta[1],self.delta[2])
    cartnew = qmat * cart

    atomxyz = [0.0,0.0,0.0]
    if self.atom_position:
      rv = self.parent.get_centre(self.atom_position)
      if not rv[0]: atomxyz = rv[1]

    self.position = [ cartnew.get_x()+self.position[0], \
                      cartnew.get_y()+self.position[1], \
                      cartnew.get_z()+self.position[2] ]


    pos1 = pygl_coord.Cartesian(self.position[0]+atomxyz[0],
                    self.position[1]+atomxyz[1],
                    self.position[2]+atomxyz[2])
    pos2 = pygl_coord.Cartesian(self.position[0]+atomxyz[0],
                    self.position[1]+atomxyz[1],
                    self.position[2]+atomxyz[2])
    
    text = self.text
    #print 'Annotation.create_annotation',text
    import TextLabel
    label_ob = TextLabel.CreateTextLabel(text,pos1,pos2)

    label_ob.thisown = 0
    label_ob.SetCentered(bool(self.centered))

    self.label_graphmod.obj.add_text_primitive(label_ob)
    self.graph_objects.append(label_ob)
    self.label_graphmod.obj.rebuild()

    self.do_redraw = 0
    self.delta = [0.0,0.0,0.0]
    
#-----------------------------------------------------------------------
  def centre_on(self,**keywords):
#-----------------------------------------------------------------------
    import build
    atomxyz = [0.0,0.0,0.0]
    if self.atom_position:
      rv = self.parent.get_centre(self.atom_position)
      if not rv[0]: atomxyz = rv[1]

    xyz = []
    for i in range(0,3):
      xyz.append(self.position[i]+atomxyz[i])
    BUILD().glthread.glevent.centre_on(xyz,self.label_graphmod.obj)

#----------------------------------------------------------------------
  def delete(self,**keywords) :
#-----------------------------------------------------------------------
    win = MAINWINDOW()
    if self.label_graphmod:
      win.removeGLDisplayObject(self.label_graphmod)
      BUILD().deletemod(self.label_graphmod)
      del self.label_graphmod
    dataobj.DispObj.delete(self)

  

#------------------------------------------------------------------
  def params(self,all=1):
#------------------------------------------------------------------
    pars = dataobj.DispObj.params(self)
    for item in ['text','position','atom_position','centered']:
      pars[item]=getattr(self,item,'')

    return pars

  
#------------------------------------------------------------------
  def movie_interpolation(self,initial_status=None,final_status=None, \
                          fraction=0.0,step=0,**keywords):
#------------------------------------------------------------------
    pkey = 'position'
    if initial_status and initial_status.params.has_key(pkey) and \
           final_status and final_status.params.has_key(pkey):
      initial = initial_status.params[pkey]
      final = final_status.params[pkey]
      delta = []
      for i in range(0,3):
        delta.append(float(final[i])-float(initial[i]))

      #print 'Annotation movie_interpolation delta',delta
      self.set_position(x = float(initial[0])+fraction*delta[0],\
                     y = float(initial[1])+fraction*delta[1], \
                     z = float(initial[2])+fraction*delta[2])
      
      dataobj.DispObj.movie_interpolation(self,initial_status=initial_status, \
           final_status=final_status,fraction=fraction,step=step)

#------------------------------------------------------------------
  def update_data_status(self,shadowdisp):
#------------------------------------------------------------------
    import utils
    diffs = utils.dict_diffs(self.params(),shadowdisp.params)[1]
    if not diffs: return []
    rv = 0
    
    if diffs.has_key('text'):
      rv = 1
      self.set_text(shadowdisp.params.get('text'))

    if diffs.has_key('position') or diffs.has_key('atom_position'):
        xyz = shadowdisp.params.get('position')
        self.set_position(atom_position = shadowdisp.params.get('atom_position'),
                        x= xyz[0],y=xyz[1],z=xyz[2])

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



#---------------------------------------------------------------------------------
def createAnnotationParamsManager():
#---------------------------------------------------------------------------------
  import services

  # This is used by annotationGui.annotateFormatWidget which provides
  # a gui to edit the format 
 
  pm = services.ParamsManager ( 
          name="annotation_format",
          help="twoDobjects",
          title='Annotation format',
          gui=[],
      default = { 'format' : [['','Res name'],[' ','Chain id'],['','Seq #']] },
      definition = {
             'format' : {}
                } )

  return pm
