# Using Python Rifs
# import batch
# 
# rifs = ['rif_it', 'rif_format.Rif(640,480)' ] <<-- 2 python rifs 
# batch.render(1, 1, rifs)
# Notes: 
#     If a python rif does NOT have inputs it can be specified by it's module name.
#     If a python rif DOES have inputs it must be specified by module_name.Rif(arg1,arg2, ...)
#     Inputs MUST be separated by commas.
#___________________________________________________________________________________________
# Using compiled C++ RifPlugins
# import batch
#
# rifs = [ ['FULL_PATH/TO/Mesh2Blobby','0.2'],
#          ['./rif_plugins/Format','640, 480'] ] <<-- relative to current Maya project dir
# batch.render(1,1, rifs)
# Notes: 
#     Only the name of the rif need be specified - either '.so' or '.dll' will be added
#     by the BatchWriter class.  
#___________________________________________________________________________________________
# Vanilla rendering - no rifs
# import batch
#
# batch.render(1,1)  <<-- Generate fresh ribs and render immediately.
# batch.render(1,0)  <<-- Or, generate fresh ribs and postpone rendering.
# batch.render(0,1)  <<-- Or, use existing ribs and render immediately.
#
# Malcolm Kesson
# July 26 2018
# Edits: Aug 6 2018
 
import rfm2.render
import maya.mel as mel
import maya.cmds as mc
import os
import re
import sys
import subprocess
from batch_writer import BatchWriter
from batch_rif import BatchRif
  
unsaved_scene_name = 'unknown'
reg_extract_numeric_ext = re.compile(r'(\w+)[._]+(\d+)[._]+rib')
  
def render(gen_ribs, do_render, rifs=None):    
    # Grab the required data  
    proj_path = mc.workspace(q=True, rootDirectory=True)
    scene_name = get_scene_name()
    anim = mc.getAttr('defaultRenderGlobals.animation')
    begin = mc.getAttr('defaultRenderGlobals.startFrame')
    end = mc.getAttr('defaultRenderGlobals.endFrame')
    by = int(mc.getAttr('defaultRenderGlobals.byFrameStep'))
    layer_name = get_render_layer()
    
    # 2. Adjust the frame range when a single frame is to be rendered 
    #    and motion blur is 'ON'.
    if not anim: 
        begin = mc.currentTime(query=True)
        end = mc.currentTime(query=True)
        motion = mc.getAttr('rmanGlobals.motionBlur');
        if motion == 1 or motion == 2:
            end = end + 1
            mc.setAttr("defaultRenderGlobals.endFrame", end)
    begin = int(begin)
    end = int(end)
    by = int(by)
        
    # 3. Generate the rib files
    if gen_ribs:
        rfm2.render.frame('-ribFile')
    
    # 4. Get a listing of all the ribs generated. 
    vt_dir_name = get_version_take_str()
    ribs_dir_path = os.path.join(proj_path,'renderman', 'rib', scene_name, vt_dir_name)    
    ribs = os.listdir(ribs_dir_path)
    
    # Get the names of the renderable cameras
    cams = get_renderable_cameras()
    
    # 5. Store the names of ribs that match the renderable camera(s). This ensures 
    #    the batch render script(s) ignores ribs that were generated by previous renders.
    #    A typical entry in the database dictionarywould be, 
    #    {'perspShape': ['PATH_TO/perspShape.0001.rib','PATH_TO/perspShape.0002.rib']}
    ribs_database = {}
        
    for cam in cams:
        re_cam = re.compile(r'%s' % cam)
        rib_list = []
        next_valid = int(begin)
        for rib in ribs:
            if not rib.endswith('.rib'):
                continue
            if re_cam.search(rib, 0):
                num_ext = get_numeric_ext(rib)
                if not anim:
                    if num_ext == begin or num_ext == end:
                        rib_list.append(os.path.join(ribs_dir_path, rib))
                if anim:
                    if num_ext % next_valid == 0:
                        if(num_ext >= begin and num_ext <= end):
                            rib_list.append(os.path.join(ribs_dir_path, rib))
                        next_valid += by
        ribs_database[cam] = rib_list
    usesCompiledRifPlugins = False
    if rifs != None:
        if len(rifs) > 0:
            if type(rifs[0]) is not list:
                BR = BatchRif(proj_path, ribs_database, rifs)
                BR.applyRifs('ascii')
            else:
                usesCompiledRifPlugins = True
    BW = BatchWriter(proj_path, scene_name, vt_dir_name, ribs_database, begin)
    if usesCompiledRifPlugins:
        batch_paths = BW.makeBatchRenderScripts(rifs)
    else:
        batch_paths = BW.makeBatchRenderScripts()
    
    # Auto executing multiple batchrender scripts is problematic. 
    # Only proceed...
    if len(batch_paths) == 1 and do_render:
        rfm2.render.show_it() # <<-- might be a problem on linux!!!!
        run_batch_script(batch_paths[0])
#_____________________________________________________________________________
  
def get_version_take_str():
    v = int(mc.getAttr('rmanGlobals.version'))
    t = int(mc.getAttr('rmanGlobals.take'))
    return 'v%0*d_t%0*d' % (3, v, 2, t)
#    
def get_renderable_cameras():
    out = []
    cams = mc.ls(type='camera')
    for cam in cams:
        renderable = mc.getAttr('%s.renderable' % cam)
        if renderable:
            out.append(cam)
    return out
#    
def get_render_layer():
    layer_index = mc.getAttr('renderLayerManager.currentRenderLayer')
    all_layers  = mc.listConnections('renderLayerManager')
    return all_layers[layer_index]
    
#    
def get_scene_name():
    name = mc.file(q=True, sceneName=True, shortName=True)
    if len(name) == 0:
        name = unsaved_scene_name
    else:
        name = name[:len(name) - 3]
    # foo_001 stays foo_001 but foo.001 becomes foo
    # This accounts for an "inconsistency" in the way that RfM
    # handles scene names
    #print('name = %s' % name)
    re_patt = re.compile(r'(\w+[_d]*)')
    match = re.search(re_patt, name)
    if match:
        #print('match = %s' % match.group(1))
        return match.group(1)
    return name
#
def get_numeric_ext(rib):
    match = re.search(reg_extract_numeric_ext, rib)
    if match:
        return int(match.group(2))
    return -1
#
def run_batch_script(fullpath):
    if os.name == "posix":
        os.chmod(fullpath, 0777)
        if sys.platform == 'darwin': # MacOSX
            args = ['open', fullpath]
        else:    # linux
            args = ['sh', fullpath]
        subprocess.Popen(args,stdout=subprocess.PIPE)
    else:    # windows
        args = ['start', fullpath]
        subprocess.call(args, shell=True)
#
def call_batch_rif(fullpath):
    args = ['/usr/bin/python', fullpath]
    if os.name == "posix":
        #os.chmod(fullpath, 0777)
        subprocess.Popen(args,stdout=subprocess.PIPE)
    else:    # windows
        subprocess.call(args, shell=True)