# batch_rif.py
# Instanced by batch.render().
# Malcolm Kesson
# Edits: Aug 6 2018
  
import re
import os
import sys
import prman
import time
import inspect
import ast
  
class BatchRif():
    def __init__(self, proj_path, ribs_dict, rifs):
        self.proj_path = proj_path
        self.ribs_dict = ribs_dict
        self.rifs = rifs
        self.logpath = proj_path
        
    def applyRifs(self, format='ascii'):
        # The user may have specified a rif by it's module eg. 'rif_it',
        # but we need the "fully specified" version ie. 'rif_it.Rif()'
        fully_specified_rifs = self.__getRifsFromList(self.rifs)[1:]
        cameras = self.ribs_dict.keys()
        for camera in cameras:
            ribs = self.ribs_dict[camera]
            self.__applyRifsToRibs(fully_specified_rifs, ribs, format)
    #-------------------------------------------------
    # __getRifsFromList [private]
    #-------------------------------------------------
    def __getRifsFromList(self, rifnames):
        out = []
        ri = prman.Ri()
        out.append(ri)
        for name in rifnames:
            cls = self.__getModuleClassArgs(name.strip())
            if cls == None:
                continue
            rifClass = cls[0]
            if len(cls) == 1:
                rifInst = rifClass(ri)
            else:
                rifArgs = cls[1]
                args = ast.literal_eval(rifArgs)
                if isinstance(args, tuple) == False:
                    args = [args]
                rifInst = rifClass(ri, *args )
            out.append(rifInst)
        return out                    
    #-------------------------------------------------
    # __getModuleClassArgs [private]
    #-------------------------------------------------
    # mcStr might be 'rif_it' or 'rif_mesh2curves.Rif( 0.03, [1,0,0] )'
    def __getModuleClassArgs(self, mcStr):
        # parts might be ['rif_it'] or ['rif_mesh2curves', 'Rif( 0.03, [1,0,0] )']
        parts = mcStr.split('.',1)
        module_name = parts[0].strip()
        if len(parts) == 1:
            class_args = 'Rif()'
        else:
            class_args = parts[1]
            
        args_begin = class_args.find('(')
        args_end = class_args.rfind(')')
        class_name = class_args[:args_begin]
        args_str = class_args[args_begin + 1:args_end]
        args_str = args_str.strip()
        try:
            m = __import__(module_name)
        except:
            print'%s' % ('-' * 70)
            print('Error: Cannot import module named "%s".' % module_name)
            print('It either does not exist or it has syntax errors.')
            print'%s' % ('-' * 70)
            return None
        m = getattr(m, class_name)
        out = [m]
        if len(args_str):
            out.append(args_str)
        return out
    #-------------------------------------------------
    # __applyRifsToRibs
    #-------------------------------------------------
    def __applyRifsToRibs(self, rifs, ribs, format):
        if len(rifs) == 0 or len(ribs) == 0:
            return
        # Get the instance of Ri used by any of the Rifs. There can only 
        # be a single instance of the 'ri' variable and it must be "shared" 
        # by the rifs so we pick the first Rif and use it to get an
        # instance of 'm_ri'.
        ri = rifs[0].m_ri
        if format == 'ascii':
            ri.Option("rib", {"string asciistyle": "indented"})
        else:
            ri.Option("rib", {"string format": "binary"})
        prman.RifInit(rifs)
  
        for ribin in ribs:
            parent = os.path.dirname(ribin)
            name = os.path.basename(ribin)
            if name.endswith('.rib') == False:
                continue
            ribout = os.path.join(parent, 'tmp_' + name)
            ri.Begin( ribout.encode('ascii', 'ignore') )
            prman.ParseFile( ribin.encode('ascii', 'ignore') )
            print('Info: BatchRif - filtered "%s"' % name)
            ri.End()
            os.remove(ribin)
            os.rename(ribout,ribin)
          prman.RifInit([]) # will crash without this !!
        msg = 'Applied:\n'
        for rif in rifs:
            name = str(rif.__class__)
            msg += '  %s\n' % name[8:len(name)-2]
        msg += 'to filter:\n'    
        for rib in ribs:
            msg += '  %s\n' % rib
        self.__log('python_rif_log.txt', msg, 'a')
  
    # Utility_____________________________________________    
    def __log(self, logname, logMsg, permission):
        f = open(os.path.join(self.logpath,logname), permission)
        if permission == 'w':
            localtime = time.asctime( time.localtime(time.time()) )
            f.write('Time %s.\n' % localtime)
        f.write(logMsg)
        f.close()