"""
     python/ui/map.py: CCP4MG Molecular Graphics Program
     Copyright (C) 2001-2008 University of York, CCLRC
     Copyright (C) 2009-2010 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.
"""

from utils import *
from dataobj import *
from global_definitions import *
import MapPlane
import sys
import tempfile
import xmapview

from PyQt4 import QtCore

def CheckMMCIF_SG_Cell(fname,coorfile):
  print "check for cell/spacegroup"
  
  f = open(fname)
  lines = f.readlines()
  f.close()
  
  for l in lines:
    if l.startswith('_cell'):
       print "Have cell"
       return fname
  else:
    print "Do not have cell"
    import mmut
    mmut.InitMatType()
    molHnd = mmut.CMMUTManager()
    molHnd.SetFlag( mmut.MMDBF_AutoSerials | mmut.MMDBF_IgnoreDuplSeqNum )
    molHnd.ReadCoorFile(coorfile)
    cell_info = molHnd.GetCellInfo()
    sg = molHnd.GetSpaceGroup()
    tfile = tempfile.NamedTemporaryFile(suffix='.mmcif',delete=False)
    tname = tfile.name
    tfile.write(lines[0])
    pdbid = lines[0][6:10]
    tfile.write('#\n')
    tfile.write('_cell.entry_id      '+pdbid+'\n')
    tfile.write('_cell.length_a      '+("%.4f" % cell_info[0])+'\n')
    tfile.write('_cell.length_b      '+("%.4f" % cell_info[1])+'\n')
    tfile.write('_cell.length_c      '+("%.4f" % cell_info[2])+'\n')
    tfile.write('_cell.angle_alpha   '+("%.4f" % cell_info[3])+'\n')
    tfile.write('_cell.angle_beta    '+("%.4f" % cell_info[4])+'\n')
    tfile.write('_cell.angle_gamma   '+("%.4f" % cell_info[5])+'\n')
    tfile.write('#\n')
    tfile.write('_symmetry.entry_id               '+pdbid+'\n')
    tfile.write("_symmetry.space_group_name_H-M   '"+sg+"'\n")
    tfile.writelines(lines[1:])
    tfile.close()
    print "return",tname
    return tname
 
#------------------------------------------------------------------
#------------------------------------------------------------------
#------------------------------------------------------------------
# The MapData class
#------------------------------------------------------------------
#------------------------------------------------------------------
#------------------------------------------------------------------

class MapData(DataObj):
  class_dependents = {}

  initialisation = {
    'f' : '',
    'phi' : '',
    'wt'  : '',
    'difference'  : 0,
    'structFile' : '',
    'rate' : 0.5,
    'is_em_map' : False,
    'filetype' : 'MTZ' }

#------------------------------------------------------------------
  def __init__(self,name='',filename=[],difference=0,dataparams={},restore_from_legend=0,structFile='',**keywords):
#------------------------------------------------------------------
    #self.filename = filename
    self.module = 'map'
    pars = {}
    pars.update(MapData.initialisation)
    pars.update(dataparams)
    pars.update(keywords)

    print "MapData.__init__",structFile,dataparams
    DataObj.__init__(self,'MapData',name=name,module='map', \
                     filename=filename,dataparams=pars)

    if dataparams.has_key("structFile") and dataparams["structFile"] != '' and dataparams["structFile"] is not None:
      print "set self.structFile to dataparams[\"structFile\"]",dataparams["structFile"]
      self.structFile = dataparams["structFile"]
    else:
      print "set self.structFile to structFile",structFile
      self.structFile = structFile
    print "self.structFile", self.structFile

    if dataparams.has_key("difference"):
      self.difference = dataparams["difference"]
    else:
      self.difference = difference

#------------------------------------------------------------------
  def delete(self,**keywords):
#------------------------------------------------------------------
    #if self.molHnd: del self.molHnd
    DataObj.delete(self)
    # *****NEED to delete xmapview!!
    del self

  def getDependentsForDeletion(self):
    # This method return any other objects that should be deleted along with
    # this one.  We need to delete the crystal object
    xtl_list = []
    xtl = CRYSTALMANAGER().getCrystal(self.name)
    if xtl: xtl_list.append(xtl)
    return xtl_list
    
    
#------------------------------------------------------------------
  def dataparams(self,all=1):
#------------------------------------------------------------------
    datapar = DataObj.dataparams(self,all=all)
    for key,default in MapData.initialisation.items():
      value = getattr(self,key)
      if all or value != default: datapar[key]= value
    return datapar

#--------------------------------------------------------------------
  def isSameData(self,shadow_data):
#--------------------------------------------------------------------
    for item in ['filename','f','phi','wt','rate','difference']:
      if getattr(self,item) != shadow_data.dataparams[item]:
        return 0
    return 1

#------------------------------------------------------------------
  def loaddata(self,emMap=False,**keywords):
#------------------------------------------------------------------
    import cprim

    if emMap:
      self.is_em_map = True

    import convert_shelx_fcf_to_cif

    if self.filetype == 'MTZ':
      if self.wt:
        self.clipper_map = xmapview.XMap(self.filename[2], self.f, self.phi, self.wt, 1, 0, 1.0/self.rate)
      else:
        self.clipper_map = xmapview.XMap(self.filename[2], self.f, self.phi, "",      0, 0, 1.0/self.rate)
    elif self.filetype == 'MAP':
      self.clipper_map = xmapview.XMap(self.filename[2])
    elif self.filetype == 'MMCIF':
        ciffile = CheckMMCIF_SG_Cell(self.filename[2],self.structFile)
        print "MMCIF", ciffile,self.structFile
        self.clipper_map = xmapview.XMap(ciffile,self.structFile,self.difference,1.0/self.rate)
    elif self.filetype == 'CIF':
      if self.filename[2].lower().endswith('fcf'):
        ft = tempfile.NamedTemporaryFile(suffix=".cif",prefix="ccp4mg"+str(os.getpid()))
        fname = ft.name
        ft.close()
        convert_shelx_fcf_to_cif.convert_shelx_fcf_to_cif(self.filename[2],fname)
        self.clipper_map = xmapview.XMap(fname,self.difference,1.0/self.rate)
      else:
        self.clipper_map = xmapview.XMap(self.filename[2],self.difference,1.0/self.rate)
    
    self.map_mean =  self.clipper_map.GetMean()
    self.map_sd =  self.clipper_map.GetStdDev()
    import math
    absolute_max = self.clipper_map.GetMax()
    absolute_min = self.clipper_map.GetMin()
    self.absolute_max = max(math.fabs(absolute_min),absolute_max)
    #print "map.loaddata absolute_max",self.filename[2],self.filetype, self.f, self.phi,self.absolute_max

    self.originalSymmetry = self.getClipperSymmetry()

    self.update_dependents('create')

    return [0,'']

#------------------------------------------------------------------------
  def getClipperSymmetry(self):
#------------------------------------------------------------------------
    import pygl_coord,math
    
    sg = self.clipper_map.GetSpaceGroup()
    cellptr = self.clipper_map.GetCell()
    if cellptr:
      pcell = []
      tmp=pygl_coord.doublea(1)
      pcell = tmp.frompointer(cellptr)
      cell = []
      for i in range(0,3): cell.append(pcell[i])
      for i in range(3,6): cell.append(pcell[i]*180.0/math.pi)
      if sg == "R 3":
        if abs(cell[3]-90)<1e-6 and abs(cell[4]-90)<1e-6 and abs(cell[5]-120)<1e-6:
          print 'Space group R 3 reset to H 3'
          sg = "H 3"
      if sg == "R 3 2":
        if abs(cell[3]-90)<1e-6 and abs(cell[4]-90)<1e-6 and abs(cell[5]-120)<1e-6:
          print 'Space group R 3 2 reset to H 3 2'
          sg = "H 3 2"
    return dict ( status = 0 , cell=cell, sg= sg)

#------------------------------------------------------------------------
  def create_contours(self,difference=0):
#------------------------------------------------------------------------

    # Create one or two contour surfaces
    #print "difference",difference
    if PM('MapDispParamsManager').get('contour_scale') == 'sigma':
      if difference:
        s0 = MapDisp ( self.name , contour_level = 3.0, colour=PM('MapDispParamsManager').get('diff_pos_colour'))
        s1 = MapDisp ( self.name , contour_level = -3.0, colour=PM('MapDispParamsManager').get('diff_neg_colour'))
      else:
        s = MapDisp ( self.name, contour_level=1.5 )
    else:
      if difference:
        s0 = MapDisp ( self.name , contour_level = 3.0*self.map_sd, colour=PM('MapDispParamsManager').get('diff_pos_colour'))
        s1 = MapDisp ( self.name , contour_level = -3.0*self.map_sd, colour=PM('MapDispParamsManager').get('diff_neg_colour'))
      else:
        s = MapDisp ( self.name, contour_level=1.5*self.map_sd )
  

#-----------------------------------------------------------------
  def add_object(self,params={},**keywords):
#-----------------------------------------------------------------
     return MapDisp(self.name,visible=1,params=params)


#------------------------------------------------------------------
  def list_data(self,**keywords):
#------------------------------------------------------------------
    #absolute_max = self.clipper_map.GetMax()
    #absolute_min = self.clipper_map.GetMin()

    list_data = 'Map from file: '+self.filename[2] + ' \n' + \
        'Structure facture = '+self.f+ '\n' + \
        'phases = '+self.phi+ '\n' + \
        'phase weight = '+self.wt + '\n' + \
        'Mean density = %.3f  standard deviation = %.3f' % (self.map_mean,self.map_sd) + '\n' 

    return list_data

#--------------------------------------------------------------------
  def set_sampling_rate(self,sampling_rate='',**keywords):
#--------------------------------------------------------------------
    import convert_shelx_fcf_to_cif

    if sampling_rate:
      self.rate = float(sampling_rate)
      #print "reset sampling",self.rate

      if self.clipper_map: self.clipper_map = None
      if self.filetype == 'MTZ':
        if self.wt:
          self.clipper_map = xmapview.XMap(self.filename[2], self.f, self.phi, self.wt, 1, 0, 1.0/self.rate)
        else:
          self.clipper_map = xmapview.XMap(self.filename[2], self.f, self.phi, "",      0, 0, 1.0/self.rate)
      elif self.filetype == 'CIF':
        if self.filename[2].lower().endswith('fcf'):
          ft = tempfile.NamedTemporaryFile(suffix=".cif",prefix="ccp4mg"+str(os.getpid()))
          fname = ft.name
          ft.close()
          convert_shelx_fcf_to_cif.convert_shelx_fcf_to_cif(self.filename[2],fname)
          self.clipper_map = xmapview.XMap(fname,self.difference,1.0/self.rate)
        else:
          self.clipper_map = xmapview.XMap(self.filename[2],self.difference,1.0/self.rate)

      for obj in self.objinsts:
        obj.recreate_graphmod()
    
#-------------------------------------------------------------------------
  def clone(self,**keywords):
#-------------------------------------------------------------------------
    import os
    if not os.path.exists(self.filename[2]) \
          or not os.path.isfile(self.filename[2]):
      MGGUI().WarningMessage('File no longer exists '+self.filename[2])
      return None
    
    m = MapData (filename=self.filename,dataparams=self.dataparams())
    rv = m.loaddata()
    if rv[0]==1:
      MGGUI().WarningMessage("ERROR loading data from file "+self.filename[2])
      m.delete()
      return None
    return m
 
     
#------------------------------------------------------------------
#------------------------------------------------------------------
#------------------------------------------------------------------
# The map display object class
#------------------------------------------------------------------
#------------------------------------------------------------------
#------------------------------------------------------------------


#--------------------------------------------------------------------------
class MapDisp(DispObj):
#--------------------------------------------------------------------------
  class_dependents = {}
  surface_style_menu = ['Chickenwire','Solid','Cylinders','Dots','Contour Slice','Mask','Multi-chicken']
  surface_style_alias= [ 'surface_style_chickenwire','surface_style_solid','surface_style_solid_chickenwire','surface_style_dots','surface_style_slice','surface_style_mask','surface_style_multichicken']
  contour_scale_menu = [['Absolute e/A', 'Sigma' ], \
                               ['absolute', 'sigma']]
  radius_menu = ["5.0","10.0","15.0","20.0"]
  sampling_rate_menu = ["0.5","0.75","1.0","1.5"]
  params_manager = None


  map_initialisation = {
    'surface_style' : 'surface_style_chickenwire',
    'radius' : 10.0,
    'contour_level': 0.0,
    'clip_mode' : 'OFF',
    'clip_MolDisp' : '',
    'clip_point': ['','','', 10.0],
    'atom_clip_radius': 1.5,
    'colour_by_radius': xmapview.COLOUR_BY_RADIUS_NONE,
    'point_clip_radius':  10.0 }

  map_initialisation_order = [ 'contour_level','surface_style','radius', \
            'clip_mode', 'clip_MolDisp', 'clip_point', \
                               'atom_clip_radius', 'point_clip_radius']

#---------------------------------------------------------------------
  def __init__(self,parent,name='',visible=1, params={}, restore_from_legend=0,**keywords):
#---------------------------------------------------------------------
  
    pars = {
      'colour' : 'magenta',
      'style' : 'surface_style_chickenwire' }
    
    for key,value in MapDisp.map_initialisation.items():
      pars[key]=value
  
    for item in ['surface_style','radius']:
      pars[item] =  PM('MapDispParamsManager').get(item)
    if len(get_dataobj(name=parent)[0].objnames) == 0:
      pars['colour']= PM('MapDispParamsManager').get('first_colour')
    else:
      pars['colour']= PM('MapDispParamsManager').get('other_colour')
    
    # Beware pre rel1.1 the plane_definition was a list
    if params.has_key('plane_definition'):
     import types
     if isinstance(params['plane_definition'],types.ListType):
       del params['plane_definition']

    pars.update(params)    
    pars.update(keywords)
    

    self.map_plane = MapPlane.MapPlane()
    
    if pars.has_key('plane_definition'):
      pars['plane_definition']['set_camera'] = 0
      self.map_plane.set_params(pars['plane_definition'])


    #print 'MapDisp.init',pars
    DispObj.__init__(self,'MapDisp',name,parent,visible=visible, \
                     params=pars)
   
    self.set_contour(update=0)
    self.set_colour(colour=self.colour,force=1)

    if pars['clip_mode'] == 'POINT':
      self.set_selection(force=1,clip_mode=pars['clip_mode'],clip_x=pars['clip_point'][0],clip_y=pars['clip_point'][1],clip_z=pars['clip_point'][2],point_clip_radius=pars['point_clip_radius'])
    else:
      self.set_selection(force=1,atom_clip_radius=pars['atom_clip_radius'], \
                 clip_mode=pars['clip_mode'],clip_MolDisp=pars['clip_MolDisp'])
    
    self.set_params(force=1,surface_style= self.surface_style)
    
    PM('MapDispParamsManager').add_dependent(self.handle_params)

    if self.transparent:
      self.set_transparency(transparent=self.transparent)
      self.set_opacity(opacity=self.opacity)
      

    self.do_redraw = 1

  def delete(self,**keywords):
    PM('MapDispParamsManager').remove_dependent(self.handle_params)
    """
    if self.graphmod:
      for glwidget in GLWIDGETS():
        glwidget.disconnect(glwidget,QtCore.SIGNAL("PositionChanged"),self.graphmod.handleGLWidgetChangePostion)
    """

    DispObj.delete(self)
    

  def get_style_label(self):
    return MapDisp.surface_style_menu[MapDisp.surface_style_alias.index(self.surface_style)]

  def get_contour_level(self):
    #print "MapDisp.get_contour_level",PM('MapDispParamsManager').get('contour_scale')
    #if PM('MapDispParamsManager').get('contour_scale') == 'sigma':
    #  return self.contour_level/self.parent.map_sd
    #else:
      return self.contour_level

  def get_contour_range(self):
    max_sigma = PM('MapDispParamsManager').get('contour_sigma_max')
    if PM('MapDispParamsManager').get('contour_scale') == 'absolute':
      range_max = self.parent.map_mean + (max_sigma*self.parent.map_sd)
      range_min = self.parent.map_mean - (max_sigma*self.parent.map_sd)
      #print "get_contour_range",max_sigma,range_min,range_max
      return (range_min,range_max)
    else:
      return (-max_sigma,max_sigma)

#-------------------------------------------------------------------------
  def handle_params(self,ParamsManager=None,updated={},**keywords):
#-------------------------------------------------------------------------
    if self.surface_style=='surface_style_dots' and (
      updated.has_key('dot_spacing') or updated.has_key('dot_size') ):
      self.set_params(surface_style='surface_style_dots',force=1)
    if self.surface_style=='surface_style_chickenwire' and (
      updated.has_key('line_width')):
      self.set_params(surface_style='surface_style_chickenwire',force=1)
    if self.surface_style=='surface_style_solid_chickenwire' and (
      updated.has_key('cylinder_width')):
      self.set_params(surface_style='surface_style_solid_chickenwire',force=1)

#------------------------------------------------------------------------
  def canBeTransparent(self):
#------------------------------------------------------------------------
    return 1

      
#-------------------------------------------------------------------------
  def recreate_graphmod(self):
#-------------------------------------------------------------------------
    '''
    Delete any existing graphmod and recreate with same parameters
    but expect that the parent clipper map has been changed
    '''
    #print "recreate_graphmod",self
    if self.graphmod:
       MAINWINDOW().removeGLDisplayObject(self.graphmod)
       self.graphmod = None
       
    self.do_redraw = 1
    self.draw()

#-------------------------------------------------------------------
  def clone (self,**keywords):
#-------------------------------------------------------------------
    pars = self.params()
    MapDisp(self.parent.name,visible=self.visible,params = pars)

  
#-------------------------------------------------------------------
  def params(self,all=1):
#-------------------------------------------------------------------
    pars = DispObj.params(self,all=all)
    if all:
      for item in MapDisp.map_initialisation.keys():
        pars[item]= getattr(self,item)
      for item in ['colour','style']:
         pars[item]= getattr(self,item)
    else:
      out = ['colour','style']
      for item in MapDisp.map_initialisation_order[0:3]:
        pars[item]= getattr(self,item,'')
      if self.clip_mode=='SELECTION':
        out.extend(['clip_mode','clip_MolDisp','atom_clip_radius'])
      elif  self.clip_mode=='POINT':
        out.extend(['clip_mode','clip_point','point_clip_radius'])
      else:
        out.extend(['clip_mode'])
      for item in out:
        pars[item]=getattr(self,item,'')
          
    pars['plane_definition'] = self.map_plane.params(all=all)
    #print 'MapDisp.params',pars
    return pars

#--------------------------------------------------------------------
  def update_data_status(self,shadowdisp):
#--------------------------------------------------------------------
    import utils
    diffs = utils.dict_diffs(self.params(),shadowdisp.params)[1]
    if not diffs: return 0
    if shadowdisp.params.get('clip_mode') == 'OFF':
       self.set_selection(clip_MolDisp = 'OFF')
    else:
      clip_point = shadowdisp.params.get('clip_point')
      self.set_selection (radius=shadowdisp.params.get('radius'),
             clip_MolDisp=shadowdisp.params.get('clip_MolDisp'),
             atom_clip_radius=shadowdisp.params.get('atom_clip_radius'),
             clip_x=clip_point[0],
             clip_y=clip_point[1],
             clip_z=clip_point[2],
             point_clip_radius=clip_point[3])
    self.set_contour(contour_level=shadowdisp.params.get('contour_level'))
    self.set_colour(colour=shadowdisp.params.get('colour'))
    for key in diffs.keys():
      if key == 'contour_level':
        self.set_contour(contour_level=diffs['contour_level'])
      elif key == 'ncontours':
        self.set_params(ncontours=str(diffs['ncontours']))
      elif key == 'surface_style':
        self.set_params(surface_style=diffs['surface_style'])
      elif key == 'plane_definition':
        if diffs['plane_definition']:
          self.map_plane.set_params( diffs['plane_definition'])
          self.map_plane.set_plane()
          
    DispObj.update_data_status0(self,shadowdisp)
    self.update_gui.append(['update'])
    return 1            

#--------------------------------------------------------------------
  def set_selection (self, radius='',clip_mode='',clip_MolDisp='', atom_clip_radius='',\
    clip_x='',clip_y='',clip_z='',point_clip_radius='',force = 0, **keywords ):
#--------------------------------------------------------------------
    #print "MapDisp.set_selection clip_MolDisp",clip_MolDisp,clip_mode
    import pygl_coord

    # Handle changes to extent or clip radii
    if radius: self.radius = float(radius)
    if atom_clip_radius:
      self.atom_clip_radius = float(atom_clip_radius)
    if point_clip_radius:
      self.point_clip_radius = float(point_clip_radius)
      
    # If updating the clip mode cancel any existing dependency
    if self.clip_mode == 'SELECTION' and (clip_mode != self.clip_mode or
                                          clip_MolDisp != self.clip_MolDisp):
         clip_dispobj = get_dispobj(object_type='MolDisp',name=self.clip_MolDisp)
         if clip_dispobj:
           self.remove_dependency(clip_dispobj.SelHandle,['selection','delete'])


    if clip_mode == 'OFF':
      self.clip_mode = 'OFF'

    # Switch on clipping to atoms
    elif clip_MolDisp and ( force or 
                          clip_MolDisp != self.clip_MolDisp or
                          self.clip_mode != 'SELECTION' ):
      clip_dispobj = get_dispobj(object_type='MolDisp',name=clip_MolDisp)
      #print "clip_dispobj",clip_MolDisp,clip_dispobj,
      if clip_dispobj and clip_dispobj.SelHandle.getNofAtoms()>0:
        self.clip_mode = 'SELECTION'
        self.clip_MolDisp = clip_MolDisp
        self.add_dependency(clip_dispobj.SelHandle,['selection','delete'],
                [self.handle_clip_MolDisp,self.handle_clip_MolDisp])

    # Switch on clipping to point
    elif (clip_x!='' or clip_y!='' or clip_z!=''):
      try:
        clip_x = float(clip_x)
      except:
        clip_x = 0.0
      try:
        clip_y = float(clip_y)
      except:
        clip_ = 0.0
      try:
        clip_z = float(clip_z)
      except:
        clip_z = 0.0
      self.clip_point = [clip_x,clip_y,clip_z,self.point_clip_radius]
      self.clip_mode = 'POINT'

    #print "MapDisp.set_selection clip_mode",self.clip_mode
    #sys.stdout.flush()

     # Update the graphics object
    self.do_redraw = 1
    #self.graphmod.rebuild()
    if self.clip_mode == 'SELECTION':
      self.selection_label = 'Clip to '+self.clip_MolDisp[0:max(10,len(self.clip_MolDisp))]
    elif self.clip_mode == 'POINT':
      self.selection_label = 'Clip to point'
    else:
      self.selection_label = 'Extent ' + str(self.radius)

#---------------------------------------------------------------------
  def set_style(self,value,**keywords):
#---------------------------------------------------------------------
    self.set_contour(value)

#-----------------------------------------------------------------------
  def set_contour(self,contour_level='',update=1,**keywords):
#----------------------------------------------------------------------
    # Assume the input contour_level is on the scale 
    # print "set_contour",contour_level,self.contour_level
    if contour_level: self.contour_level = float(contour_level)
    
    # Use the contour_level var to check against the gui style_label
    if PM('MapDispParamsManager').get('contour_scale') == 'sigma':
      scaled_contour = self.contour_level * self.parent.map_sd
    else:
      scaled_contour = self.contour_level

    #print "set_contour",self.contour_level,scaled_contour
        
    if self.graphmod: self.graphmod.obj.SetContourLevel(scaled_contour)
    self.do_redraw = 1

#-----------------------------------------------------------------------
  def draw(self):
#-----------------------------------------------------------------------
    #print "map.draw do_redraw",self.do_redraw; sys.stdout.flush()
    #print "radius", self.radius; sys.stdout.flush()
    #print "graphmod", self.graphmod; sys.stdout.flush()

    import pygl_coord

    transformMatrix = pygl_coord.matrix()
    xtl = CRYSTALMANAGER().getCrystal(self.parent.name)
    dataobj = get_dataobj(object_type='MolData')
    for dobj in dataobj:
      if hasattr(dobj,"masterCrystal") and dobj.masterCrystal == xtl and hasattr(dobj,"name"):
         if hasattr(dobj,"molHnd")  and hasattr(dobj.molHnd,"GetTransform") and callable(dobj.molHnd.GetTransform):
           transformMatrix = pygl_coord.matrix(4,4, dobj.molHnd.GetTransform())
           if self.graphmod:
              self.graphmod.obj.SetTransformMatrix(transformMatrix)

    if not self.do_redraw and not self.do_recolour and self.graphmod:
      if self.do_update_opacity:
         self.graphmod.obj.SetAlpha(self.opacity)
         self.do_rebuildGL.append('graphmod')
         self.do_update_opacity = 0
         return 1
      else:
         return 0
         

    pm=PM('MapDispParamsManager')
    plane = pygl_coord.Plane(1,0,0,0)
    plottype = xmapview.CHICKENWIRE
    linestyle = xmapview.WIREFRAME
    if self.surface_style == 'surface_style_chickenwire':
        plottype = xmapview.CHICKENWIRE
        linestyle = xmapview.WIREFRAME
    if self.surface_style == 'surface_style_multichicken':
        plottype = xmapview.MULTICHICKEN
        linestyle = xmapview.WIREFRAME
    elif self.surface_style == 'surface_style_marching_cubes':
        plottype = xmapview.MARCHINGCUBES
        linestyle = xmapview.WIREFRAME
    elif self.surface_style == 'surface_style_solid':
        plottype = xmapview.MARCHINGCUBES
        linestyle = xmapview.SOLID
    elif self.surface_style == 'surface_style_solid_chickenwire':
        plottype = xmapview.CHICKENWIRE
        linestyle = xmapview.SOLID
    elif self.surface_style == 'surface_style_slice':
        self.map_plane.update_plane()
        plane = self.map_plane.plane
        plottype = xmapview.CONTOURS
        linestyle = xmapview.WIREFRAME
    elif self.surface_style == 'surface_style_mask':
        self.map_plane.update_plane()
        plane = self.map_plane.plane
        plottype = xmapview.MASK
        linestyle = xmapview.WIREFRAME
    elif self.surface_style == 'surface_style_dots':
        plottype = xmapview.MARCHINGCUBES
        linestyle = xmapview.DOTS
    line_width = pm.get('line_width')
    cylinder_width = pm.get('cylinder_width')
    dot_spacing = pm.get('dot_spacing')
    dot_size = pm.get('dot_size')

    if not self.graphmod:
      import mapgraphicsmodel

      if PM('MapDispParamsManager').get('contour_scale') == 'sigma':
        scaled_contour = self.contour_level * self.parent.map_sd
      else:
        scaled_contour = self.contour_level


      if not self.parent.is_em_map:
        # XTAL MAP
        self.graphmod = mapgraphicsmodel.mapgraphicsmodel(self.parent.clipper_map,VW('mainview').com,VW('mainview').origin,contour_level=scaled_contour,radius=self.radius,plottype=plottype,linestyle=linestyle,wiresize=line_width,dotSize=dot_size,dotSpacing=dot_spacing,plane=plane,transformMatrix=transformMatrix,cylindersize=cylinder_width)
        #print "MapDisp.draw",self.graphmod
        for glwidget in GLWIDGETS():
          glwidget.connect(glwidget,QtCore.SIGNAL("PositionChanged"),self.graphmod.handleGLWidgetChangePostion)
        print "Connected move signal"; sys.stdout.flush()
      else:
        #EM MAP
        map_orig = self.parent.clipper_map.GetOrigin()
        draw_orig = (map_orig.get_x(),map_orig.get_y(),map_orig.get_z())
        print "Set origin of map to",draw_orig
        self.graphmod = mapgraphicsmodel.mapgraphicsmodel(self.parent.clipper_map,VW('mainview').com,draw_orig,contour_level=scaled_contour,radius=self.radius,plottype=plottype,linestyle=linestyle,wiresize=line_width,dotSize=dot_size,dotSpacing=dot_spacing,plane=plane,transformMatrix=transformMatrix,cylindersize=cylinder_width)
        #FIXME - Need to determine this properly!
        self.radius = 0.45*self.parent.clipper_map.GetMaxDim()

      if len(GLWIDGETS())>0:
	    glwidget=GLWIDGETS()[0]
            # Not for EM, sigh
            if not self.parent.is_em_map:
	     self.graphmod.CentreOn((-glwidget.rpos[0],-glwidget.rpos[1],-glwidget.rpos[2]))
      self.set_params()
      rgb = MGCOLOUR().RGB(self.colour)
      self.graphmod.obj.SetColour(rgb[0],rgb[1],rgb[2])
      if self.parent.is_em_map:
        self.graphmod.obj.SetColourByRadius(self.colour_by_radius)
      BUILD().append(self.graphmod)
      self.graphmod.obj.SetAlpha(self.opacity)
      self.do_recolour = 0
      self.do_redraw = 1
    
    if self.do_recolour:
      rgb = MGCOLOUR().RGB(self.colour)
      #print "map.draw rgb",self.colour,rgb
      self.graphmod.obj.SetColour(rgb[0],rgb[1],rgb[2])
      self.do_recolour = 0
      self.do_redraw = 1

    if  self.do_redraw:
      if plane:
        self.map_plane.update_plane()
        self.graphmod.obj.SetPlane(self.map_plane.plane)
        self.graphmod.obj.SetContourLevelStep(self.map_plane.contour_spacing)
      self.graphmod.obj.SetPlotType(plottype)
      self.graphmod.obj.SetLineStyle(linestyle)
      self.graphmod.obj.SetLineWidth(line_width)
      self.graphmod.obj.SetCylinderWidth(cylinder_width)
      self.graphmod.obj.SetDotSpacing(dot_spacing)
      self.graphmod.obj.SetDotSize(dot_size)
      
      self.graphmod.obj.SetRadius(self.radius)
      if self.clip_mode == 'SELECTION':
        self.graphmod.obj.SetClipRadius(self.atom_clip_radius)
        obj = get_dispobj(object_type='MolDisp',name= self.clip_MolDisp)
        if obj:
          nSelAtoms,SelAtoms=obj.SelHandle.getSelIndex()
          import atom_util
          if nSelAtoms > -1:
            clip_vec = atom_util.CartesiansFromAtoms(SelAtoms,nSelAtoms)
          else:
            clip_vec = pygl_coord.CartesianVector()
          self.graphmod.obj.SetClipPositions(clip_vec)
        else:
          self.clip_mode = 'OFF'
          
      if self.clip_mode=='POINT':
        self.graphmod.obj.SetClipRadius(self.point_clip_radius)
        clip_vec = pygl_coord.CartesianVector(1)
        clip_vec[0]=pygl_coord.Cartesian(self.clip_point[0],self.clip_point[1],self.clip_point[2])
        self.graphmod.obj.SetClipPositions(clip_vec)
      elif self.clip_mode=='OFF':
        clip_vec = pygl_coord.CartesianVector(0)
        self.graphmod.obj.SetClipPositions(clip_vec)

      self.graphmod.rebuild()
      self.graphmod.obj.SetAlpha(self.opacity)



    self.do_redraw=0
    self.do_rebuildGL.append('graphmod')
    return 1
      
#------------------------------------------------------------------------
  def set_params(self,surface_style='',force=0,**keywords):
#-----------------------------------------------------------------------

    #print "MapDisp set_params surface_style",surface_style,self.surface_style
                                 

    if surface_style and (force or surface_style != self.surface_style): 
      self.surface_style = surface_style


      self.do_redraw = 1

#---------------------------------------------------------------
  def handle_clip_MolDisp(self,attribute='',master='',**keywords):
#---------------------------------------------------------------
    import pygl_coord
    clip_dispobj = get_dispobj(name=self.clip_MolDisp)
    if not clip_dispobj:   return
    #print "clip_dispobj",clip_dispobj
    
    if attribute == 'selection':
      #print "handle_clip_MolDisp selection"
      # First redraw all of the density
      tmp_clip_vec = pygl_coord.CartesianVector(0)
      self.graphmod.obj.SetClipPositions(tmp_clip_vec);
      del tmp_clip_vec
      nSelAtoms,SelAtoms = clip_dispobj.SelHandle.getSelIndex()
      import atom_util
      clip_vec = atom_util.CartesiansFromAtoms(SelAtoms,nSelAtoms)
      #print "handle_clip_MolDisp nSelAtoms",nSelAtoms
    elif attribute == 'delete':
      self.clip_mode = 'OFF'
      self.clip_MolDisp = ''
      clip_vec = pygl_coord.CartesianVector(0)

    if self.graphmod:
      self.graphmod.obj.SetClipPositions(clip_vec);
    self.do_redraw = 1

#------------------------------------------------------------------
  def movie_interpolation(self,initial_status=None,final_status=None, \
                          fraction=0.0,step=0,**keywords):
#------------------------------------------------------------------
    if initial_status and final_status:
      delta = float(final_status.params['contour_level'])- \
              float(initial_status.params['contour_level'])
      self.set_contour(contour_level = \
        float(initial_status.params['contour_level'])+fraction*delta)
    #print "MapDisp.movie_interpolation",fraction,delta

    DispObj.movie_interpolation(self,initial_status=initial_status, \
          final_status=final_status,fraction= fraction,step=step)    
      

        

#-----------------------------------------------------------------------
def openMTZ (filename='',f='',phi='',wt='', \
            use_wt='',difference ='0',rate='',maptype='MTZ',structFile='',**keywords):
#-----------------------------------------------------------------------
  # If no f or phi defined then this is a request to
  # update the gui with the list of f/phi extracted from
  # the mtx file
    print "openMTZ",structFile
    import utils,string,os
    f = string.strip(f)
    phi = string.strip(phi)
    wt = string.strip(wt)
    rate = string.strip(rate)
    if len(rate) < 1:
      rate = 1.5
    else:
      rate = float(rate)
    if len(phi) < 1 or len(f) < 1: return None
    use_wt = 0
    if use_wt: use_wt = int(use_wt)
    if difference: difference = int(difference)
    if not use_wt or wt == 'No_WEIGHT': wt = ''

    if filename and os.access(filename,os.R_OK):
      m = MapData(filename=filename,structFile=structFile,f=f,phi=phi,wt=wt,rate=rate,difference=difference)
      m.filetype = maptype
      rv = m.loaddata()
      if rv[0]:
        MGGUI().WarningMessage( "File not readable: "+filename[2] )
        del m
        return None
    else:
      MGGUI().WarningMessage( "File not readable: "+filename[2] )
      return None


    m.create_contours(difference=difference)
    import rebuild
    rebuild.UpdateDisplay()
    return m


#==========================================================================
# MapData.ParamsManager automatically created on startup
#==========================================================================

def createDrawingStylePM(name='MapDispParamsManager'):
  # Default is to return the 'standard' MapDisp.params_manager
  # but if standard=0 will create and return a new instance of
  # ParamsManager with Map parameters set
  import services
    
  colour_menu,colour_alias = MGCOLOUR().colour_menu()
  pm = services.ParamsManager ( \
          name=name, \
          help = 'maps#preferences' ,
          picture_definition = 1,
          title='Map drawing style', \
          gui=['sampling_rate','radius','surface_style','contour_scale', \
               'contour_sigma_max', 'first_colour','other_colour','diff_pos_colour','diff_neg_colour','dot_spacing','dot_size', 'line_width','cylinder_width'], \
      default = {
    'radius': 10.0,
    'surface_style': 'surface_style_chickenwire',
    'contour_scale': 'absolute',
    'contour_sigma_max' : 5.0,
    'ncontours' : 1,
    'sampling_rate' : 0.75,
    'dot_spacing' : 0.3,
    'dot_size' : 1.0, \
    'line_width' : 1.0, \
    'cylinder_width' : 0.03, \
    'first_colour' : 'blue',
    'diff_pos_colour' : 'green',
    'diff_neg_colour' : 'red',
    'other_colour' : 'magenta' }, \
    definition = {
      'radius' : dict(type=float,label='Extent',style='spinbox',max=50.0,min=0.0,step=5.0),
      'dot_spacing' : dict(type=float, label='Maximum dot separation(0.005-0.5)',style='spinbox',max=0.5,min=0.005,step=0.01),
      'dot_size' : dict(type=float, label='Dot size(1.0-3.0)',style='spinbox',max=3.0,min=1.0,step=1.0),     
      'line_width' : dict(type=float, label='Chickenwire line width',style='spinbox',max=5.0,min=0.1,step=1.0),
      'cylinder_width' : dict(type=float, label='Cylinders width',style='spinbox',max=1.0,min=0.01,step=.01),
      'sampling_rate' : dict(type=float,label='Sampling rate (MTZ/CIF data only)',style='spinbox',max=5.0,min=0.01,step=0.1),
      'surface_style' : dict(type=str,label='Surface drawing style',style='combobox',menu=['Chicken wire','Solid','Cylinders','Dots'],alias= [ 'surface_style_chickenwire','surface_style_solid','surface_style_solid_chickenwire','surface_style_dots'] ),
      'contour_scale' : dict(type=str,label='Contour scale in',style='combobox',menu =['Absolute e/A', 'Sigma'],alias=['absolute', 'sigma']),
      'contour_sigma_max' : dict(type=float,label='Max/min contour level for sigma mode',style='spinbox',max=10.0,min=1.0,step=1.0),
      'ncontours' : dict(type=int,label='Number of contour levels',style='spinbox',max=4,min=0,step=1),
      'first_colour' : dict(type=str, label='First contour colour',style='combobox' , menu=colour_menu,alias=colour_alias ),
      'other_colour' : dict(type=str,label='Second contour colour',style='combobox',menu=colour_menu,alias=colour_alias),
      'diff_pos_colour' : dict(type=str,label='+ve diff. map colour',style='combobox',menu=colour_menu,alias=colour_alias),
      'diff_neg_colour' : dict(type=str,label='-ve diff. map colour',style='combobox',menu=colour_menu,alias=colour_alias)
             })
    
  return pm
