"""
     python/ui/presentation.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 os, sys, utils
from PyQt4 import QtCore
from global_definitions import *
directory_ext = 'ccp4mg_presentation'
SNAPSHOT_SIZE = 200

#----------------------------------------------------------------------
def open_presentation( presentation_dir='', DIR_presentation_dir='',
                       mode='',**keywords):
#----------------------------------------------------------------------

    #print 'open_presentation',presentation_dir
    
    if os.path.splitext(presentation_dir)[1] == '.zip':
        presentation_dir = os.path.abspath(utils.get_filename(DIR_presentation_dir,presentation_dir))
        rv = utils.unzip(presentation_dir)
        if rv[0]:
          MGGUI().WarningMessage('Error unpacking presentation '+presentation_dir)
          return None
        else:
          presentation_dir = rv[1]

    if presentation_dir:
      dir = os.path.abspath(utils.get_filename(DIR_presentation_dir,presentation_dir))
      pref_file = os.path.join(dir,'preferences.pkl')
      if os.path.exists(dir) and os.path.exists(pref_file):
        action = 'open'
      else:
        # Beware in 'open' mode file browser does not add extension
        if os.path.splitext(dir)[1]!= '.'+directory_ext:
            dir = dir + '.' + directory_ext
        action = 'create'

      #print "presentation.insts",presentation.insts,exit
      #if sys.platform == 'win32': pref_file = utils.msvcescape(pref_file)
      #print "pref_file",pref_file
      if presentation.insts:
        for obj in presentation.insts:
          if obj.master_dir == dir:
            return obj
      #print 'presentation.open_presentation',action
      if action == 'open':
        new_presentation = presentation(master_dir= dir)
        status = new_presentation.unpickle_movie(file=pref_file)
        #print "unpickled movie project_name",new_presentation.project_name
        if status:
          MGGUI().WarningMessage('Error attempting to open movie '+dir)
          new_presentation.delete()
          return None
        else:
          new_presentation.open(mode=mode)
          return new_presentation
      elif action == 'create':
        dir = create_presentation_dir(dir)
        if dir:
          new_presentation=presentation(master_dir= dir)
          new_presentation.pickle_movie(new_presentation.movie_file)
          return new_presentation
        else:
          MGGUI().WarningMessage('Error attempting to create movie directory '+dir)
          return None
      else:
        if sys.platform == 'win32': 
          import re
          pref_file = re.sub(r'/','\\',pref_file)
        MGGUI().WarningMessage('Error attempting to open presentation preferences file '+pref_file)
        del new_presentation
        return None
   
#----------------------------------------------------------------------
def create_presentation_dir(presentation_dir,mode='movie'):
#----------------------------------------------------------------------
    
    # Create new directory
    parent,tail=os.path.split(presentation_dir)
    name,ext = os.path.splitext(tail)
    if not ext: presentation_dir =presentation_dir  + directory_ext
    if os.path.exists(presentation_dir):
      MGGUI().WarningMessage('Attempting to create a '+mode+' file.\nA directory '+presentation_dir+' already exists.\n Please give an alternative NEW name for a new '+mode)
      return ''
    if not os.path.exists(parent) or not os.path.isdir(parent):
      MGGUI().WarningMessage('Can not create directory '+presentation_dir+
          '\nParent directory does not exist')
      return ''
    try:
      os.mkdir(presentation_dir)
      
    except:
      MGGUI().WarningMessage('Error attempting to create directory\n'+presentation_dir)
      return ''
    return presentation_dir

    
#---------------------------------------------------------------------
#---------------------------------------------------------------------
#---------------------------------------------------------------------
class presentation():
#---------------------------------------------------------------------
#---------------------------------------------------------------------
#---------------------------------------------------------------------

  insts = []

  saved_program_status = None
  
  default_details = {
   'transform' : [ 0.0,0.0,0.0,  0.0,0.0,0.0, 0.0],
   'rock_angle': 20,
   'rock_axis' : 'y',
   'rock_period' : 2.0,
   'interpolate_time' : 1,
   'interpolate_rock':0,
   'interpolate_repeats':1,
   'ramp_start':0,
   'ramp_end':0,
   'time' : 2,
   'view' : 'fixed'
   }

   
   #'raytrace'  : 0,
   #'render_quality' : 0}

  render_quality_menu = ['0','1']
  render_quality_alias = ['fast','good']

  directory_ext = 'ccp4mg_presentation'

  movie_encoder_menu = ['ffmpeg','ImageMagick convert']
  movie_encoder_alias = ['ffmpeg','convert']
  movie_ext_menu = ['.gif','.mpg','.mp4','.avi']
  movie_encoder_size_multiple = {'ffmpeg':8,'mencoder':8,'convert':1}
  movie_encoder_fps = {'ffmpeg':[25,30],'mencoder':[25,30],'convert':[]}
  movie_encoder_formats = {'ffmpeg':('.mpg','.mp4','.avi'),'mencoder':('.mpg','.mp4','.avi'),'convert':('.gif','.mpg','.mp4','.avi')}

  initialisation = {
    'title' : '',
    'identifier' : '',
    'frame_rate' : 25, 
    'encoder_quality' : 100, 
    'frame_size' : [640,480],
    'antialias' : 0,
    'movie_encoder' : 'ffmpeg',
    'movie_ext' : '.mpg',
    'save_file_format' : 'status',
    'html_template' : ['','',''],
    'render_quality' : 0,
    'last_scene' : 0,
    'last_movie_snapshot_id' : 0,
    'snapshot_list' : [],
    'snapshot_details' : {},
    'recorded_details' : {},
    'notes' : {},
    'gui_mode' : 'presentation',
    'true_transparency' : 0,
    'do_render' : 0,
    'scale_fonts_and_images' : 0
     }
  
    #self.mencoder_command = "-ovc xvid -xvidencopts fixed_quant=1"

  
#----------------------------------------------------------------------
  def __init__(self,master_dir='',params={},**keywords):
#----------------------------------------------------------------------
    #print 'presentation.init master_dir',master_dir,params
    self.last_frame = 0
    self.current_scene = -1
    self.make_frame_mode = 'status'
    self.animation_on = 0
    self.animation_time_delay = 0.5
    self.animation_rock = 0

    self.master_dir = unicode(master_dir,'utf-8')
    self.movie_file = os.path.join(self.master_dir,'preferences.pkl')
    self.movie_file_root = utils.fileRoot(self.master_dir)

    self.pending_jobs = {}

    for key,value in presentation.initialisation.items():
        setattr(self,key,value)
    if params:
      for key,value in params.items(): setattr(self,key,value)

    if self.master_dir and not self.identifier:
      import string
      self.identifier = string.split(os.path.split(master_dir)[1],'.')[0]
    if not self.title: self.title = self.identifier
      
    presentation.insts.append(self)
    self.last_restored = 0
    self.snapshot_changes = {}

    self.interruptable = 0

    # From v1.1 want ot use png files for snapshots (supported
    # by browsers and noe supported by Tk with Img extension
    # But stick with ppm for 'old' presentation directory
    self.snapshot_ext = '.ppm'
    #import glob
    #if len(glob.glob(os.path.join(self.master_dir,'snapshot_*.ppm')))>0:
    #  self.snapshot_ext = '.ppm'
    #print "self.snapshot_ext",self.snapshot_ext
    
  def open(self,mode=''):
    # The open mode (which depends on how it was opened
    # on the GUI) takes precedence over the stored mode which was
    # how it was opened last time
    if mode: self.gui_mode = mode
    


#-------------------------------------------------------------------
  def apply(self, action='',notes='',
                 load_file='',select='',gui_mode='',
                 index='',show_notes='',show_details='',
                 **keywords):
#-------------------------------------------------------------------

    #print 'presentation.apply',action
    if gui_mode:
      self.gui_mode = gui_mode
      
    if action == 'current_status':
      indx,backup = self.add_movie_snapshot()
      #print "current_status indx",indx
      self.pickle_movie(file = self.movie_file)
      return indx

    elif action == 'write_html':
      if self.html_template[1]:
        template_file=utils.get_filename(self.html_template[0],self.html_template[1])
      else:
        template_file = ''
      rv = self.write_html(template_file=template_file)
      if rv[0]:
        MGGUI().WarningMessage(rv[1])
      else:
        WEB().launch_browser(rv[1],internal=1)
      
    elif action == 'backup':
        if keywords.has_key('identifier'):
            self.identifier = keywords['identifier']
        compress = int(keywords.get('compress',0))
        self.do_backup_data_files(project=self.identifier,compress=compress)

      
    elif action == 'cleanup':
      
        import glob,re
        # Remove all files not currently in the snapshot list
        filn_list = glob.glob(os.path.join(self.master_dir,'snapshot_*'+self.snapshot_ext))
        for filn in filn_list:
          indx = filn[-9:-4]
          if not self.snapshot_list.count(indx):
            utils.remove_file(filn)
            filn0 = re.sub('snapshot','status',filn)
            if os.path.exists(filn0): utils.remove_file(filn0)
        # Remove all the backup status files
        for mode in ['status','snapshot']:
          filn_list = glob.glob(os.path.join(self.master_dir,mode+'_*.*.pkl'))
          for filn in filn_list: utils.remove_file(filn)
        
        
    elif action == 'delete_movie' or action == 'delete_frame':
        import glob,re
        for scene_list in self.tmp_delete_range:
          for scene in scene_list:
            # Remove all files not currently in the snapshot list
            filn_list = glob.glob(os.path.join(self.master_dir,'scene_'+scene,action[7:]+'*'))
            for filn in filn_list: utils.remove_file(filn)
        del self.tmp_delete_range     

        self.get_movie_files(update_gui=1)
      
    elif action == 'delete_all':
       # zap everything - probably only wise to enable for animation
       import glob
       filn_list = glob.glob(os.path.join(self.master_dir,'scene_*'))
       #print "presenrtation.apply clear",filn_list
       for filn in filn_list: utils.remove_directory(filn)
       self.snapshot_list = []
       
    elif load_file:
      if self.snapshot_list.count(load_file):
        # This status is already in the movie so copy
        indx,backup=self.add_movie_snapshot(index='',create=0)
        import shutil
        try:
          shutil.copy( self.snapshot_file(load_file),
                     self.snapshot_file(indx)  )
          shutil.copy( self.snapshot_file(load_file,mode='status'),
                     self.snapshot_file(indx,mode='status')  )
          #GUI.GUI.insts.WarningMessage('Snapshot '+load_file+' already in '+ \
          #       self.movie_file_root+' so copied to '+indx)
        except:
          MGGUI().WarningMessage('Snapshot '+load_file+' already in '+ \
              self.movie_file_root+' so attempting to make copy\n'+ \
                                      'Error attempting to make copies')
      else:
        indx = load_file
        self.add_movie_snapshot(index=indx,create=0)
        self.pickle_movie(file = self.movie_file)

      self.update_gui_details(indx)


    elif action == 'undo_selection':
        self.snapshot_select = []
    elif select:
        self.snapshot_select = select


    elif ['restore','restore_view','restore_display'].count(action):
       return self.restore_status(action=action,index=index)
       
    elif ['replace'].count(action):
      indx,backup = self.add_movie_snapshot(index=index,save_changes='replaced')
      #print "replace",indx,backup
      if indx>0: self.update_gui_details(indx)

    elif ['replace_propagate'].count(action):
      targets = self.get_play_list(default_all=0,group_interp_ranges=0)      
      self.handle_copy_changes(index=index)

    elif ['next','previous'].count(action):
      if len(self.snapshot_list)>0 and \
             hasattr(self,'last_restored') and \
             self.snapshot_list.count(self.last_restored):
        if action == 'next':
          next = self.snapshot_list.index(self.last_restored)+1
          if next>=len(self.snapshot_list): next = 0
        else:
          next = self.snapshot_list.index(self.last_restored)-1
          if next<0: next = len(self.snapshot_list)-1
      else:
        if action == 'next':
          next = 0
        else:
          next = len(self.snapshot_list)-1
      #print "next",next,self.snapshot_list
      self.last_restored = self.snapshot_list[next]
      self.restore_status(action='restore',index=self.snapshot_list[next])

    #elif action == 'copy_changes':
    #  self.handle_copy_changes(copy_changes=1)
       
    elif show_details:
        self.handle_movie_details(index=show_details)
    elif show_notes:
      #self.handle_movie_details(index=show_details)
      index=show_notes
      if not self.notes.has_key(index):
        self.notes[index] = {}
      if not self.notes[index].has_key('notes'):
        self.notes[index]['notes'] = ' '
      notes_text =  self.notes[index]['notes']

    elif notes:
      self.notes[index]['notes']= notes
      
    elif action == 'quit':
      self.delete()
    
    elif action == 'preferences':
      if self.gui_mode == 'movie':
        self.define_movie_params()
      else:
        self.define_presentation_params()
    

    elif ['preview','run_auto','record'].count(action):
      if action == 'run_auto': action = 'preview'
      self.make_movie_frames(action)
        
    elif action == 'compile':
      self.run_compile()
      
    elif action == 'merge':
      self.run_compile(merge=1,compile=0)
          
    elif action == 'make':
      rv = self.make_movie_frames('record',compile=1)

          
    elif action == 'run_animation':
      if  self.snapshot_details[index].has_key('animation'):
        ret=self.restore_status(action='restore',index=index)
        if ret: return 
        molobj_list = get_dataobj(name= self.snapshot_details[index]['animation'][0])
        if molobj_list and  hasattr(molobj_list[0],'animation'):
          molobj_list[0].animation.run_animation()

    

    return 0

#----------------------------------------------------------------------
  def makeCopy(self,copy_from):
#----------------------------------------------------------------------
    if self.snapshot_list.count(copy_from):
      # This status is already in the movie so create new snapshot_details
      # and copy the status/snapshot file
      indx,backup=self.add_movie_snapshot(index='',create=0)
      import shutil
      try:
        shutil.copy( self.snapshot_file(copy_from),
                   self.snapshot_file(indx)  )
        shutil.copy( self.snapshot_file(copy_from,mode='status'),
                   self.snapshot_file(indx,mode='status')  )
        #GUI.GUI.insts.WarningMessage('Snapshot '+copy_from+' already in '+ \
        #       self.movie_file_root+' so copied to '+indx)
      except:
        MGGUI().WarningMessage('Snapshot '+copy_from+' already in '+ \
            self.movie_file_root+' so attempting to make copy\n'+ \
                                    'Error attempting to make copies')
        return [1,'Error attempting to make copy of '+copy_from]
    else:
      # Just recreate the snapshot_details for this indx
      indx = copy_from
      self.add_movie_snapshot(index=indx,create=0)

    return [0,indx]

#----------------------------------------------------------------------
  def check_status_files(self,snapshot_list=[]):
#----------------------------------------------------------------------
    if not snapshot_list: snapshot_list = self.snapshot_list

    objList=[]
    fileDef= {}
    for snapshot in self.snapshot_list:
      filn = self.snapshot_file(snapshot,mode='status')
      if filn:
        rv = HISTORY().get_status_data_files(filn)
        if rv[0]<1: return [1,snapshot]
        if rv[0]>0:
          for item in rv[1]:
            if not objList.count(item):
              objList.append(item)
              fileDef[item] = rv[2][item]
              
    if not objList:
      return [0]
    else:
      return [2,objList,fileDef]

#----------------------------------------------------------------------
  def edit_status_data_files(self,objList,fileDefn):
#----------------------------------------------------------------------
    failed = []
    for snapshot in self.snapshot_list:
      filn = self.snapshot_file(snapshot,mode='status')
      if filn:
        status = HISTORY().edit_status_data_files(filn,1,objList,fileDefn)
        rv = HISTORY().write_pickle_file(filn,status)
        if rv: failed.append(snapshot)

    return failed
          

#----------------------------------------------------------------------
  def restore_status(self,action='restore',id=''):
#----------------------------------------------------------------------
    #print "presentation.restore_status id",id,action
    if utils.safeInt(id,-1)<0: return [1,'Unrecognised snapshot id'+id]
    self.last_restored = id
    filn = self.snapshot_file(id,mode=self.save_file_format)
    if os.path.exists(filn):
      format = self.save_file_format
    else:
      # try the alternative format
      format = ['status','mgpic'][1-['status','mgpic'].index(self.save_file_format)]
      filn = self.snapshot_file(index,mode=format)
      if not os.path.exists(filn):
        return [1,'Snapshot '+filn+' not found ']

    if format == 'status':
      rv = 0
      if  ['restore','restore_view'].count(action):
          rv = HISTORY().restore_view(filename=filn)
      if  ['restore','restore_display'].count(action):

          rv = HISTORY().get_status_data_files(filename=filn)
          if rv[0]<0:
            return [1,'Unable to restore status from snapshot '+filn]
            return
          elif rv[0]:
              hints = []
              if file:
                hints.append(os.path.split(filn)[0])
              nLost,objList,fileDef,nFound = HISTORY().get_status_data_files(filn,hints)
              if nLost == nFound:
                status_new =  HISTORY().edit_status_data_files(filn,1,objList,fileDef)
                rv = HISTORY().update_data_status(status=status_new,
                      override_visible=0,exclude_list=['screenshot_preferences'],
                      delay_delete=1)

          else:
            rv = HISTORY().update_data_status(filename=filn,
                override_visible=0,exclude_list=['screenshot_preferences'],
                delay_delete=1)
      if rv:
        return [1,'Unable to restore status from snapshot '+filn]

    else:
        restore_list = []
        keep_current = 0
        if ['restore','restore_display'].count(action):
          restore_list.extend(['colours','display','params'])
        if  ['restore','restore_view'].count(action):
          restore_list.append('view')
        if ['restore_view'].count(action):keep_current=1
        
        PD().restore_picture_definition(filename=filn,trap_errors=1,test=0,
             restore_list=restore_list,keep_current=keep_current,
             delay_delete=1)


        
    return [0,'']

#-------------------------------------------------------------------------
  def Exit(self):
#-------------------------------------------------------------------------
    self.pickle_movie(self.movie_file)
    return

#------------------------------------------------------------------------
  def animate(self,mode=-1):
#------------------------------------------------------------------------
    if mode<0:
      mode = 1 - self.animation_on
    if not mode:
      MAINWINDOW().removeAnimationHandler('Animation')
      self.animation_on = 0
    else:
      play_list = self.get_play_list()
      #print "presentation.animate play_list",play_list
      self.animate_scene_list = []
      for item in play_list:
        for scene in item:
          status = HISTORY().load_pickle_file(filename=self.snapshot_file(scene,mode='status'))
          self.animate_scene_list.append(status)
      if len(self.animate_scene_list)<2:
        MGGUI().WarningMessage("Need at least two scenes selected for animation")
        del self.animate_scene_list
        return


      # Set the initial status
      self.animate_scene_position = -1
      self.animate_scene_incr = 1
      self.animation_count = 10
 
      self.handle_animate()
      MAINWINDOW().addAnimationHandler('Animation',self.handle_animate)
      self.animation_on = 1
   
#------------------------------------------------------------------------
  def handle_animate(self):
#------------------------------------------------------------------------

      self.animation_count = self.animation_count + 1
      # This assumes the animation timer is firing every 0.1s
      if self.animation_count < (self.animation_time_delay * 10):
          return

      self.animation_count = 0

      self.animate_scene_position = self.animate_scene_position + self.animate_scene_incr
      # Rotate or rock?
      if self.animation_rock:
        if self.animate_scene_position<0:
          self.animate_scene_position=1
          self.animate_scene_incr = 1
        elif self.animate_scene_position>=len(self.animate_scene_list):
          self.animate_scene_incr = -1
          self.animate_scene_position = len(self.animate_scene_list)-2
      else:
        if self.animate_scene_position>=len(self.animate_scene_list):
          self.animate_scene_position = 0

      #print "presentation.handle_animate animate_scene_position",self.animate_scene_position
      status = self.animate_scene_list[self.animate_scene_position]

      for data_name in status['Data_list']:
        if status.has_key(data_name):
          d_obj = get_dataobj(name=data_name)
          if d_obj:
            rv = d_obj[0].animate(status[data_name])
            #print "presentation.handle_animate",d_obj[0].name,d_obj[0].visible
        
      import rebuild
      rebuild.UpdateDisplay()
    

#------------------------------------------------------------------------
  def make_movie_frames(self,action='',compile=0):
#------------------------------------------------------------------------
    # Sort out a play_list listing the snapshots to be
    # processed with those that are part of a glide or interpolate
    # grouped into a sublist
    play_list = self.get_play_list()
    if not play_list: return 1

    self.make_frame_mode = action
    
    if self.make_frame_mode == 'record' and not self.do_render:
      #print "presentation.make_movie_frames self.frame_size",self.frame_size
      MAINWINDOW().setGLSize(width=self.frame_size[0],height=self.frame_size[1],save=1)
      MAINWINDOW().hideWindows()
      sleep_period = 0
      
    elif self.make_frame_mode == 'internal':
      import ffmpeg_wrapper
      ffmpeg_wrapper.OpenMovie(self.frame_size[0],self.frame_size[1],'test.mov')
      sleep_period = 0
    else:
      sleep_period = 1.0/self.frame_rate


    for snap_list in play_list:   
      scene = snap_list[0]
      # Check for status files
      for snap in snap_list:
        if not os.path.exists( self.snapshot_file(snap,mode='status')):
          MGGUI().WarningMessage('Status file for snapshot '+snap+' not found')
          return 0  
        #cleanup all movie snapshots
      if self.make_frame_mode=='record':
        import glob
        scene_dir = os.path.join(self.master_dir,'scene_'+scene)
        if os.path.exists(scene_dir):
          for ext in ['png','gif','mpg','mp4','avi']:
            for file in glob.glob(os.path.join(scene_dir,'*.'+ext)) :
              utils.remove_file(file)
        else:
          os.mkdir(scene_dir)



    interrupt = self.transform(
                          play_list = play_list,
                          interrupt_label = 'Movie:'+self.identifier,
                          update_method=self.make_frame,
                          finish_method = [self.end_transform,{'compile':compile,'play_list':play_list}],
                          label=0)

    return 0

#--------------------------------------------------------------------
  def restore_status_0(self,status):
#--------------------------------------------------------------------
      import rebuild
      HISTORY().update_data_status(status=initial_status,
               exclude_list=['screenshot_preferences'],restore_all_visible=1)

      rebuild.UpdateDisplay()
      if initial_status.has_key('view'):
        initial_status['view'].restore()
      elif initial_status.has_key('view2'):
        MAINWINDOW().setViewParams(initial_status['view2'])


#--------------------------------------------------------------------
  def run_compile(self,scene_list=[],merge=0,compile=1,**keywords):
#--------------------------------------------------------------------
    # Need to test if this exists - beware executable may just
    # be on the PATH
       
    if not scene_list:
      import glob
      play_list = self.get_play_list()
      scene_list=[]
      for snap_list in play_list:
        snap = snap_list[0]
        scene_dir = os.path.join(self.master_dir,'scene_'+snap)
        if os.path.exists(scene_dir) and \
               glob.glob(os.path.join(scene_dir,'frame*')):
          scene_list.append(snap)


    # Run a test compile which will return error code if there
    # are obvious problems
    if compile:
      rv = self.compile(compile=0,scene_list=scene_list)
      #print "presentation.run_compile rv",rv
      if rv[0]==-3:
          import string
          utils.remove_file(string.split(rv[1])[-1])
          return
    
      elif rv[0]<0:
         MGGUI().WarningMessage('Aborting compiling movie..\n'+rv[1])
         return

    try:
      if not self.movie_ext in self.movie_encoder_formats[self.movie_encoder]:
        print "RESETTING SUFFIX to", self.movie_encoder_formats[self.movie_encoder][0]
        self.movie_ext = self.movie_encoder_formats[self.movie_encoder][0]
      if len(self.movie_encoder_fps[self.movie_encoder])>0 and not self.frame_rate in self.movie_encoder_fps[self.movie_encoder]:
        print "RESETTING FRAME RATE to", self.movie_encoder_fps[self.movie_encoder][0]
        self.frame_rate = self.movie_encoder_fps[self.movie_encoder][0]
    except:
        print "problem setting suffix"

    if merge and not compile:
      # test if there are some movies to merge
      rv = self.merge_movies(scene_list=scene_list,overwrite=1,ext=self.movie_ext,encoder=self.movie_encoder,test=1)
      if rv[0]:
        MGGUI().WarningMessage('Aborting merging movie..\n'+rv[1])

        
    # Ensure current status is saved
    self.pickle_movie(file = self.movie_file)


    args = ['-dir',self.master_dir.encode('utf-8'),'-master',self.movie_file.encode('utf-8'),'-scene']
    for scene in scene_list: args.append(scene)
    args.extend(['-encoder',self.movie_encoder,'-ext',self.movie_ext])
    pm = PM('movie_preferences')

    
    for item in [self.movie_encoder+'_exe']:
      args.extend(['-'+item,pm.get(item)])
    for item in [self.movie_encoder+'_command']:
      cmd_args = pm.get(item)
      if self.movie_encoder == "ffmpeg":
	 cmd_args += ' -r '+str(self.frame_rate)
	 cmd_args += ' -s '+str(self.frame_size[0])+"x"+str(self.frame_size[1])
      args.extend(['-'+item,cmd_args])
    for item in [self.movie_encoder+'_merge_command']:
      args.extend(['-'+item,pm.get(item)])
      
    #print args
    #print self.movie_encoder
    #print self.frame_size
    
    if merge : args.append('-merge')
    if not compile: args.append('-no_compile')
    #print 'run_compile pm args',pm,args
    
    label = 'For movie '+self.identifier[0:25]+'\n'
    if compile and merge:
      label = label + 'Converting frames to scene movie\nand merging scene movies'
    elif compile:
      label = label+'Converting frames to scene movies'
    elif merge:
      label = label+'Merging scene movies'

    if merge and len(scene_list)>1:      
      movie_file = \
        os.path.join(self.master_dir,'movie_'+scene_list[0]+'_'+scene_list[-1]+self.movie_ext)
    else:
      movie_file = \
        os.path.join(self.master_dir,'scene_'+scene_list[-1],'movie'+self.movie_ext)                       
    
    #print os.path.join(os.environ["CCP4MG"],"bin","compile_movie")
    #print args

    rv = JOBCONTROL().start_process(
                name='compile_movie',
                command=os.path.join(os.environ["CCP4MG"],"bin","compile_movie"),
                args= args,
                interpreter = 'python',
                handler=[self.review_compiled_scene,{ 'movie':movie_file}],
                add_job_id = 1,
                progress= { 'TITLE' : 'Compile movie',
                            'HELP'  : 'movies',
                            'LABEL'  : label } )
    if rv[0]:
      MGGUI().WarningMessage(rv[1])
      return
   

#--------------------------------------------------------------------
  def handle_movie_details(self,index='',params={},**keywords):
#--------------------------------------------------------------------
    if not index: return
    details = self.snapshot_details[index]
    params.update(keywords)

    # Take snapshot quality from movie default
    if not  details.has_key('render_quality'): details['render_quality'] = self.render_quality
    for key,value in self.default_details.items():
      if not details.has_key(key): details[key] = value

    if params.has_key('transform'):
      details['transform'] = params['transform']
      
    for key in ['raytrace','interpolate_rock','interpolate_repeats','ramp_start','ramp_end','render_quality']:
      if params.has_key(key): details[key] = int(params[key])
    for key in ['rock_period','rock_angle']:
      if params.has_key(key): details[key] = float(params[key])

    #print "presentation.handle_movie_details",index,self.snapshot_details[index]

    self.pickle_movie(file = self.movie_file)
        
             

#-----------------------------------------------------------------------
  def review_compiled_scene(self,id='',**kw):
#-----------------------------------------------------------------------
    #print "presentation.review_compiled_scene",id,kw

    mess = ''
    status = JOBCONTROL().read_log_file(id)

    #print "review_compiled_scene status",status
    if status.has_key('status') and status['status']:
        if  status['status'] != 'FINISHED':
          messs = 'Error compiling movie.'
    if not kw.has_key('movie'):
        messs = 'Error compiling movie.'
    elif not os.path.exists(kw['movie']):
        mess = mess + 'Movie file '+kw['movie']+' not found.'
        
    if mess:
      mess = mess + ' Look in Tools->Review jobs for further information'
      MGGUI().WarningMessage(mess)
    else:        
      self.play_movie(filename=kw['movie'])

  
#-----------------------------------------------------------------------
  def get_last_frame(self,scene_dir='',ext='*'):
#-----------------------------------------------------------------------
    '''
    Initialise setup at start of recording a movie
    '''
    # Find the last file number
    import glob, string, utils
  
    existing_files = glob.glob(os.path.join(scene_dir,'frame_*.'+ext))
    #print "existing_files",existing_files
    last = 0
    for file in existing_files:
      i = utils.safeInt(string.split \
           (string.split(os.path.basename(file),'_')[-1],'.')[0],0)
      if ( i > last): last = i
    return last


#-----------------------------------------------------------------------
  def get_movie_files(self,scene='*',update_gui=0):
#-----------------------------------------------------------------------
    '''
    Get a list of movie files
    '''
    # Return list of movies
    import glob
    import string
    movie_list = []
    if scene != '*':
      return glob.glob(os.path.join(self.master_dir,'scene_'+scene,'movie*.*'))
    else:
      for path in glob.glob(os.path.join(self.master_dir,'movie*.*')):
        movie_list.append(os.path.basename(path))
      
      path_list = glob.glob(os.path.join(self.master_dir,'scene_'+scene,'movie*.*'))
      for path in path_list:
        split1 = os.path.split(path)
        split2=  os.path.split(split1[0])
        movie_list.append(split2[1]+'/'+split1[1])


      return movie_list



#-------------------------------------------------------------------------
  def pickle_movie(self,file=''):
#--------------------------------------------------------------------------
    import pickle

    if not file: file = self.movie_file

    try:
      errcode = 2
      f = open(file,'w')
      errcode = 3
      pars = self.getparams()
      #print 'presentation.pickle_movie',pars
      #pars['preferences']=PM('movie_preferences').get()
      pickle.dump(pars,f)
      errcode = 4
      f.close()
    except:
      MGGUI().WarningMessage("Error saving movie control file "+file+"\nError code is "+str(errcode))
      return errcode

    return 0
  
#-------------------------------------------------------------------------
  def unpickle_movie(self,file=''):
#-------------------------------------------------------------------------
    import pickle
    pars = {}
    if not os.path.exists(file):
      MGGUI().WarningMessage("Error presentation preferences file "+file+' not found')
      return 1
    try:
      err=1
      f = open(file,'rU')
      if f:
        err=2
        #print "f",f
        pars = pickle.load(f)
        #print "unpickle_movie pars",file,pars
        err=3
        f.close()
      else:
        raise IOError
    except:
      print sys.exc_info()
      MGGUI().WarningMessage("Error reading presentation preferences file "+file+'\nError code='+str(err))
      return 1

    # Load the parameters from the pickle file
    #print 'presentation.unpickle',pars
    for key,value in pars.items(): setattr(self,key,value)
    if self.master_dir :
      import string
      if not self.identifier : self.identifier = string.split( \
          os.path.split(self.master_dir)[1],'.')[0]
    return 0


#----------------------------------------------------------------------
  def compile(self,scene_list=[],overwrite=1,compile=1,ext='gif', \
              encoder='convert',preferences={}):
#----------------------------------------------------------------------
    '''
    Compile the image files in one scene directory into a movie gif
    '''
    try:
      if not self.movie_ext in self.movie_encoder_formats[self.movie_encoder]:
        print "RESETTING SUFFIX to", self.movie_encoder_formats[self.movie_encoder][0]
        self.movie_ext = self.movie_encoder_formats[self.movie_encoder][0]
      if len(self.movie_encoder_fps[self.movie_encoder])>0 and not self.frame_rate in self.movie_encoder_fps[self.movie_encoder]:
        print "RESETTING FRAME RATE to", self.movie_encoder_fps[self.movie_encoder][0]
        self.frame_rate = self.movie_encoder_fps[self.movie_encoder][0]
    except:
        print "problem setting suffix"

    #print "compile ext",ext,self.frame_size,povray
    #print "movie.compile scene",compile,scene_list,preferences
    import re,sys

    log = 0
    
    spawn_mode = os.P_WAIT
    
    if len(scene_list)<1: return [-1,'']
    
    if sys.platform == 'win32':
      master = re.sub('/',r'\\',self.master_dir)
    else:
      master = self.master_dir

    # Check into scene directories and frames exist
    for scene in scene_list:
      err = ''
      scene_dir = os.path.join(master,'scene_'+str(scene))
      if not os.path.exists(scene_dir) or not os.path.isdir(scene_dir):
        return [-2,"Directory does not exist "+scene_dir]
      last_frame = self.get_last_frame(scene_dir)
      if last_frame<=0: err = err + 'No frames recorded for scene '+scene+'\n'
      if self.is_recording_done(scene) > 0:
        err = err + 'Recorded frames not up to date for '+scene +'\n'

    if err: return [-1,err] 
    

    # Create output filename
    scene_dir = os.path.join(master,'scene_'+str(scene_list[0]))
    filename = os.path.join(scene_dir,'movie'+'.'+ext.lstrip('.'))
    # Just return prospective file name    
    if os.path.exists(filename):
      if overwrite:
        utils.remove_file(filename)
      else:
        return [-3,'Output movie file exists: '+filename]

    if not compile:
      # This is just a test inside ccp4mg - if all OK then the
      # compile will be run as a separate process
      return [0,filename]

    if sys.platform == 'win32': filename = utils.msvcescape(filename)


    # Run convert or mencoder  to convert pngs to movie
    if encoder == 'convert':
      encoder_exe = preferences.get('convert_exe','convert')
      #encoder_args = preferences.get('convert_command','-quality 100')
      encoder_args = '-quality '+str(int(self.encoder_quality))
      command = ' -delay '+str(self.frame_rate)+' '+encoder_args+' '
      for scene in scene_list:
        command = ''
	command_list = [encoder_exe]
        scene_dir = os.path.join(master,'scene_'+scene)
        first_frame = 1
        last_frame = self.get_last_frame(scene_dir,ext='png')
        for i in range(first_frame,last_frame+1):
          ppmfile =  os.path.join(scene_dir,'frame_'+('00000'+str(i))[-6:]+ '.png')
	  command_list.append(ppmfile)
          if sys.platform == 'win32': ppmfile = utils.msvcescape(ppmfile)
          command = command + ' ' + ppmfile
        output =  os.path.join(scene_dir,'movie'+ext)
	command_list.append(output)
        if sys.platform == 'win32': output = utils.msvcescape(output)
        command = command + ' ' + output
        #print "convert command",command
        #os.system(encoder_exe+' '+command)
	import subprocess
        try:
            if sys.platform == 'win32':
	        subprocess.call(command_list,shell=True)
            else:
	        subprocess.call(command_list)
        except:
            return [-4,'Failed to run ImageMagick program convert successfully']

    elif encoder == 'mencoder':
      encoder_exe = preferences.get('mencoder_exe','mencoder')
      #encoder_args = preferences.get('mencoder_command','-ovc lavc -lavcopts vcodec=msmpeg4v2:vbitrate=1800')
      encoder_args = '-ovc lavc -lavcopts vcodec=msmpeg4v2:vbitrate=1800'

      for scene in scene_list:
        # This is written to allow possibility of 2 runs of mencoder
        for com in [encoder_args]:
          if com:
            command = ''
            scene_dir = os.path.join(master,'scene_'+scene)
            command=command+'"mf://'+os.path.join(scene_dir,'*.png')+'" '
            # 'fps=' + str(self.frame_rate) +
            command = command + \
                ' -mf type=png ' + com + \
                ' -o ' + os.path.join(scene_dir,'movie'+self.movie_ext)
            #print "mencoder command",command
            if sys.platform == 'win32':
              # Try to get path from the registry
              import _winreg
              try:
                reg_key = _winreg.OpenKeyEx(_winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\mencoder\\Current',0,_winreg.KEY_READ)
              except:
                reg_key = None
              if not reg_key: return [-3,'Can not find mencoder program']
              binpath = _winreg.QueryValueEx(reg_key,'BinPath')[0]
              _winreg.CloseKey(reg_key)
              print "Attempting to run mencoder program:",os.path.join(binpath,'mencoder.exe')
              try:
                os.spawnl(spawn_mode,os.path.join(binpath,'mencoder.exe'),'--',command)
              except:
                print "ERROR starting mencoder"
                return [1,'Can not start mencoder program']
            else:
              #print "command",command
              ret = os.system(encoder_exe+' '+command)
              if ret/512:
                return [1,'Can not start mencoder program']
    elif encoder == 'ffmpeg':
      print '--------------------------------------------------'
      encoder_exe = preferences.get('ffmpeg_exe','ffmpeg')
      #encoder_args = preferences.get('ffmpeg_command','')
      encoder_args = '-f mpeg -vcodec mpeg1video -ar 48000 -b '+str(500000*int(self.encoder_quality))+' -ab 192000 -y'
      print encoder_args

      import glob,sys,shutil
      import subprocess
      for scene in scene_list:
        scene_dir = os.path.join(master,'scene_'+scene)
        file_list = glob.glob(os.path.join(scene_dir,'*.png'))
        file_list.sort()
          
        clist = [encoder_exe,'-i',os.path.normpath(os.path.join(scene_dir,'frame_%06d.png'))]
        clist.extend(encoder_args.strip().split())
        clist.append(os.path.join(scene_dir,'movie'+self.movie_ext))
        #print "ffmpeg command",clist
        try:
          if sys.platform == 'win32':
            subprocess.call(clist,shell=True)
          else:
            subprocess.call(clist)
        except:
          return [-4,'Failed to run ffmpeg successfully']

    return [0,filename]

#-----------------------------------------------------------------------
  def merge_movies(self,scene_list=[],overwrite=1,ext='gif',encoder='convert',preferences={},test=0):
#-----------------------------------------------------------------------

    import os
    import subprocess

    spawn_mode = os.P_WAIT
    
    if sys.platform == 'win32':
      import re
      master = re.sub('/',r'\\',self.master_dir)
    else:
      master = self.master_dir
      
    if len(scene_list) == 1:
        return [0,os.path.join(master,'scene_'+scene_list[0],'movie.'+ext)]
    elif len(scene_list) == 0:
        return [2,'No scenes selected for merging']


    #print "merge_movies scene_list",scene_list
    merged_file = os.path.normpath(os.path.join(master,'movie_'+scene_list[0]+'_'+scene_list[-1]+ext))
    if os.path.exists(merged_file):
      if overwrite:
        utils.remove_file(merged_file)
      else:
        return [-3,'Output movie file exists: '+merged_file]

    command = ''
    nmerge = 0
    input_files = []
    for scene in scene_list:
      if os.path.exists( os.path.join(master,'scene_'+scene ,'movie'+ext)):
        nmerge = nmerge+1
        file =  os.path.join(master,'scene_'+scene ,'movie'+ext)
	input_files.append(os.path.normpath(file))
        if sys.platform == 'win32': file = utils.msvcescape(file)
        command = command + file + ' '
    if nmerge==1:
      return [2,'Only one movie file in selected scene - can not merge']
    elif nmerge == 0:
      return [2,'No movie files in selected scenes - can not merge']


    if test:
      # This is just a test inside ccp4mg - if all OK then the
      # compile will be run as a separate process
      return [0,merged_file]

  
    if encoder == 'convert':
      encoder_exe = preferences.get('convert_exe','convert')
      clist = [encoder_exe]
      for f in input_files:
	      clist.append(f)
      clist.append(merged_file)
      try:
        if sys.platform == 'win32':
          subprocess.call(clist,shell=True)
        else:
          subprocess.call(clist)
      except:
        print 'Can not start ImageMagick program convert'; sys.stdout.flush()
        return [1,'Can not start ImageMagick program convert']

    elif encoder=='mencoder':
      if  sys.platform == 'win32': merged_file = utils.msvcescape(merged_file)
      encoder_exe = preferences.get('mencoder_exe','mencoder')
      #encoder_merge = preferences.get('mencoder_merge_command','-ovc copy')
      encoder_merge = '-ovc copy'
      command = encoder_merge + ' -o '+merged_file + ' ' + command
      #print "merge_movies command",command
      if sys.platform == 'win32':
        # Try to get path from the registry
        import _winreg
        try:
          reg_key = _winreg.OpenKeyEx(_winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\mencoder\\Current',0,_winreg.KEY_READ)
        except:
          reg_key = None
        if not reg_key: return [-3,'Can not find mencoder program']
        binpath = _winreg.QueryValueEx(reg_key,'BinPath')[0]
        _winreg.CloseKey(reg_key)
        try:
          os.spawnl(spawn_mode,os.path.join(binpath,'mencoder.exe'),'--',command)
        except:
          print "ERROR starting mencoder"
          return [1,'Can not start mencoder program']
      else:
        ret = os.system(encoder_exe+' '+command)
        if ret/512:
          return [1,'Can not start mencoder program']

    elif encoder == 'ffmpeg':
      import tempfile
      ftmp = tempfile.NamedTemporaryFile(suffix='.mpg',delete=False)
      for f in input_files:
	      fin = open(f,"rb")
	      ftmp.write(fin.read())
	      fin.close()
      ftmp.close()
      try:
         if sys.platform == 'win32':
            subprocess.call(['ffmpeg','-i',ftmp.name,'-sameq',merged_file],shell=True)
	 else:
            subprocess.call(['ffmpeg','-i',ftmp.name,'-sameq',merged_file])
      except:
         return [-4,'Failed to run ffmpeg successfully']
      return [0,merged_file]

    return [0,merged_file]


  def get_movie_params(self):
    pars = {}
    
#---------------------------------------------------------------------------
  def set_movie_params(self, params={},**keywords):
#---------------------------------------------------------------------------
    params.update(keywords)

    #print "set_movie_params",params
    for key in ['frame_size','frame_rate','movie_ext','movie_encoder','encoder_quality','render_quality','true_transparency','do_render','scale_fonts_and_images']:
      if params.has_key(key):
        setattr(self,key,params[key])

    # Save the new parameters
    self.pickle_movie(file = self.movie_file)


#---------------------------------------------------------------------
  def get_snapshot_list(self):
#---------------------------------------------------------------------
    snap = []
    for item  in self.snapshot_list: snap.append(item)
    return snap

#---------------------------------------------------------------------
  def set_snapshot_list(self,new_list):
#---------------------------------------------------------------------
      self.snapshot_list = []
      for item in new_list:
        self.snapshot_list.append(item)


          
#---------------------------------------------------------------------
  def get_snapshot_details(self,index=''):
#---------------------------------------------------------------------
    pars = {}
    if index:
      index_list = [index]
    else:
      index_list = self.snapshot_details.keys()
    #print 'get_snapshot_details index_list',index_list,
    for idx in index_list:
      pars[idx] = {}
      pars[idx].update(self.snapshot_details[idx])
      if not self.snapshot_details[idx].has_key('transform'):
        pars[idx].update(presentation.default_details)
    return pars

  def snapshot_detail(self,index,key):
    if self.snapshot_details.has_key(index) and  self.snapshot_details[index].has_key(key):
      if ['time','interpolate_time'].count(key):  
         return float(self.snapshot_details[index][key])
      else: 
         return self.snapshot_details[index][key]
    else:
        return presentation.default_details[key]

#---------------------------------------------------------------------
  def getparams(self):
#---------------------------------------------------------------------
    pars = {}
    for item in presentation.initialisation.keys():
      if hasattr(self,item): pars[item] = getattr(self,item)
    #print "presentation.getparams",pars
    return pars

#------------------------------------------------------------------
  def setparams(self,params={},**keywords):
#------------------------------------------------------------------
    import string,re
    params.update(keywords)

    #print 'presentation.setparams',params
    
    # update the snapshot list order
    if params.has_key('snapshot_list'):
      self.snapshot_list = []
      for item in params['snapshot_list']:
        self.snapshot_list.append(item)
        if not self.snapshot_details.has_key(item):
          print "WARNING snapshot_list contains item without details",item
          #self.snapshot_details[item] = {}
      #print "presentation.setparams snapshot_list",self.snapshot_list

    # This handles pre-2.0 data grouped by the attribute
    # In 2.0+ data is grouped  by the snapshot
    for key in ['time','to_snapshot','view','display','interpolate_time']:
      if params.has_key(key):
        nn = -1
        for item in self.snapshot_list:
          nn = nn + 1
          if not self.snapshot_details.has_key(item): self.snapshot_details[item] = {}
          self.snapshot_details[item][key] = params[key][nn]

    # update the snapshot_details for given snapshot id
    for id,value in params.items():
      #print "presentation.setparams",id,value
      if self.snapshot_details.has_key(id):
        self.snapshot_details[id].update(value)

    #print "presentation.setparams snapshot_details",self.snapshot_details
    self.pickle_movie()


#-------------------------------------------------------------------
  def add_movie_snapshot(self,index='',create=1,copy_from=None, \
                         save_changes=''):
#-------------------------------------------------------------------
    import shutil
    backup=''

    #print "add_movie_snapshot",index
    if save_changes and index:
      for mode in ['snapshot','status']:
        filn0 = self.snapshot_file(index,mode=mode)
        if os.path.exists(filn0):
          #Backup to filename with extension derived from epoc time
          backup = self.snapshot_file(index,mode=mode,version=save_changes)
          shutil.copyfile(filn0, backup)
          

    if not index:
      self.last_movie_snapshot_id = self.last_movie_snapshot_id + 1
      index = str(self.last_movie_snapshot_id)
      index = '00000'[0:5-len(index)] + index      

    animation = ['']
    if create:
      filn = self.snapshot_file(index)
      #print "add_movie_snapshot filn",filn
      if os.path.exists(filn): utils.remove_file(filn)
      size = SNAPSHOT_SIZE
      import screenshot
      screenshot.makeScreenshot(filename=filn.encode('utf-8'),size=[size,size],clear_labels=1,render_quality=0)      

      filn0 = self.snapshot_file(index,mode=self.save_file_format)
      if self.save_file_format == 'status':
        copy_to_dir = os.path.dirname(filn0)
        HISTORY().save_status(filename=filn0, \
         overwrite='overwrite',save_list = ['view','data','COLOUR','params','view_options'],copy_to_dir=copy_to_dir)
      else:
        PD().save_picture_definition(filename=filn0,limited_save=0)
      
    if copy_from:
      animation = self.snapshot_details[copy_from]['animation']
    else:
      #Are there any animations - get the frame range
      import global_definitions
      for moldata in global_definitions.get_dataobj(object_type='MolData'):
        if hasattr(moldata,'animation'):
          animation = [moldata.name,moldata.animation.frame_range[0],
                       moldata.animation.frame_range[1]]
          break
    #print 'Presentation.add_movie_snapshot animation',animation,index, self.snapshot_details.has_key(index)
    if not self.snapshot_details.has_key(index):
      self.snapshot_details[index] = {}
      self.snapshot_details[index].update(presentation.default_details)
      self.snapshot_details[index]['animation'] = animation
      self.snapshot_details[index]['to_snapshot'] =index
      if animation != ['']:
        self.snapshot_details[index]['time']= \
          (float(animation[2])-float(animation[1])+1.0)/ \
                 float(self.frame_rate)
        #print 'Presentation.add_movie_snapshot time',self.snapshot_details[index]['time']
    else:
      # Just make sure the animation status us correct
      self.snapshot_details[index]['animation']=animation
      
    if not self.notes.has_key(index):
      self.notes[index] = {
        'title' : ' ',
        'notes' : ' ' }

    #print 'presentation.add_snapshot'
    self.pickle_movie(self.movie_file)
    return index,backup
      

       
#-----------------------------------------------------------------------
  def snapshot_file(self,index='',mode='snapshot',version=''):
#-----------------------------------------------------------------------
    '''
    Return path for file containing status or snapshot image for given index
    '''
    if  mode == 'snapshot':
      ext = self.snapshot_ext
    elif  mode == 'mgpic':
      ext = '.py'
    else:
      ext = '.pkl'
    
    filn = os.path.join(self.master_dir,mode+'_'+str(index))

    # Add the version number extension
    if ['new','replaced','edited'].count(version):
      import time,string,re
      t0 = string.split(time.ctime(time.time()))
      t1 = t0[0]+'_'+t0[2]+'_'+t0[1]+'_'+re.sub(':','_',t0[3])
      filn = filn + '.' + t1 
      if version != 'new': filn = filn + '_' + version
      
    elif version:
      filn = filn + '.' + str(version)

    #print "snapshot_file",index,'*',mode,'*',version,'*',filn
    filn = filn+ext
    return filn

#----------------------------------------------------------------------
  def get_play_list(self,default_all=1,group_interp_ranges=1):
#----------------------------------------------------------------------
    play_list = []
    details = self.snapshot_details
      
    if hasattr(self,'snapshot_select') and self.snapshot_select:
      if self.snapshot_list.count(self.snapshot_select[0]) and \
         self.snapshot_list.count(self.snapshot_select[1]):
        isnap = self.snapshot_list.index(self.snapshot_select[0])
        last = self.snapshot_list.index(self.snapshot_select[1])+1
      else:
        return []
    elif not default_all:
      return []
    else:
      isnap = 0
      last = len(self.snapshot_list)

    if not group_interp_ranges:
      for ii in range(isnap,last):
        play_list.append(self.snapshot_list[ii])
    else:        
      while isnap < last:
        snap = self.snapshot_list[isnap]
        #if details[snap]['display'] == 'interpolate' or \
        #      details[snap]['view'] == 'glide':
      
        if details[snap]['to_snapshot'] != snap and \
          self.snapshot_list.count( details[snap]['to_snapshot']) and \
          self.snapshot_list.index( details[snap]['to_snapshot']) > isnap:
          play_list.append(self.snapshot_list[isnap: self.snapshot_list.index( details[snap]['to_snapshot']) +1])
          isnap = self.snapshot_list.index( details[snap]['to_snapshot'])
        else:
          play_list.append([snap])
        isnap = isnap + 1
    #print "snapshot_select",self.snapshot_select,"play_list",play_list
    return play_list


#-----------------------------------------------------------------------
  def is_recording_done(self,snap):
#-----------------------------------------------------------------------
    import glob
    scene_dir = os.path.join(self.master_dir,'scene_'+snap)
    if not os.path.exists(scene_dir):
      return -1
    if not glob.glob(os.path.join(scene_dir,'frame*')):
      return -2

    if not self.recorded_details.has_key(snap):
      return 1
    if self.snapshot_details[snap] != self.recorded_details[snap]:
      #print 'is_recording_done no',self.snapshot_details[snap], self.recorded_details[snap]
      return 1


    return 0


#----------------------------------------------------------------------
  def make_frame(self,repeat=1,**keywords):
#----------------------------------------------------------------------
    '''
    Make one frame  of a movie
    '''
    from PyQt4 import QtOpenGL

    current_scene = keywords.get('scene')
    self.last_frame = self.last_frame+1
    #print "make_frame current_scene",current_scene,self.last_frame

    if self.make_frame_mode == 'preview':
      return 0

    elif self.make_frame_mode == 'internal':
      import opengl, image_info,  ffmpeg_wrapper
      yuv = image_info.image_info_yuv_tPtr(opengl.get_yuvdata())
      #print yuv.y
      #print yuv.u
      #print yuv.v
      ffmpeg_wrapper.AddYUVMovieFrame(yuv)
      if repeat>1:
        n = 1
        while n < repeat:
          n = n + 1
          ffmpeg_wrapper.AddMovieFrame(yuv.y,yuv.u,yuv.v)
      return 0

    else:
      #print "snapshot_details", self.snapshot_details[current_scene]
 
      filn = os.path.join(self.master_dir,'scene_'+str(current_scene),
                    'frame_'+('00000'+str(self.last_frame))[-6:])+'.png'

      if self.snapshot_details[current_scene].has_key('render_quality'):
          render_quality = self.snapshot_details[current_scene]['render_quality']
      else:
          render_quality=self.render_quality

      # Somehow need to consider scaling text and images.
      if not self.do_render: # Simple Screenshot
        import tempfile
        from PyQt4 import QtGui,QtCore
        import screenshot
        import MGApplication
        havePixiePlugin = True
        try:
          from PixieDialog import RendererCore
          mainwin = MGApplication.GetMainWindow()

          if self.scale_fonts_and_images: # Scale text and images using rendererCore methods.
            oldDrawImages = mainwin.glWidget.drawImages
            oldDrawText = mainwin.glWidget.drawText
            oldDrawTextSeparately = mainwin.glWidget.drawTextSeparately
            mainwin.glWidget.drawImages = False
            mainwin.glWidget.drawText = False
            mainwin.glWidget.drawTextSeparately = False
        except:
          havePixiePlugin = False
          # After all PixieDialog is a plugin.
          pass

        if False:#QtOpenGL.QGLPixelBuffer.hasOpenGLPbuffers ():
          screenshot.makeScreenshot(filename=filn.encode('utf-8'),clear_labels=1,render_quality=0,hideWindows=0,use_pbuffer=True,size=[self.frame_size[0],self.frame_size[1]])
        else:
          screenshot.makeScreenshot(filename=filn.encode('utf-8'),clear_labels=1,render_quality=0,hideWindows=0)

        if self.scale_fonts_and_images and havePixiePlugin: # Scale text and images using rendererCore methods.
          mainwin.glWidget.drawImages = oldDrawImages
          mainwin.glWidget.drawText = oldDrawText
          mainwin.glWidget.drawTextSeparately = oldDrawTextSeparately
          fontScaling = 1.0
          if hasattr(mainwin,"savedGLSize"):
            fontScaling = float(self.frame_size[1])/mainwin.savedGLSize[1]
          renderer = RendererCore()
          mainwin = MGApplication.GetMainWindow()
          renderer.glScale = mainwin.glWidget.viewsize* mainwin.glWidget.RADIUS *2 / 60.0
          labelsAndImages = renderer.renderFile(mainwin.glWidget,"dummy.tiff",filn,getGLScale=False,size=self.frame_size,current_size_in=mainwin.glWidget.size(),transparent=False,raytrace=False,smoothRibbons=False,darkInside=False,createInputFile=False,fontScaling=fontScaling)
	  renderer.applyTextLabelsFromLabelsAndImages(labelsAndImages,filn,[255,255,255],transparent=False)

      else: # render!
        import tempfile
        from PyQt4 import QtGui,QtCore
        import MGApplication
        from PixieDialog import RendererCore

        renderer = RendererCore()
        f = filn
        if f.rfind(".")>-1:
          frib = f[:f.rfind(".")]+".rib"
        else:
          frib = f+".rib"
        ftiff_ = tempfile.mkstemp(".tiff",prefix="ccp4mg"+str(os.getpid()))
        ftiff = ftiff_[1]
        os.close(ftiff_[0])
        mainwin = MGApplication.GetMainWindow()
        renderer.glScale = mainwin.glWidget.viewsize* mainwin.glWidget.RADIUS *2 / 60.0
	# Need to sort options
        labelsAndImages = renderer.renderFile(mainwin.glWidget,frib,ftiff,getGLScale=False,size=self.frame_size,current_size_in=mainwin.glWidget.size(),transparent=False,raytrace=False,smoothRibbons=False,darkInside=False)
        renderer.runPixie(frib,ftiff,labelsAndImages,transparent=False)
	renderer.applyTextLabelsFromLabelsAndImages(labelsAndImages,ftiff,[255,255,255],transparent=False)
        fin = QtGui.QImage(ftiff)
        fin.save(filn)
        os.unlink(ftiff)
      
      if repeat>1:
        n = 1
        while n < repeat:
          n = n + 1
          self.last_frame = self.last_frame+1
          fr = os.path.join(self.master_dir,'scene_'+str(current_scene),
                       'frame_'+('00000'+str(self.last_frame))[-6:])+'.png'
        ##NEED TO DO A COPY *************************
      return 0

#-----------------------------------------------------------------------
  def end_transform(self,compile=0,play_list={},**kw):
#-----------------------------------------------------------------------
    #print "presentation.end_transform",compile,play_list,kw
    if self.make_frame_mode == 'internal':
      ffmpeg_wrapper.CloseMovie()

    for scene in play_list:
      #print 'end_transform scene',scene
      self.recorded_details[scene[0]] = {}
      self.recorded_details[scene[0]].update(self.snapshot_details[scene[0]])

    #print 'end_transform',self.recorded_details
        
    if not self.do_render:
      MAINWINDOW().setGLSize(restore=1)
    MAINWINDOW().hideWindows(open=1)

    if compile:
      self.run_compile(merge=1)

 

#-----------------------------------------------------------------------
  def do_backup_data_files ( self,dir='',project='' ,compress=0):
#-----------------------------------------------------------------------
    import shutil,glob,pickle
    import dataobj,utils

    if not dir:
      # Default is to save to the master directory
      dir = os.path.join(self.master_dir)
    else:
      # Cleanout or create any named directory ?????
      if os.path.exists(dir): shutil.rmtree(dir)
      if not os.path.exists(dir):
        try:
          os.mkdir(dir)
        except:
          return (1,'Error creating directory'+dir)

    #print 'Presentation.do_backup_data_files',dir
    
    errors = []
    for indx in self.snapshot_list:
      filn = self.snapshot_file(index=indx,mode='status')
      status =  HISTORY().load_pickle_file(filename=filn)
      if status:
        # Copy all data files to this directory
        print " Presentation.do_backup_data_files status['Data_list']", status['Data_list']
        for objname in status['Data_list']:
          if status.has_key(objname) and \
                status[objname].dataparams.has_key('filename'):
            rv = status[objname].copy_data_files(dir=dir,project=project)
            #print "Presentation.do_backup_data_files rv",rv
            if rv[0]:
              for error in rv[1]:
                if not errors.count(error): errors.append(error)

      # Save the updated status
      f = utils.openFile(filn,'w',overwrite='overwrite')
      pickle.dump(status,f)
      f.close()
      

    if errors:
        text = errors[0]
        for item in errors[1:]: text = text +'\n' + item
        return [1,text]

    if compress:
      import utils
      rv = utils.ZipAFile(filelist=[self.master_dir],zip_file=self.master_dir+'.zip')
      if rv[0]:
          return [1,[rv[1]]]
      else:
        return [0,'Saved presentation to '+self.master_dir+'.zip']
    else:
      return [0,'All data files copied to '+self.master_dir]

  
          
#---------------------------------------------------------------------------
  def copy_changes(self,index='',oldfile='',new_index='',new_version='', \
                   targets=[],recreate_snapshot=1):
#---------------------------------------------------------------------------

    # Get the differences between the old and new version of the
    # index status files
    import shutil,pickle
    
    old_status =  HISTORY().load_pickle_file(filename=oldfile)
    if not new_index: new_index=index
    filename =  self.snapshot_file(index,mode='status',version=new_version)
    new_status = HISTORY().load_pickle_file(filename=filename)

    # Parameters
    param_diffs = old_status['params'].difference(new_status['params'].data)
    #print "params diffs",param_diffs

    #Display data
    diffs=HISTORY().status_difference(old_status,new_status)
    #print "status_difference diffs",diffs

    if not diffs:
        MGGUI().WarningMessage('No differences between '+index+ ' version '+str(version)+ '\\n and '+new_index+' version '+new_version+'\\n No changes applied')
    
    #print "targets",targets
    # Make sure selection does not include the original changed snapshot
    if targets.count(index): targets.remove(index)
    for indx in targets:
      filename =  self.snapshot_file(indx,mode='status')
      #print "copy_changes indx",indx
      status =  HISTORY().load_pickle_file(filename=filename)
      HISTORY().status_add(status,diffs[0],diffs[1],diffs[2])
      if param_diffs: status['params'].add(param_diffs)
      backup = self.snapshot_file(indx,mode='status',version='edited')
      try:
        shutil.copy( filename,backup )
        shutil.copy( os.path.splitext(filename)[0]+self.snapshot_ext, \
                     os.path.splitext(backup)[0]+self.snapshot_ext )
      except:
        pass

      f = utils.openFile(filename,'w',overwrite=1)
      if f: 
        pickle.dump(status,f)
        f.close()
      else:
        MGGUI().WarningMessage('Error saving updated status to '+filename)
      if recreate_snapshot:
        self.restore_status(action='restore',index=indx)
        # Can not use apply method to restore here as will save
        # the status file in add_movie_snapshot
        indx0,backup = self.add_movie_snapshot(index=indx)
        if indx0>0:
          self.update_gui_details(indx)
        else:
          MGGUI().WarningMessage('Error saving updated snapshot for '+indx)

      del status

#-----------------------------------------------------------------------
  def write_html(self,file='',template_file=''):
#-----------------------------------------------------------------------
    import os,utils,re

    #Get name for output html file
    backup = 0
    if not file: file = os.path.join(self.master_dir,'index.html')

    if os.path.exists(file):
      root,ext = os.path.splitext(file)
      while backup == 0 or os.path.exists(backup_file):
        backup = backup + 1
        backup_file = root + '_' + str(backup) + '.' + ext
    
    
    #Read template file
    if not template_file:
      template_file = os.path.join (os.environ["CCP4MG"],'data','presentation_template.html')
    if not os.path.exists(template_file):
      return [1,'Template file '+template_file+' does not exist']
    f = utils.openFile(template_file,'r')
    if f: 
      template =  f.read()
      f.close()
    else:
      return [1,'Error reading template file '+template_file]

    #Parse template file
    rx = re.search(r'(.*)<CCP4MG_INDEX_LOOP>(.*)</CCP4MG_INDEX_LOOP>(.*)',template,re.DOTALL)
    #if rx: print "rx.groups",rx.groups()
    if not rx or len(rx.groups())!=3:
      return [1,'Error could not find \\n<CCP4MG_INDEX_LOOP>..</CCP4MG_INDEX_LOOP> in template file \\n'+template_file]
    head,loop,tail = rx.groups()


    # Create the html file content
    content = re.sub('%TITLE%',self.title,head)

    for indx in self.snapshot_list:
      content = content + re.sub ('%REFERENCE%', self.identifier, re.sub ( '%INDEX%',indx,loop))

    content = content + tail

    # make backup
    if backup>0:
      import shutil
      shutil.copyfile(file,backup_file)
      
    # Write html file
    f = utils.openFile(file,'w',overwrite=1)
    if f:
      try:
        f.write(content)
        f.close()
      except:
        return [1,'Error writing to file '+file]
    else:
      return [1,'Error opening file '+file]

    return [0,file]


  def setInterrupt(self):
    #print 'presentation.setInterrupt'
    self.interruptSet = 1

#------------------------------------------------------------------------
  def transform ( self,play_list=[],update_method='',finish_method='',label=0,interrupt_label='',**keywords):
#-----------------------------------------------------------------------


    self.do_label=label
    self.update_method = update_method
    self.finish_method = finish_method
    if interrupt_label:
      self.interrupt_label = interrupt_label
    else:
      self.interrupt_label = 'Transform'

    self.transform_play_list = play_list
    self.transform_scene = 0
    self.interruptSet = 0
    self.setup_scene_transform()
 
    MAINWINDOW().addAnimationHandler(self.interrupt_label,self.next_transform)
    self.interruptable = 1

#-----------------------------------------------------------------------
  def setup_scene_transform(self):
#-----------------------------------------------------------------------

    #print "setup_scene_transform transform_scene",self.transform_scene 
    interpolate_status = 1
    snap_list = self.transform_play_list[self.transform_scene]
    
    scene = snap_list[0]
    #print "setup_scene_transform scene",snap_list,scene,self.snapshot_detail(scene,'view') 
    # Set information for make_frame method
    self.last_frame = 0
    
    # Restore the initial status
    initial_status = HISTORY().load_pickle_file(filename=self.snapshot_file(scene,mode='status'))
    self.restore_status(id=scene)
    import rebuild
    rebuild.UpdateDisplay()

    # Initialise parameters for Transform
    max_repeat=self.snapshot_detail(scene,'interpolate_repeats')
    period=self.snapshot_detail(scene,'time')
    ramp_start = self.snapshot_detail(scene,'ramp_start')
    ramp_end = self.snapshot_detail(scene,'ramp_end')
    interpolate_rock=self.snapshot_detail(scene,'interpolate_rock')
    transf=[[0.0,0.0,0.0, 0.0,0.0,0.0, 0.0]]
    transform_rock = 0
    interpolate_view = []
    update_objects = []

    # Beware snapshot without animation has [scene]['animation']=['']
    if self.snapshot_details[scene].has_key('animation') and \
               self.snapshot_details[scene]['animation'][0]:
      update_objects.extend(get_dataobj(name= self.snapshot_details[scene]['animation'][0]))

    ntransparent = HISTORY().get_status_transparency(initial_status)
    #print 'setup_scene_transform ntransparent',ntransparent
    self.status_list = [[initial_status,0,ntransparent]]
    for snap in snap_list[1:]:
      stat = HISTORY().load_pickle_file(filename=self.snapshot_file(snap,mode='status')) 
      frac_time =  self.snapshot_detail(snap,'interpolate_time'
                                        )
      ntransparent = HISTORY().get_status_transparency(stat)
      self.status_list.append([stat,frac_time,ntransparent])
          
    if self.snapshot_detail(scene,'view') == 'rotate':
          transf=[[0.0,360.0,0.0, 0.0,0.0,0.0, 0.0]]
    elif self.snapshot_detail(scene,'view')== 'rock':
          rock_period = self.snapshot_detail(scene,'rock_period')
          transform_rock = int((period/float(rock_period))+0.5)
          rock_angle = self.snapshot_detail(scene,'rock_angle')
          transf = [[ 0.0,rock_angle,0.0, 0.0,0.0,0.0, 0.0, 0.0]]
    elif self.snapshot_detail(scene,'view') == 'transform':           
          transf = [self.snapshot_detail(scene,'transform')]
          transform_rock = interpolate_rock
    elif self.snapshot_detail(scene,'view') == 'glide':
          transf = []
          for snap in snap_list:
            status,view=self.read_view(filename=self.snapshot_file(snap,mode='status'))
            frac_time =self.snapshot_detail(snap,'interpolate_time')
            if status:
              return 1
            else:
              interpolate_view.append([view,frac_time])

   
    if interpolate_view:
      rock_centre = 0
    else:
      rock_centre = 1

    nsteps = int ( 0.5 + (period * self.frame_rate))
    #print "period,frame_rate,nsteps",period,frame_rate,nsteps
    if nsteps<=2: nsteps = 3
    if transform_rock and rock_centre:
      nsteps = 4 * int((nsteps+2)/4)
    elif transform_rock:
      nsteps = 2 * int((nsteps+1)/1)
    
    if max_repeat<=0:
      self.maxframes = 0
    else:
      self.maxframes = nsteps*max_repeat


    self.vpattern = []
    self.tpattern = []
    self.spattern = []

    if len(interpolate_view)>1:
      MAINWINDOW().setViewParams(interpolate_view[0][0])
      time_frac_total = 0
      for iv in interpolate_view[1:]: time_frac_total=time_frac_total + iv[1]
      for vw in range(0,len(interpolate_view)-1):
        ns = nsteps * (interpolate_view[vw+1][1]/time_frac_total) * \
                1.0/float(interpolate_rock+1) # number steps between each view
        r_start = 0
        r_end = 0
        if vw==0:  r_start = ramp_start
        if vw==len(interpolate_view)-2:  r_end = ramp_end
        self.vpattern.append([[interpolate_view[vw][0],interpolate_view[vw+1][0]], \
                     self.get_steps(nsteps=ns,ramp_start=r_start,ramp_end=r_end)])
      
      if interpolate_rock:
        # Repeat everything in reverse
        for vw in range(len(interpolate_view)-1,0,-1):
          ns = nsteps * (interpolate_view[vw][1]/time_frac_total) * \
               1.0/float(interpolate_rock+1) # number steps between each view
          self.vpattern.append([[interpolate_view[vw][0],interpolate_view[vw-1][0]],\
                     self.get_steps(nsteps=ns)])
      self.vshot = 0
      self.vframe = -1
    else:
      if not transf: transf=[[0.0,0.0,0.0, 0.0,0.0,0.0, 0.0, 0]]
      ns = nsteps/len(transf)
      for tr in transf:
        self.tpattern.append([tr,self.get_steps(nsteps=ns,rock=transform_rock,delta=1,centre_rock=1)])
      self.tshot = 0
      self.tframe = -1
    
    #if interpolate_status:
    update_dataobj_list=[]
    #print 'transform len self.status_list',len(self.status_list)
    if len(self.status_list)>1:
      time_frac_total=0.0
      for iv in self.status_list[1:]: time_frac_total=time_frac_total + iv[1]
      for st in range(0,len(self.status_list)-1):
        #print "nsteps",nsteps,"status_list[st+1][1]",status_list[st+1][1],"time_frac_total",time_frac_total
        ns = nsteps * (self.status_list[st+1][1]/time_frac_total) * \
              1.0/float(interpolate_rock+1)
        # number steps between each view
        update_dataobj_list=self.get_changed_objects( \
                 self.status_list[st][0],self.status_list[st+1][0],
                 interpolate_status=interpolate_status)

        #print "Transform update_dataobj_list",update_dataobj_list
        # beware -- we dont have initial and final status for the following objects
        for item in update_objects:
          if not update_dataobj_list.count(item): update_dataobj_list.append([item,None,None])
        if update_dataobj_list:
          pattern = self.get_steps(nsteps=ns,rock=0)
          #print "spattern",pattern
          self.spattern.append([update_dataobj_list,pattern])

          
      if interpolate_rock:
        # 'Rock' back by reversing though the different states
        for st in range(len(self.status_list)-1,0,-1):
          ns = nsteps * (self.status_list[st][1]/time_frac_total) * \
              1.0/float(interpolate_rock+1)
          # number steps between each view
          update_dataobj_list=self.get_changed_objects( \
                 self.status_list[st][0],self.status_list[st-1][0],
                 interpolate_status=interpolate_status)
          # beware -- we dont have initial and final status for the following objects
          for item in update_objects:
            if not update_dataobj_list.count(item): update_dataobj_list.append([item,None,None])
          if update_dataobj_list:
            pattern = self.get_steps(nsteps=ns,rock=0)
            self.spattern.append([update_dataobj_list,pattern])

    else:
      ns=nsteps
      for item in update_objects:
        update_dataobj_list.append([item,None,None])
      if update_dataobj_list:
        self.spattern.append([update_dataobj_list,self.get_steps(nsteps=ns,rock=interpolate_rock)])
          
    self.sshot = 0
    self.sframe = -1
      
    #print "setup_scene_transform vpattern",len(self.vpattern)
    #print "tpattern",len(self.tpattern),self.tpattern
    #print "spattern",len(self.spattern)
    
    self.iframe = -1

    return 0

#----------------------------------------------------------------------------------------------------
  def next_transform(self):
#----------------------------------------------------------------------------------------------------
      import time
      import rebuild

      #print "next_transform", self.vpattern

      if self.interruptSet:
        MAINWINDOW().removeAnimationHandler(self.interrupt_label)
        self.interruptSet = 0
        self.interruptable = 0
        return
      
      # Set up the grapics thread for transform
      glWidget = GLWIDGETS()[0]
      ntransparent = 0
      
      self.iframe = self.iframe + 1
      #print "next_transform iframe",self.iframe
      if self.do_label: self.label(text=str(self.iframe+1))

      if self.spattern:
        #if interpolate_status:
        self.sframe = self.sframe+1
        if self.sframe>=len(self.spattern[self.sshot][1]):
          self.sframe = 0
          self.sshot = self.sshot + 1
          if self.sshot>=len(self.spattern):
            self.sshot= 0
            HISTORY().update_data_status( \
              status=self.status_list[0][0],restore_all_visible=1)
            
        frac = self.spattern[self.sshot][1][self.sframe]
        #print "sshot frac",self.sshot,frac
        #if interpolate_status:
        for item in self.spattern[self.sshot][0]:
          if item[1]: ntransparent = ntransparent + item[1].nofTransparentObjects()
          if item[2]: ntransparent = ntransparent + item[2].nofTransparentObjects()
          item[0].movie_interpolation(initial_status=item[1], \
              final_status=item[2],fraction=frac,step=self.sframe)

        #print 'ntransparent',ntransparent

      #if spattern or label:
      update_transparency =  ( self.true_transparency and ntransparent>0 )
      if self.spattern or self.do_label or update_transparency :
        if update_transparency:
            saved_transparency = glWidget.transparency()
            glWidget.setTransparency(1)
        rebuild.UpdateDisplay(auto_save=0)
        if update_transparency: glWidget.setTransparency(saved_transparency)

      if self.vpattern:
        import pygl_coord
        qPtr = pygl_coord.doublea(4)
        start_quat = pygl_coord.Quat()
        end_quat = pygl_coord.Quat()

        self.vframe = self.vframe+1
        if self.vframe>=len(self.vpattern[self.vshot][1]):
          self.vframe = 0
          self.vshot = self.vshot + 1
          if self.vshot>=len(self.vpattern): self.vshot= 0

        start = self.vpattern[self.vshot][0][0]
        end = self.vpattern[self.vshot][0][1]
        frac = self.vpattern[self.vshot][1][self.vframe]

        for ii in range(0,4):qPtr[ii]=start['quat'][ii]
        start_quat.Setdval(qPtr)
        for ii in range(0,4):qPtr[ii]=end['quat'][ii]
        end_quat.Setdval(qPtr)
        l1,l2= pygl_coord.Quat.Distance(start_quat,end_quat), pygl_coord.Quat.Distance(start_quat,-end_quat)
        if abs(l1)<0.01:
          quat = None
        elif l2>=l1:
          quat = pygl_coord.Quat().Slerp(start_quat,end_quat,frac)
        else:
          quat = pygl_coord.Quat().Slerp(start_quat,-end_quat,frac)
        if quat: glWidget.setQuatNoUpdate(quat)
        
        if start.has_key('rpos'):
          rpos = []
          for j in range(0,3): rpos.append( 
                 ((1.0-frac)*start['rpos'][j])+(frac*end['rpos'][j]))
          glWidget.setPositionNoUpdate(rpos)
        if start.has_key('RADIUS'):
          glWidget.setZoomNoUpdate((((1.0-frac)*start['RADIUS'])+(frac*end['RADIUS'])))
          
        if start.has_key('pos'):
          pos = []
          for j in range(0,3): pos.append( 
                  ((1.0-frac)*start['pos'][j])+(frac*end['pos'][j]))
          glWidget.setPositionNoUpdate(pos)

        if start.has_key('scale'):
          glWidget.setZoomNoUpdate((((1.0-frac)*start['scale'])+(frac*end['scale'])))

        if start.has_key('fog_near') and start.has_key('fog_far'):
          glWidget.setFogNearAndFar((((1.0-frac)*start['fog_near'])+(frac*end['fog_near'])),(((1.0-frac)*start['fog_far'])+(frac*end['fog_far'])))

        if start.has_key('slab_width') and start.has_key('slab_offset') and start.has_key('slab_enabled'):
          glWidget.setSlab(start['slab_enabled'],(((1.0-frac)*start['slab_width'])+(frac*end['slab_width'])),(((1.0-frac)*start['slab_offset'])+(frac*end['slab_offset'])))

      if self.tpattern:
        self.tframe = self.tframe+1
        if self.tframe>=len(self.tpattern[self.tshot][1]):
          self.tframe = 0
          self.tshot = self.tshot + 1
          if self.tshot>=len(self.tpattern): self.tshot= 0

        transf = self.tpattern[self.tshot][0]
        frac =  self.tpattern[self.tshot][1][self.tframe]
        #print "tframe,tshot,frac,transf",tframe,tshot,frac,transf
        glWidget.setRotationNoUpdate(transf[0]*frac,transf[1]*frac,transf[2]*frac )
        #glWidget.setPosition((transf[3]*frac,transf[4]*frac,transf[5]*frac ))
        #glWidget.setZoom( transf[6]*frac )
	#glWidget.frame_count = str(self.iframe+1)

      glWidget.updateGL()
      glWidget.emit(QtCore.SIGNAL("PositionChanged"),(glWidget))
      glWidget.emit(QtCore.SIGNAL("QuatChanged"),(glWidget))
      glWidget.emit(QtCore.SIGNAL("ZoomChanged"),(glWidget))
      #self.update_dependents('transform')
      if self.update_method:
        rv = self.update_method(scene=self.transform_play_list[self.transform_scene][0])


      if self.maxframes and self.iframe>= self.maxframes-1:
        if self.do_label: self.label(delete=1)
        MAINWINDOW().removeAnimationHandler(self.interrupt_label)
        self.interruptable = 0
        if self.transform_scene < len(self.transform_play_list)-1:
          self.transform_scene = self.transform_scene + 1
          self.setup_scene_transform()
          MAINWINDOW().addAnimationHandler(self.interrupt_label,self.next_transform)
        elif self.finish_method:
          DISPLAYTABLE().update()
          apply(self.finish_method[0],[],self.finish_method[1])


#--------------------------------------------------------------------
  def get_steps(self,nsteps=1,rock=0,centre_rock=0,delta=0,mode='', \
                ramp_start=0, ramp_end=0):
#--------------------------------------------------------------------
    ramp_start=2*(ramp_start/2)
    ramp_end=2*(ramp_end/2)
    #print "get_steps",ramp_start,ramp_end,rock
    tmp = []
    if mode == 'sine':
      import math,copy
      last_phase = 0.0
      if rock:
        f = 2.0
      else:
        f= 1.0
      for step in range (1,nsteps+1):
        phase = math.sin ( float(step) * math.pi * f / nsteps )
        if delta:
          tmp.append(phase-last_phase)
        else:
          tmp.append(phase)
        last_phase=copy.deepcopy(phase)
  
    else:
      ns = int(nsteps/(rock+1))
      #print 'get_steps ns',ns
      if rock and centre_rock:
        if delta:
          frac = 1.0/float(ns)
          for i in range(0,ns/2): tmp.append(-frac)
          for i in range(0,ns): tmp.append(frac)
          for i in range(0,ns/2): tmp.append(-frac)
        else:
          for i in range(ns/2,-1,-1): tmp.append(float(i)/float(ns))
          for i in range(0,ns): tmp.append(float(i)/float(ns))
          for i in range(ns,ns/2,-1): tmp.append(float(i)/float(ns))
      else:
        if ramp_start+ramp_end>0:
          inc = 1.0/(float(ns-(ramp_start+ramp_end))+ \
                   0.5*float(ramp_start+ramp_end))
        else:
          inc = 1.0/float(ns)
        if delta:
          for i in range(0,ns): tmp.append(inc)
          if rock:
            for i in range(0,ns): tmp.append(-inc)
        else:
          frac = 0.0
          if ramp_start:
            for i in range(1,ramp_start+1):
              tmp.append(frac)
              #print "i",i,float(i-1)/float(ramp_start),frac
              frac=frac+(inc*float(i)/float(ramp_start))
          for i in range(ramp_start+1,ns-ramp_end+1):
            frac=frac+inc
            #print "i",i,frac
            tmp.append(frac)
          if ramp_end:
            for i in range(ns-ramp_end+1,ns+1):
              frac=frac+(inc*float(ns-i)/float(ramp_end))
              #print "i",i,float(ns-i)/float(ramp_end),frac
              tmp.append(frac)
            
          if rock:
            for i in range(ns-1,-1,-1):
              tmp.append(tmp[i])

    #print 'get_steps',nsteps,tmp
    if rock>1:
      for nn in range(2,rock+1):
        for i in range(0,ns): tmp.append(tmp[i])

    #print "tmp",tmp
    return tmp


#------------------------------------------------------------------------
  def get_changed_objects(self,initial_status,final_status,
                          interpolate_status=1):
#------------------------------------------------------------------------
    changed_list = []

    #print "transform.get_changed_objects interpolate_status",interpolate_status,initial_status.keys(),final_status.keys()

    if interpolate_status:

      # Get list of ShadowDataObj which have changed between the initial and final status
      # and convert this to list of names
      difobj_list = HISTORY().status_difference(initial_status,final_status)[0]
      difobj_name_list = []
      for item in difobj_list: difobj_name_list.append(item.name)
      #print 'presentation.get_changed_objects',difobj_name_list
      # Create list with one item for each currently loaded dataobj
      # Each item in list is [dataobj, dataobj_initial_status, dataobj_final_status]
      # The dataobj_initial_status and dataobj_final_status are None if there arew no changes
      import dataobj
      for item in dataobj.get_dataobj():
        if difobj_name_list.count(item.name):
          changed_list.append([item,initial_status[item.name],final_status[item.name]])
        else:
          changed_list.append([item,None,None])
      #print 'presentation.get_changed_objects changed_list',changed_list

      '''
      import dataobj
      for item in dataobj.get_dataobj():
        if initial_status.has_key(item.name) and \
             final_status.has_key(item.name):
            initial_obj = initial_status[item.name]
            final_obj = final_status[item.name]
            if initial_obj == final_obj:
              #print "transform.get_changed_objects initial and final status identical for",item
              changed_list.append( [item,None,None])
            else:
              changed_list.append([item,initial_obj,final_obj])
      '''
      
         
      if initial_status.has_key('COLOUR') and final_status.has_key('COLOUR'): 
        diffs = MGCOLOUR().compare_objects( \
          initial_status['COLOUR'],final_status['COLOUR'])
        #print "COLOUR diffs",diffs
        if diffs[0]:                                       
          changed_list.append([MGCOLOUR(),diffs[0],diffs[1]])

      if initial_status.has_key('params') and final_status.has_key('params'): 
        import services
        for key in initial_status['params'].data.keys():
          if final_status['params'].data.has_key(key) and  services.PM(key):
            diffs=services.PM(key).compare_objects( \
                       initial_status['params'].data[key], \
                       final_status['params'].data[key])
            #print "diffs",key,diffs
            if diffs[0]:
              changed_list.append([services.PM(key),diffs[0],diffs[1]])
              

    #print "transform.get_changed_objects changed_list",changed_list
    return changed_list

   
#------------------------------------------------------------------------
  def read_view(self,filename=''):
#------------------------------------------------------------------------
    '''
    Read the view from a status file
    '''
    import pickle
    params={}
    if not os.path.exists(filename): return [1,params]
    try:
      f = open(filename,'r')   
    except:
      return [1,params]
    try:
      status = pickle.load(f)      
    except:
      return [2,params]

    if status.has_key('view'):
      for key in ['rpos','RADIUS','NEAR','FAR','quat']:
        params[key] = getattr(status['view'],key)
      return [0,params]
    elif status.has_key('view2'):
      #print "transform.read_view",status['view2']
      for key in ['pos','scale','quat','fog_far','fog_near','slab_width','slab_offset','slab_enabled']:
        params[key] = status['view2'].get(key)
      return [0,params]

    return [3,params]
    
#-----------------------------------------------------------------
  def label(self,text='transform label',delete=0):
#------------------------------------------------------------------
    import build,cprim,pygl_coord,graphicsmodel

    #print "transform::label",text

    if delete:
      
      #if  hasattr(self,'label_graphmod') and  self.label_graphmod:
      #  build.build.insts.deletemod(self.label_graphmod)
      #  del self.label_graphmod
      #  del self.label_graphmod_obj
      return

    else:

      if not hasattr(self,'label_graphmod') or not self.label_graphmod:
        import build 
        self.label_graphmod = graphicsmodel.graphicsmodel( )
        build.build.insts.append(self.label_graphmod)

      if hasattr(self,'label_graphmod_obj') and len(self.label_graphmod_obj)>0:
        for obj in self.label_graphmod_obj:
          cprim.DeleteTextLabel(self.label_graphmod.obj,obj.GetID())

      self.label_graphmod_obj = []
      x,y=0.1,0.9
      label_ob = cprim.BillBoardText( \
                  pygl_coord.Cartesian(x,y,0.0), \
                  text, pygl_coord.Cartesian(x,y,0.0))

      label_ob.thisown = 0

      self.label_graphmod.obj.add_text_primitive(label_ob)
      self.label_graphmod_obj.append(label_ob)
      self.label_graphmod.obj.rebuild()
      font = DT().viewmenu.default_font
      self.label_graphmod.obj.SetTextFont(str(font['family']),str(font['weight']), \
                                    str(font['slant']),'24',font['underline'])

    
#-------------------------------------------------------------------
  def play_movie(self,filename):
#-------------------------------------------------------------------
    import os
    from PyQt4 import QtGui,QtCore
    image_formats_c = QtGui.QMovie.supportedFormats() 
    image_formats = []
    for im in image_formats_c:
        if not image_formats.count(str(im).lower()):
          image_formats.append(str(im))

    if os.path.exists(filename):
      name_split = os.path.splitext(filename)
      if len(name_split)>1 and '.' in name_split[1] and image_formats.count(name_split[1][1:]):
        viewer =  FILEVIEWER(self.identifier)
        viewer.open(filename,format='movie',title=filename)
      else:
        if sys.platform == 'linux2':
          viewer =  FILEVIEWER(self.identifier)
          viewer.open(filename,format='movie_phonon',title=filename)
        else:
          QtGui.QDesktopServices.openUrl(QtCore.QUrl.fromLocalFile(filename))

#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
class movie_preferences:
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------

  insts = None

#-------------------------------------------------------------------
  def __init__(self):
#-------------------------------------------------------------------
        movie_preferences.insts = self
        self.PM = self.create_movie_preferences()

#-------------------------------------------------------------------
  def movie_preferences(self):
#-------------------------------------------------------------------
      return self.PM
        
#-------------------------------------------------------------------------
  def create_movie_preferences(self):
#-------------------------------------------------------------------------
    import services
    return services.ParamsManager (
          name='movie_preferences',
          help = 'movies#movies',
          title='Movie Compile',
          gui =['convert_exe','ffmpeg_exe','mencoder_exe','player_exe','show_progress'],
          default = {
                  'convert_command' : '-quality 100',
                  'ffmpeg_command' : '-f mpeg -vcodec mpeg1video -ar 48000 -b 7000000 -ab 192000 -y',
                  'mencoder_command' : '-ovc lavc -lavcopts vcodec=msmpeg4v2:vbitrate=1800',
                  'mencoder_merge_command' : '-ovc copy',
                  'player_command' : '-loop 0',
                  'convert_exe' : 'convert',
                  'ffmpeg_exe' : 'ffmpeg',
                  'mencoder_exe' : 'mencoder',
                  'player_exe' : 'mplayer',
                 'show_progress' : 1 },
          definition = { \
      'convert_exe' : dict(type=str,label='Convert executable(Imagemagick)'),
      'convert_command' : dict(type=str,label='Convert arguments'),
      'ffmpeg_exe' : dict(type=str,label='Ffmpeg executable'),
      'ffmpeg_command' : dict(type=str,label='Ffmpeg arguments'),
      'mencoder_exe' : dict(type=str,label='mencoder executable'),
      'mencoder_command': dict(type=str,label='Mencoder arguments'),
      'mencoder_merge_command': dict(type=str,label='Mencoder merge arguments'),
      'player_exe' : dict(type=str,label='mpeg player executable'),
      'player_command' : dict(type=str,label='mpeg player arguments'),
      'show_progress' : dict(type='bool',label='Show progress',style='checkbox')
         })
