"""
     python/ui/picture_definition_classes.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.
"""
import dataobj,os.path
DataList = []
DataLookup = {}
CrystalList = []
twoDList = []
InlineList = []
SelectionSchemeList = []
ColourSchemeList = []
global ERROR_MESSAGE
ERROR_MESSAGE = []


def get_dataobj(name=''):
  rv = dataobj.get_dataobj(name='')
  if rv:
    return rv[0]
  else:
    return None


def DataObj_isGZIPPED(name='',dataparams={},object_type='MolData'):
  import utils
  if not name:
      if dataparams.has_key('filename'):
        if dataparams['filename'][1]:
          fname = dataparams['filename'][1]
        elif  dataparams['filename'][2]:
          fname = dataparams['filename'][2]
        name =  os.path.split(os.path.splitext(fname)[0])[-1]
        ext = os.path.splitext(fname)[1][1:].lower()
        extgz = None
        if ext == 'gz':
           ext2 = os.path.splitext(os.path.splitext(fname)[0])[1]
           if ext2 != '':
             extgz = (ext2 + '.' + ext)[1:].lower()
             fname = utils.gunzipToNamedFile(fname)
             if not fname: return False
             if dataparams['filename'][1]:
                dataparams['filename'][1] = fname
             elif  dataparams['filename'][2]:
                dataparams['filename'][2] = fname
             return True
  return False

def DataObj_name(name='',dataparams={},object_type='MolData'):
  if not name:
      if dataparams.has_key('filename'):
        if dataparams['filename'][1]:
          name =  os.path.split(os.path.splitext(dataparams['filename'][1])[0])[-1]
        elif  dataparams['filename'][2]:
          name =  os.path.split(os.path.splitext(dataparams['filename'][2])[0])[-1]
      else:
        name = object_type+str(len(DataList)+1)
  return name

def DispObj_parent(parent='',name='',object_type='MolData'):
    import types
    parent_obj = None
    #print "DispObj_parent in",parent,DataLookup
    if parent:
      if isinstance(parent,types.StringType):
        if DataLookup.has_key(parent):
          parent_obj = DataLookup[parent]
      elif isinstance (parent,dataobj.DataObj):
        for shadow in DataList:
          if shadow.dataobj == parent:
            parent_obj = shadow
            break        
    elif name:
      for obj in DataList:
        if obj.object_type == object_type and obj.objnames.count(name):
          parent_obj = obj
    if not parent_obj:
      if len(DataList)>0:
        for ii in range(len(DataList)-1,-1,-1):
          if DataList[ii].object_type == object_type:
            parent_obj = DataList[ii]
            break
    #print "parent_obj",parent_obj
    return parent_obj

def DispObj_name(parent_obj=None,name='',object_type='MolDisp'):
  if name:
    exi = parent_obj.objnames.count(name)
    if not exi and hasattr(parent_obj,'dataobj'):
      exi = parent_obj.dataobj.objnames.count(name)
    if not exi: return name

  n = len(parent_obj.objnames)
  if hasattr(parent_obj,'dataobj'): n = n + len(parent_obj.dataobj.objnames)
  contu = 1
  while contu:
    n = n + 1
    nname = parent_obj.name+object_type+str(n)
    contu = parent_obj.objnames.count(nname)
    if not contu and hasattr(parent_obj,'dataobj'):
      contu = parent_obj.dataobj.objnames.count(nname)
  return nname

def ReadFile(filename=""):
  try:
    f = open(filename)
    text = f.read()
    f.close()
  except:
    text=""

  return text
 
#--------------------------------------------------------------------
class MolData(dataobj.DataObjShadow):
#--------------------------------------------------------------------
  def __init__(self,name='',reference='',objnames=[],visible=1,display_objects=[],**dataparams):
    dataparams['visible']=visible
    isGZ = DataObj_isGZIPPED(name=name,dataparams=dataparams,object_type='MolData')
    name = DataObj_name(name=name,dataparams=dataparams,object_type='MolData')
    if name:
      #print "Setting name to",name
      dataparams["name"] = name
    
    # Beware the following lines are VERY necessary to prevent all dataobjects
    # containing all display objects
    objnames = []
    for item in display_objects: objnames.append(item)
    objinsts = []

    self.reference = reference
    
    dataobj.DataObjShadow.__init__(self,name=name,object_type='MolData',objnames=objnames,objinsts=objinsts,dataparams=dataparams)
    #dataobj.DataObjShadow.set(display_objects=display_objects,dataparams=dataparams)
    DataList.append(self)
    DataLookup[name]=self
    #print 'Loaded picture definition: MolData',name


  def get(self,mode=''):
    if not hasattr(self,'dataobj'):
      self.restore()

    if hasattr(self,'dataobj'):
      return self.dataobj.get(mode=mode)
    else:
      return []

      
#--------------------------------------------------------------------
class MolDisp(dataobj.DispObjShadow):
#--------------------------------------------------------------------

  def __init__(self,name='',parent='',object_type='MolDisp',selection_parameters={},colour_parameters={},style_parameters={},visible=1,**keywords):

    global ERROR_MESSAGE
    
    parent_obj= DispObj_parent(parent=parent,name=name,object_type='MolData')
    if not parent_obj:
      ERROR_MESSAGE.append('Can not find parent DataObj for '+object_type + ' ' + name)
      return
    name = DispObj_name(parent_obj=parent_obj,name=name,object_type='MolDisp')
    
    dataobj.DispObjShadow.__init__(self,name=name,object_type=object_type,selparams=selection_parameters,colparams=colour_parameters,styleparams=style_parameters,visible=visible,params=keywords)
    
    if self.params.has_key('selection'):
      rv = self.convert_selection(self.params['selection'])
      if not rv[0]:
        self.params['selection'] = rv[1]
      else:
        print name + ' : ' + rv[1]

    if not parent_obj.objnames.count(name):
      parent_obj.objnames.append(name)
      parent_obj.objinsts.append(self)
      #print "parent_obj.objnames",parent_obj.name,parent_obj.objnames,parent_obj.objinsts
      
    #print 'Loaded picture definition: MolDisp',name,'in DataObj',parent_obj.name
#--------------------------------------------------------------------    
class HBonds(dataobj.DispObjShadow):
#--------------------------------------------------------------------  
   def __init__(self,name='',parent='',object_type='HBonds',selection_parameters={},colour_parameters={},style_parameters={},visible=1,**keywords):

     parent_obj= DispObj_parent(parent=parent,name=name,object_type='MolData')
     if not parent_obj:
       global ERROR_MESSAGE
       ERROR_MESSAGE.append('Can not find parent DataObj for '+object_type + ' ' + name)
       return
     name = DispObj_name(parent_obj=parent_obj,name=name,object_type='HBonds')

     dataobj.DispObjShadow.__init__(self,name=name,object_type=object_type,selparams=selection_parameters,colparams=colour_parameters,styleparams=style_parameters,visible=visible,params=keywords)

     if not parent_obj.objnames.count(name):
       parent_obj.objnames.append(name)
       parent_obj.objinsts.append(self)

     #print 'Loaded picture definition: Hbonds',name

#--------------------------------------------------------------------
class Contacts(dataobj.DispObjShadow):
#--------------------------------------------------------------------  
   def __init__(self,name='',parent='',object_type='Contacts',selection_parameters={},colour_parameters={},style_parameters={},visible=1,**keywords):

     parent_obj= DispObj_parent(parent=parent,name=name,object_type='MolData')
     if not parent_obj:
       global ERROR_MESSAGE
       ERROR_MESSAGE.append('Can not find parent DataObj for '+object_type + ' ' + name)
       return
     name = DispObj_name(parent_obj=parent_obj,name=name,object_type='Contacts')

     dataobj.DispObjShadow.__init__(self,name=name,object_type=object_type,selparams=selection_parameters,colparams=colour_parameters,styleparams=style_parameters,visible=visible,params=keywords)

     if not parent_obj.objnames.count(name):
       parent_obj.objnames.append(name)
       parent_obj.objinsts.append(self)

     #print 'Loaded picture definition: Contacts',name
     
#--------------------------------------------------------------------     
class AnisoU(dataobj.DispObjShadow):
#--------------------------------------------------------------------  
   def __init__(self,name='',parent='',object_type='AnisoU',selection_parameters={},colour_parameters={},style_parameters={},visible=1,**keywords):

     parent_obj= DispObj_parent(parent=parent,name=name,object_type='MolData')
     if not parent_obj:
       global ERROR_MESSAGE
       ERROR_MESSAGE.append('Can not find parent DataObj for '+object_type + ' ' + name)
       return
     name = DispObj_name(parent_obj=parent_obj,name=name,object_type='AnisoU')

     dataobj.DispObjShadow.__init__(self,name=name,object_type=object_type,selparams=selection_parameters,colparams=colour_parameters,styleparams=style_parameters,visible=visible,params=keywords)
     
     if not parent_obj.objnames.count(name):
       parent_obj.objnames.append(name)
       parent_obj.objinsts.append(self)

     #print 'Loaded picture definition: AnisoU',name

#--------------------------------------------------------------------     
class Annotation(dataobj.DispObjShadow):
#--------------------------------------------------------------------  
   def __init__(self,name='',parent='',object_type='Annotation',selection_parameters={},colour_parameters={},style_parameters={},visible=1,**keywords):
     
     parent_obj= DispObj_parent(parent=parent,name=name,object_type='MolData')
     if not parent_obj:
       global ERROR_MESSAGE
       ERROR_MESSAGE.append('Can not find parent DataObj for '+object_type + ' ' + name)
       return
     name = DispObj_name(parent_obj=parent_obj,name=name,object_type='Annotation')
     
     dataobj.DispObjShadow.__init__(self,name=name,object_type=object_type,selparams=selection_parameters,colparams=colour_parameters,styleparams=style_parameters,visible=visible,params=keywords)

     if not parent_obj.objnames.count(name):
       parent_obj.objnames.append(name)
       parent_obj.objinsts.append(self)

     #print 'Loaded picture definition: Annotation',name

#--------------------------------------------------------------------     
class SurfaceDispobj(dataobj.DispObjShadow):
#--------------------------------------------------------------------  
  def __init__(self,name='',parent='',object_type='SurfaceDispobj',selection_parameters={},colour_parameters={},style_parameters={},visible=1,**keywords):

     parent_obj= DispObj_parent(parent=parent,name=name,object_type='MolData')
     if not parent_obj:
       global ERROR_MESSAGE
       ERROR_MESSAGE.append('Can not find parent DataObj for '+object_type + ' ' + name)
       return
     name = DispObj_name(parent_obj=parent_obj,name=name,object_type='SurfaceDispobj')

     dataobj.DispObjShadow.__init__(self,name=name,object_type=object_type,visible=visible,selparams=selection_parameters,colparams=colour_parameters,styleparams=style_parameters,params=keywords)

     if not parent_obj.objnames.count(name):
       parent_obj.objnames.append(name)
       parent_obj.objinsts.append(self)

     #print 'Loaded picture definition: SurfaceDispobj',name

#--------------------------------------------------------------------
class CrystalData(dataobj.DataObjShadow):
#--------------------------------------------------------------------  
  def __init__(self,name='CrystalData',display_objects=[],**dataparams):
    pass
    #dataobj.DataObjShadow.__init__(self,name=name,object_type='CrystalData',objnames=objnames,dataparams=dataparams)
    #DataList.append(self)   
    #print 'Loaded picture definition: CrystalData',name

#--------------------------------------------------------------------    
class Crystal(dataobj.DispObjShadow):
#--------------------------------------------------------------------  
  def __init__(self,name='',object_type='Crystal',visible=1,**keywords):
    if not name: name = 'Crystal'+str(len(CrystalList)+1)
    dataobj.DispObjShadow.__init__(self,name=name,object_type=object_type,visible=visible,params=keywords)
    if name: CrystalList.append(self)
    #print 'Loaded picture definition: Crystal',name

#----------------------------------------------------------------------------
class MapData(dataobj.DataObjShadow):
#----------------------------------------------------------------------------

  def __init__(self,name='MapData',display_objects=[],visible=1,**dataparams):
    dataparams['visible']=visible
    name = DataObj_name(name=name,dataparams=dataparams,object_type='MapData')

    objnames = []
    for item in display_objects: objnames.append(item)
    objinsts = []

    dataobj.DataObjShadow.__init__(self,name=name,object_type='MapData',objnames=display_objects,objinsts=objinsts,dataparams=dataparams)
    DataList.append(self)
    DataLookup[name]=self

    #print 'Loaded picture definition: MapData',name

      
#----------------------------------------------------------------------------
class MapDisp(dataobj.DispObjShadow):
#----------------------------------------------------------------------------

  def __init__(self,name='',parent='',object_type='MapDisp',visible=1,**keywords):

     parent_obj= DispObj_parent(parent=parent,name=name,object_type='MapData')
     if not parent_obj: return
     name = DispObj_name(parent_obj=parent_obj,name=name,object_type='MapDisp')

     dataobj.DispObjShadow.__init__(self,name=name,object_type=object_type,visible=visible,params=keywords)
     if not parent_obj.objnames.count(name):
       parent_obj.objnames.append(name)
       parent_obj.objinsts.append(self)
       #print "parent_obj.objnames",parent_obj.name,parent_obj.objnames,parent_obj.objinsts

     #print 'Loaded picture definition: MapDisp',name,'in DataObj',parent_obj.name

#--------------------------------------------------------------------     
class VectorsData(dataobj.DataObjShadow):
#--------------------------------------------------------------------  
  def __init__(self,name='VectorsData',display_objects=[],visible=1,**dataparams):
    dataparams['visible']=visible
    name = DataObj_name(name=name,dataparams=dataparams,object_type='VectorsData')
    # Beware the following lines are VERY necessary to prevent all dataobjects
    # containing all display objects
    objnames = []
    for item in display_objects: objnames.append(item)
    objinsts = []

    dataobj.DataObjShadow.__init__(self,name=name,object_type='VectorsData',objnames=display_objects,objinsts=objinsts,dataparams=dataparams)
    DataList.append(self)
    DataLookup[name]=self

    #print 'Loaded picture definition: VectorsData',name

#--------------------------------------------------------------------    
class VectorsDispobj(dataobj.DispObjShadow):
#--------------------------------------------------------------------  
  def __init__(self,name='',parent='',object_type='VectorsDispobj',visible=1,**keywords):

     parent_obj= DispObj_parent(parent=parent,name=name,object_type='VectorsData')
     if not parent_obj:
       global ERROR_MESSAGE
       ERROR_MESSAGE.append('Can not find parent DataObj for '+object_type + ' ' + name)
       return
     name = DispObj_name(parent_obj=parent_obj,name=name,object_type='VectorsDispobj')

     dataobj.DispObjShadow.__init__(self,name=name,object_type=object_type,visible=visible,params=keywords)

     if not parent_obj.objnames.count(name):
       parent_obj.objnames.append(name)
       parent_obj.objinsts.append(self)

     #print 'Loaded picture definition: VectorsDispobj',name

#--------------------------------------------------------------------
class Legend(dataobj.DispObjShadow):
#--------------------------------------------------------------------  
  def __init__(self,name='',object_type='Legend',visible=1,**keywords):

     dataobj.DispObjShadow.__init__(self,name=name,object_type=object_type,visible=visible,params=keywords)
     twoDList.append(self)
     #print 'Loaded picture definition: Legend',name

#--------------------------------------------------------------------     
class Image(dataobj.DispObjShadow):
#--------------------------------------------------------------------  
  def __init__(self,name='',object_type='Image',visible=1,**keywords):
    
     dataobj.DispObjShadow.__init__(self,name=name,object_type=object_type,visible=visible,params=keywords)
     twoDList.append(self)
     #print 'Loaded picture definition: Image',name
     
#--------------------------------------------------------------------
class FieldData(dataobj.DataObjShadow):
#--------------------------------------------------------------------  
  def __init__(self,name='FieldData',display_objects=[],visible=1,**dataparams):
    dataparams['visible']=visible
    name = DataObj_name(name=name,dataparams=dataparams,object_type='FieldData')
    # Beware the following lines are VERY necessary to prevent all dataobjects
    # containing all display objects
    objnames = []
    for item in display_objects: objnames.append(item)
    objinsts = []

    dataobj.DataObjShadow.__init__(self,name=name,object_type='FieldData',objnames=display_objects,objinsts=objinsts,dataparams=dataparams)
    DataLookup[name] = self
    DataList.append(self)

    #print 'Loaded picture definition: FieldData',name

#--------------------------------------------------------------------    
class FieldDisp(dataobj.DispObjShadow):
#--------------------------------------------------------------------  
  def __init__(self,name='',parent='',object_type='FieldDisp',visible=1,**keywords):

     parent_obj= DispObj_parent(parent=parent,name=name,object_type='FieldData')
     if not parent_obj:
       global ERROR_MESSAGE
       ERROR_MESSAGE.append('Can not find parent DataObj for '+object_type + ' ' + name)
       return
     name = DispObj_name(parent_obj=parent_obj,name=name,object_type='FieldDisp')

     if not name: name = parent_obj.name+'MolDisp'+str(len(parent_obj.objnames)+1)

     dataobj.DispObjShadow.__init__(self,name=name,object_type=object_type,visible=visible,params=keywords)

     if not parent_obj.objnames.count(name):
       parent_obj.objnames.append(name)
       parent_obj.objinsts.append(self)

     #print 'Loaded picture definition: FieldDisp',name

 
#============================================================================

class ParamsManager:
  insts = []
  def __init__(self,name = '', **keywords):
    self.name = name
    self.params = {}
    for key,value in keywords.items():
      self.params[key] = value
    ParamsManager.insts.append(self)
    #print 'Loaded picture definition: ParamsManager',name
    #print "ParamsManager.insts",ParamsManager.insts
  
class ColourSchemeManager:
  insts = []
  def __init__(self,name = '', **keywords):
    self.name = name
    self.params = {}
    for key,value in keywords.items():
      self.params[key] = value
    ColourSchemeManager.insts.append(self)
    #print 'Loaded picture definition: ColourSchemeManager',name
    #print "ColourSchemeManager.insts",ColourSchemeManager.insts

class View:
  insts = []
  def __init__(self,name='',**keywords):
    self.name = name
    self.params = {}
    for key,value in keywords.items():
      self.params[key] = value
    View.insts.append(self)

      
class Colours:
  insts = []
  def __init__(self,colour_definitions={},**keywords):
    self.params = []
    if colour_definitions:
      for key,value in colour_definitions.items():
        self.params.append([key,value])
    elif keywords:
      for key,value in keywords.items():
        self.params.append ([key,value])
    Colours.insts.append(self)

class Wizard:
  def __init__(self,MolData1='',drawing_style='',**keywords):
    global ERROR_MESSAGE
    parent_obj = DispObj_parent(parent=MolData1,object_type='MolData')
    if not parent_obj: return
    if parent_obj.get_filename()[0] != "INLINE":
      parent_obj.restore()
    import string,global_definitions
    wizard = global_definitions.PICTUREWIZARD()
    folder,index = string.split(drawing_style,':',1)
    if index and folder:
      if os.path.exists(os.path.join(wizard.master_dir,folder)):
        theDir = os.path.join(wizard.master_dir,folder)
      else:
        theDir = os.path.join(utils.get_CCP4MG(),'data','picture_wizard_files',folder)          
      mgpic_file = wizard.snapshot_file(index=index,mode='mgpic',dir=theDir)
    #print "mgpic_file",mgpic_file

    # Initialise the choices
    rv,choices = wizard.read_mgpic_file_choices(filename=mgpic_file)
    #print " rv,choices", rv,choices
    if rv<=0:
      for param in choices:
        if param.has_key('name'):
          if param.has_key('initial'):
            globals()[param['name']] = param['initial']
          else:
            globals()[param['name']] = ''

    import global_definitions
    if len(global_definitions.get_dataobj(name=parent_obj.name))>0:
      globals()["MolData1"] = global_definitions.get_dataobj(name=parent_obj.name)[0]
    else:
      globals()["MolData1"] =parent_obj.name
    # Run the wizard script
    rv,script_text = wizard.read_mgpic_file_section(filename=mgpic_file,section='SCRIPT')
    #print "script_text",script_text
    if not rv:
      for key,value in keywords.items():
        globals()[key] = value
      try:
        locs = {}
        exec(script_text,globals(),locs)
      except StandardError, e:
        #print "ERROR in Wizard",e
        ERROR_MESSAGE.append( 'ERROR handing Wizard '+e)
    else:     
      #print "ERROR in Wizard reading script for "+drawing_style
      ERROR_MESSAGE.append("ERROR in Wizard reading script for "+drawing_style)

class Inline:
  def __init__(self,name = '',  data = ''):
    self.name = name
    self.data = data
    InlineList.append(self)
    #print "data",data
    
  def unpack (self,target=''):
    import utils
    if not target: target = utils.get_filename('INLINE',self.name)

    #print "unpack target",target
    rv = utils.saveFile(target,text=self.data)
    if rv:
      return [1,'Error saving inline data to file '+target]

    if os.path.splitext(self.name)[-1] == '.gz':
      import gzip
      try:
        i = gzip.open(target)
        o = open(target[0:-3],'wb')
        o.write(i.read())
      except:
        return [1,'Error uncompressing '+target]

    return [0]

class SelectionScheme:
  def __init__(self,name='',context='',selection='',selparams={},**keywords):
    self.name = name
    if context == 'generic':
      self.parent_obj='generic'
    else:
      self.parent_obj= DispObj_parent(parent=context,object_type='MolData')
      if not self.parent_obj: self.parent_obj = 'generic'
    self.selection = selection
    SelectionSchemeList.append(self)
    #print "SelectionScheme parent_obj",self.parent_obj
    
class ColourScheme:
  def __init__(self,name='',context='',colours='',**keywords):
    self.name = name
    if context == 'generic':
      self.parent_obj='generic'
    else:
      self.parent_obj= DispObj_parent(parent=context,object_type='MolData')
      if not  self.parent_obj:  self.parent_obj = 'generic'
    self.colours = colours
    ColourSchemeList.append(self)
    #print "ColourScheme parent_obj",self.parent_obj
