"""
     python/ui/FieldDisp.py: CCP4MG Molecular Graphics Program
     Copyright (C) 2001-2008 University of York, CCLRC
     Copyright (C) 2009 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 GUI
from utils import *
import os
import string
from dataobj import *
import model
import build
import view
from global_definitions import *
from MapPlane import MapPlaneSet

def fielddata(name):
  if FieldData.names.count(name) <= 0:
    return ""
  else:
    i = FieldData.names.index(name)
    return FieldData.insts[i]

class FieldData(DataObj):
  names = []
  insts = []
  class_dependents = {}
  
  def __init__(self,filename=[],name='',dataparams={},restore_from_version=0,**kw):
    self.module = 'FieldDisp'
    self.rate = 0.2
    self.style=''
    DataObj.__init__(self,'FieldData',name=name,module='FieldDisp', \
                     filename=filename,dataparams=dataparams)
    if FieldData.names.count(name) == 0:
      FieldData.names.append(name)
      FieldData.insts.append(self)
      
  def delete(self,**keywords):
    DataObj.delete(self)
    del self

  def dataparams(self,all=1):
    datapar = DataObj.dataparams(self)
    datapar['modules'] = ['FieldDisp']
    for item in ['rate']:
      datapar[item]=getattr(self,item)
    return datapar

  def loaddata(self,**keywords):
    import field
    import mapview
    self.fields = field.ReadCubeFile(self.filename[2])
    self.gui_create()
    self.update_dependents('create')
    return [0,'']

  def create_contours(self):
    s = FieldDisp ( self.name )
     
  def add_object(self,params={},**keywords):
    dobj = FieldDisp(self.name,visible=1,params=params)
    return dobj

  def define_icon(self,window=''):
    if self.visible:
      visibility_label = 'Hide'
    else:
      visibility_label = 'Show'
    guidef = [
      ['WINDOW_ID',window],
      ['PARAM','toggle_visibility',
        ['TYPE','_logical'],
        ['INITIAL',self.visible],
        ['RETURN_METHOD','set_visibility'],
        ['LABEL',visibility_label] ],
      ['PARAM','delete',
        ['TYPE','_logical'],
        ['INITIAL','0'],
        ['RETURN_METHOD','delete'],
        ['LABEL','Delete'] ],
      ['PARAM','list_file',
        ['TYPE','_logical'],
        ['INITIAL','0'],
        ['RETURN_METHOD','list_data_file'],
        ['LABEL','List map stats']],
      ['PARAM','_sampling_rate',
        ['TYPE','_logical'],
        ['INITIAL','0'],
        ['RETURN_METHOD','sampling_rate_gui'],
        ['LABEL','Grid spacing']],
      ['PARAM','add_object',
        ['TYPE','_logical'],
        ['INITIAL','0'],
        ['RETURN_METHOD','add_object'],
        ['LABEL','Add object'] ],
      
      ['DISPLAY','PULLDOWN', [
        ['com','toggle_visibility'],
        ['com','delete'],
        ['com','_sampling_rate'],
        ['com','add_object'] ] ]
      ]
     #   ['com','list_file'],
    GUI.insts.CreateGUIWindow('icon'+self.name,self,guidef)

  def list_data_file(self,**keywords):
    pass


#--------------------------------------------------------------------
  def sampling_rate_gui(self,_sampling_rate='',sampling_rate='',exit='',**keywords):
#--------------------------------------------------------------------
    '''
    Create and handling map sampling rate GUI
    '''

    # NB The GUI is actually for grid size in Angstrom
    # ie reciprocal of sampling rate
    
    if _sampling_rate:
      GUI.insts.CreateGUIWindow ('sampling_rate',self, [
            ['TITLE','Contour grid size'],
            ['RETURN_METHOD','sampling_rate_gui',
              ['RETURN_LIST',
               ['sampling_rate::param_value',['ALIAS','sampling_rate']]]],
            ['OBJECT','sampling_rate',
              ['TYPE','Wheel'],
              ['CONFIGURE',
                 ['scale','0.05'],
                 ['label','grid size'],
                 ['message','Set the contour grid size'],
                 ['param_name','sampling_rate'],
                 ['max_value','3.0'],
                 ['min_value','0.02'],
                 ['entry','1'],
                 ['param_value',str(self.rate)]]],
            ['DISPLAY','WINDOW',
                ['LINE',
                  ['LABEL','Recalculate contour with']],
                ['LINE',['OBJECT','sampling_rate']],
              ['BUTTONS',
                ['ok',['LABEL','Apply']],
                ['dismiss',['CLOSE']]]
             ] ] )

    # Only act after user hit Apply button
    #elif exit == 'ok':
    #  self.rate = float(sampling_rate)
    #  #print "reset sampling",self.rate#

    #  if self.clipper_map: self.clipper_map = None
    #  import xmapview
    #  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)

    #  for obj in self.objinsts:
    #    obj.recreate_graphmod()


def fielddisp(parent,name):
  m = fielddata(parent)
  if not m: return ""
  if m.objnames.count(name) <= 0:
    return ""
  else:
    i = m.objnames.index(name)
    return m.objinsts[i]

class FieldDisp(DispObj,MapPlaneSet):
  class_dependents = {}
  def __init__(self,parent,name='',visible=1, params={}, restore_from_version=0,**keywords):
    import field
    import mapview
    import build
    import nxmapgraphicsmodel
    import pygl_coord
    import map
    pars = {}
    pars['surface_style'] =  map.MapParamsManager().get('surface_style')
    pars['contour_level']= 0.1
    pars['ncontours']= 1
    pars['selection']= 0
    pars['maxval']= 0
    pars['minval']= 0
    pars['plane'] = pygl_coord.Plane(1,0,0,0)
    pars['plane_definition'] = []
   
    import dataobj
    if dataobj.get_dataobj(parent) and len(dataobj.get_dataobj(parent)[0].objnames)> 0:
      pars['colour']=  map.MapParamsManager().get('other_colour')
    else:
      pars['colour']=  map.MapParamsManager().get('first_colour')
    pars.update(params)
    pars.update(keywords)
    DispObj.__init__(self,'FieldDisp',name,parent,visible=visible,params=pars)
    
    f = field.GetField(self.parent.fields,self.selection)
    f.GenerateStats()
    self.maxval = f.Max()
    self.minval = f.Min()
    if self.maxval < self.minval:
      self.maxval = 10
      self.minval = -10
    if abs(self.maxval) > abs(self.minval):
      self.minval = -self.maxval
    else:
      self.maxval = -self.minval
      
    self.graphmod = nxmapgraphicsmodel.nxmapgraphicsmodel(self.parent.fields,ifield=self.selection,ncont=self.ncontours)
    self.graphmod.ui = self
    if not self.plane_definition:
      self.plane_definition = MapPlaneSet.initialisation
    MapPlaneSet.__init__(self)
    build.build.insts.append(self.graphmod)
    self.gui_object = self.name
    resol = (self.maxval-self.minval)/50.
    self.gui_create(style_widget=['SCALE',self.minval,self.maxval,resol],style=str(self.contour_level)) 
    self.set_selection(force=1)
    self.set_colour(force=1)
    self.set_style(float(self.contour_level))
    self.set_params(self.surface_style,force=1)


  def define_icon(self,window=''):
    import map
    style_menu = []
    style_alias = []
    for item in map.MapDisp.surface_style_menu: style_menu.append(item)
    for item in map.MapDisp.surface_style_alias: style_alias.append(item)
    style_menu.append("Contour Slice")
    style_alias.append("slice")
    style_menu.append("Mask")
    style_alias.append("mask")

    if self.visible:
      visibility_label = 'Hide'
    else:
      visibility_label = 'Show'

    guidef = [
      ['WINDOW_ID',window],
      ['PARAM','toggle_visibility',
        ['TYPE','_logical'],
        ['INITIAL',self.visible],
        ['RETURN_METHOD','set_visibility'],
        ['LABEL',visibility_label] ],
      ['PARAM','ncontours',
        ['TYPEDEF','menu',['Single Contour','Plus/Minus Contours'],['1','-1']],
        ['INITIAL',str(self.ncontours)],
        ['LABEL','Contour mode'],
        ['RETURN_METHOD','set_params']],
      ['PARAM','centre_on',
        ['TYPE','_logical'],
        ['INITIAL','0'],
        ['LABEL','Centre on'],
        ['RETURN_METHOD',"centre_on"] ],
        ['PARAM','surface_style',
         ['TYPEDEF','_menu', style_menu ,
                             style_alias ],
         ['INITIAL',self.surface_style],
         ['RETURN_METHOD','set_params'],
         ['LABEL','Surface style ..'] ],
       ['PARAM','plane',
        ['TYPE','_logical'],
        ['INITIAL','0'],
        ['LABEL','Contour slice details'],
        ['RETURN_METHOD',"define_plane"] ],     
       ['PARAM','clone',
        ['TYPE','_logical'],
        ['INITIAL','0'],
        ['LABEL','Clone'],
        ['RETURN_METHOD',"clone"] ],     
      ['PARAM','delete',
        ['TYPE','_logical'],
        ['INITIAL','0'],
        ['RETURN_METHOD',"delete"],
        ['LABEL','Delete'] ],
      ['DISPLAY','PULLDOWN', [
        ['com','toggle_visibility'],
        ['rb2','ncontours'],
        ['com','plane'],
        ['rb2','surface_style'],
        ['com','clone'],
        ['com','delete'] ] ]
      ]
     #   ['com','centre_on'],

    GUI.insts.CreateGUIWindow('icon'+self.name,self,guidef)

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


  def update_contour_range(self):
    resol = (self.maxval-self.minval)/50.
    self.style_label = str(self.contour_level)
    try:
      GUI.insts.SetAttributes(self.gui_object,[['style',str(self.style_label)],
        ['style_widget',GUI.insts.writeguilist(['SCALE',self.minval,self.maxval,resol])]])
      
    except:
      print "Error updating gui DataObj" + self.name

  def params(self,all=1):
    pars = DispObj.params(self)
    for item in ['contour_level','ncontours','surface_style','plane_definition']:
      pars[item]=getattr(self,item)
    return pars

  def update_data_status(self,shadowdisp):
    import utils
    rv = 0
    diffs = utils.dict_diffs(self.params(),shadowdisp.params)[1]
    if diffs:
      rv = 1
      self.update_gui.append(['update'])
    #print "FieldDisp update_data_status",self,diffs
    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':
        self.set_plane(plane_definition= diffs['plane_definition'])

    rv = max(rv,DispObj.update_data_status0(self,shadowdisp) )
    return rv

  def set_selection(self,selection='',orbital='',force=0, **keywords):
    import nxmapgraphicsmodel
    import field
    if orbital or selection or force:
      if selection: self.selection = int(selection)
      if orbital: self.selection = int(orbital)
      self.graphmod.obj.define_field(field.GetField(self.parent.fields,self.selection))
      self.do_redraw = 1
      #self.graphmod.build_primitives()
      self.selection_label = 'Orbital '+str( self.selection)
      GUI.insts.SetAttributes(self.gui_object,[['selection',self.selection_label]])
      f = field.GetField(self.parent.fields,self.selection)
      f.GenerateStats()
      self.maxval = f.Max()
      self.minval = f.Min()
      if self.maxval < self.minval:
        self.maxval = 10
        self.minval = -10
      if abs(self.maxval) > abs(self.minval):
        self.minval = -self.maxval
      else:
        self.maxval = -self.minval
      self.update_contour_range()

  def define_selection (self, window=''):
     import field
     orbital_menu = []
     for i in range(field.GetNumFields(self.parent.fields)):
        orbital_menu.append(i)

     guidef = [
          ['TITLE','Select Molecular Orbital'],
          ["WINDOW_ID",window],
          ["RETURN_METHOD", "set_selection"],
    	  ["PARAM","orbital",
             ["TYPEDEF","menu",orbital_menu,orbital_menu],
             ["INITIAL",str(self.selection)],
             ["LABEL","Orbital"] ],
          ["DISPLAY","PULLDOWN", [
                  ['rb2','orbital']
               ]
	  ] ]
     GUI.insts.CreateGUIWindow ('fieldobj_selmenu',self,guidef)

  def set_style(self,value,**keywords):
    self.set_contour(value,update=0)

  def set_contour(self,contour_level='',update=1,**keywords):
    self.contour_level = float(contour_level)
    self.graphmod.obj.SetMaxContourLevel(self.contour_level)
    self.graphmod.obj.SetMinContourLevel(-self.contour_level)
    self.do_redraw = 1
    if self.style_label != str(contour_level):
      self.style_label = contour_level
      if int(update):
        GUI.insts.SetAttributes( self.gui_object,[['style',self.style_label]])

  def set_colour ( self,colour='',force=0,**keywords):
    changed = COneColour.set_colour(self,colour=colour)
    if force or changed :
      rgb = MGCOLOUR().RGB(self.colour)
      self.graphmod.obj.SetColour(rgb[0],rgb[1],rgb[2])
    self.colour_label = self.colour
    GUI.insts.SetAttributes(self.gui_object,[['colour',self.colour_label]])

  def draw(self):

    if not self.do_redraw: return 0
    self.graphmod.obj.SetNumberOfContours(self.ncontours);

    self.graphmod.build_primitives()
    self.do_rebuildGL.append('graphmod')
    self.do_redraw = 0
    return 1

  def set_params(self,surface_style='',ncontours='',force=0,**keywords):
    import mapview
    import build

    if ncontours and ['1','-1'].count(ncontours):
      self.ncontours = int(ncontours)
      self.do_redraw = 1

    if surface_style and ((surface_style != self.surface_style) or force>0): 
      self.surface_style = surface_style
      
      if self.surface_style == 'chickenwire':
        self.graphmod.obj.SetPlotType(mapview.CHICKENWIRE)
        self.graphmod.obj.SetLineStyle(mapview.WIREFRAME)
      elif self.surface_style == 'marching_cubes':
        self.graphmod.obj.SetPlotType(mapview.MARCHINGCUBES)
        self.graphmod.obj.SetLineStyle(mapview.WIREFRAME)
      elif self.surface_style == 'solid':
        self.graphmod.obj.SetPlotType(mapview.MARCHINGCUBES)
        self.graphmod.obj.SetLineStyle(mapview.SOLID)
      elif self.surface_style == 'solid_chickenwire':
        self.graphmod.obj.SetPlotType(mapview.CHICKENWIRE)
        self.graphmod.obj.SetLineStyle(mapview.SOLID)
      elif self.surface_style == 'slice':
        self.graphmod.obj.SetPlane(self.plane)
        self.graphmod.obj.SetPlotType(mapview.CONTOURS)
      elif self.surface_style == 'mask':
        self.graphmod.obj.SetPlane(self.plane)
        self.graphmod.obj.SetPlotType(mapview.MASK)
        self.graphmod.obj.SetLineStyle(mapview.SOLID)


      self.do_redraw = 1
      #self.graphmod.build_primitives()


  def centre_on(self,**keywords):
    import field
    import pygl_coord
    import build
    origin = pygl_coord.CartesianPtr(field.GetField(self.parent.fields,self.selection).origin)
    build.build.insts.glthread.glevent.centre_on(origin,self.graphmod.obj,zoom=1)
      # ,plane=plane)

