from __future__ import print_function
import os
import os.path
from os.path import abspath
import nuke
import KEnv
import re
from imp import reload
from collections import OrderedDict
# import ftrack_tools -> in getframerange(node)

# martin@keller.io
__version__ = '1.2'

# default interface values
projectDef = 'GEN'
seasonDef = '01'
episodeDef = '101'
listTasks = ['taskOne___', 'taskTwo___']
listDepts = ['departmentOne___', 'departmentTwo___']
seqDef = '001'
shotDef = '010'
major_version = 1
minor_version = 1
user = 'xy'
info = ''
start = 1001
cutIn = 1001
cutOut = 1001
end = 1001
comment = ''
# / default interface values


# debug

# __GLOBALS__
# generic project folder: //hades/p/_projekte/GENFOLDER
GENFOLDER = 'GEN'
INIT_DONE = False
DEBUG = True
UPDATE_TOOLSET = False
WRITENODE_VERSION = 1.0
USE_ENV_PROJECT_ROOT = 1
WRITENODE_LABEL = '[value compression]'


# Plugin / commands
class sceneControl(KellerNukePlugin):

    def configurePlugin(self):
        self.menu = nuke.menu('Nuke')
        m = self.menu.addMenu('SceneControl')
        m.addCommand('SceneControl', 'import sceneControl; sceneControl.createSceneControl()',shortcut='F12')
        m.addCommand('Increment Major', 'import sceneControl; sceneControl.increment_major_version()', tooltip="Increment Major version and save script.", shortcut='alt+shift+s')
        m.addCommand('Increment Minor', 'import sceneControl; sceneControl.increment_minor_version()', tooltip="Increment Minor version and save script.", shortcut='alt+s')
        m.addCommand('Reload Config', 'import sceneControl; sceneControl.kenvDelete()')

        m.addCommand('Helpers/Read/Set Missing Frames Mode', 'import sceneControl; sceneControl.setErrorMode()', tooltip="Sets the Error Mode on selected Read nodes.")
        m.addCommand('Helpers/Read/Set colorspace on Nodes', 'import sceneControl; sceneControl.setOcioRole()', tooltip="Sets the OCIO role on selected Read / Write nodes.")
        m.addCommand('Helpers/Read/Reload Reads', 'import sceneControl; sceneControl.refresh_read_nodes()', tooltip="Reload footage of selected Read / Write nodes.")
        #
        m.addCommand('Helpers/Write/Ignore selected Nodes', 'import sceneControl; sceneControl.setIgnoreFlag(True)')
        m.addCommand('Helpers/Write/Manage selected Nodes','import sceneControl; sceneControl.setIgnoreFlag(False)')
        m.addCommand('Helpers/Write/Set colorspace on Nodes', 'import sceneControl; sceneControl.setOcioRole()', tooltip="Sets the OCIO role on selected Read / Write nodes.")
        m.addCommand('Helpers/Write/Update Write Nodes Tab', 'import sceneControl; sceneControl.updateWriteNodeConfig()', tooltip="Updates Keller Tab and functions of selected write nodes.")

        #internal
        m.addCommand('Debug/Enable Debug Mode', 'import sceneControl; sceneControl.setDebug(True)')
        m.addCommand('Debug/Disable Debug Mode', 'import sceneControl; sceneControl.setDebug(False)')
        m.addCommand('Debug/DeleteKEnv', 'import sceneControl; sceneControl.kenvDelete()')
        m.addCommand('Debug/Internal/ReloadTasks', 'import sceneControl; sceneControl.kenvReloadTasks()', index=10)
        #m.addCommand('Debug/Internal/GetRenderpath', 'import sceneControl; sceneControl.kenvGetRenderpath(task,element)', index=11)
        #m.addCommand('Debug/Internal/GetPreviewOutput', 'import sceneControl; sceneControl.kenvGetPreviewOutput()', index=12)
        m.addCommand('Debug/Internal/WriteNodeSetPath', 'import sceneControl; sceneControl.kenvWriteSetPath(writeNode)', index=13)
        m.addCommand('Debug/Internal/WriteNodeReloadTasks', 'import sceneControl; sceneControl.kenvWriteReloadTasks(writeNode)', index=14)
        m.addCommand('Debug/Internal/KEnvQuery', 'import sceneControl; sceneControl.kenvQuery(query,**kwargs)', index=15)

        # TODO: remove the commands from the menu
        #m.findItem('Draw/ReloadTasks').setVisible(False)
        #m.findItem('Draw/GetRenderpath').setVisible(False)
        #m.findItem('Draw/WriteNodeSetPath').setVisible(False)
        #m.findItem('Draw/WriteNodeReloadTasks').setVisible(False)
        #
        nuke.addOnCreate(onCreateWrite, nodeClass=('Write'))
        nuke.addOnScriptLoad(onScriptLoad)
        nuke.addKnobChanged(onKnobChanged)
        nuke.addOnDestroy(onDestroy)

    def unconfigurePlugin(self):
        self.menu.removeItem('SceneControl')
        self.menu.removeItem('Increment Major')
        self.menu.removeItem('Increment Minor')
        self.menu.removeItem('Reload Config')
        self.menu.removeItem('Helpers/Read/Set Missing Frames Mode')
        self.menu.removeItem('Helpers/Read/Set colorspace on Nodes')
        self.menu.removeItem('Helpers/Read/Reload Reads')
        self.menu.removeItem('Helpers/Write/Ignore selected Nodes')
        self.menu.removeItem('Helpers/Write/Manage selected Nodes')
        self.menu.removeItem('Helpers/Write/Set colorspace on Nodes')
        self.menu.removeItem('Helpers/Write/Update Write Nodes Tab')
        #
        self.menu.removeItem('Debug/Enable Debug Mode')
        self.menu.removeItem('Debug/Disable Debug Mode')
        self.menu.removeItem('Debug/DeleteKEnv')
        self.menu.removeItem('Debug/Internal/ReloadTasks')
        #self.menu.removeItem('Debug/Internal/GetRenderpath')
        #self.menu.removeItem('Debug/Internal/GetPreviewOutput')
        self.menu.removeItem('Debug/Internal/WriteNodeSetPath')
        self.menu.removeItem('Debug/Internal/WriteNodeReloadTasks')
        self.menu.removeItem('Debug/Internal/KEnvQuery')
        #
        nuke.removeOnCreate(onCreateWrite)
        nuke.removeOnScriptLoad(onScriptLoad)
        nuke.removeKnobChanged(onKnobChanged)
        nuke.removeOnDestroy(onDestroy)



# EVENTS

def onScriptLoad():
    sc = getSceneControl()
    if sc is None:
        createSceneControl()
    else:
        # SceneControl in script
        if kenvModuleLoaded():
            print('SceneControl: Info. Script Load. Generating KEnv environment...')
            initSceneControlValues(sc)


def onKnobChanged():
    # sceneControl ready
    global INIT_DONE
    if not INIT_DONE:
        # not ready
        return

    k = nuke.thisKnob()
    refresh = ['project','dept','task','element','sequence','shot','major_version','minor_version','info','user','useEnvProjectRoot']
    task_refresh = ['dept','task']
    exr_compression = ['compression',]
    if k.name() in task_refresh:
        print('SceneControl: Info. Event task_refresh triggered.')
        # Department changed, loading new tasks
        kenvReloadTasks()

    if k.name() in refresh:
        print('SceneControl: Info. Event refresh triggered.')
        # Config changed, loading new tasks
        kenvGetWorkFile()
        pass

    # exr compression on write nodes
    if k.name() in exr_compression:
        # get the node
        n = nuke.thisNode()
        if k.value().startswith('Zip'):
            # % (r * 255, g * 255, b * 255, 1), 16): change r g and b to your liking
            hexColour = int('%02x%02x%02x%02x' % (184, 184, 0, 1), 16)
            n['tile_color'].setValue(hexColour)
        if k.value().startswith('DW'):
            # % (r * 255, g * 255, b * 255, 1), 16): change r g and b to your liking
            hexColour = int('%02x%02x%02x%02x' % (1 * 255, 0.666 * 255, 0.266 * 255, 1), 16)
            n['tile_color'].setValue(hexColour)


def onCreateWrite():
    n = nuke.thisNode()
    createCustomWrite(n)
    return


def onDestroy():
    print('SceneControl: Info. Nice meeting you. Removing Kenv now...')
    try:
        del(nuke.kenv)
    except:
        print('SceneControl: Info. KEnv was already gone.')



# SceneControl
def getSceneControl():
    c = nuke.exists("sceneCtrl")
    if c:
        sc = nuke.toNode('sceneCtrl')
    else:
        print('SceneControl: Error. No SceneControl node found. Creating one for you.')
        import sceneControl
        deselectAll()
        sceneControl.createSceneControl()
        sc = nuke.toNode('sceneCtrl')
    return sc


def createSceneControl():
    # deselect all nodes
    deselectAll()
    # createUI
    print('SceneControl: Info. Creating SceneControl at Nuke root level.')
    #with nuke.root():
    # for calling from within groups
    try:
        nuke.thisParent().begin()
    except:
        pass
    scenecontrol = createSceneControlUI()
    # fill out
    kenvLoaded = kenvModuleLoaded()
    if kenvLoaded is not None:
        initSceneControlValues(scenecontrol)
        pass
    else:
        pass
    sc = nuke.toNode('sceneCtrl')
    # Init done. Callbacks now armed.
    global INIT_DONE
    INIT_DONE = True
    # touch
    sc.knobs()['major_version'].setValue(0)
    sc.knobs()['major_version'].setValue(1)
    try:
        nuke.thisParent().end()
    except:
        pass
    return sc


def createSceneControlUI():
    n = nuke.Node("NoOp")
    n.setName("sceneCtrl")
    n['hide_input'].setValue(True)

    # % (r * 255, g * 255, b * 255, 1), 16): change r g and b to your liking
    hexColour = int('%02x%02x%02x%02x' % (0.2 * 255, 0.478 * 255, 0.647 * 255, 1), 16)
    n['tile_color'].setValue(hexColour)
    n['label'].setValue("_\n__")

    # ###########################
    # ---------------------------
    # tab main
    # ---------------------------
    # ###########################

    k = nuke.Tab_Knob('main', 'Main')
    n.addKnob(k)

    # Scriptname
    #k = nuke.String_Knob("scriptname", "Script")
    #n.addKnob(k)
    #n.knob("scriptname").setValue(scriptname)
    #n.knob("scriptname").setEnabled(False)

    # Project
    k = nuke.String_Knob('project', 'Project')
    k.setTooltip('Project Shortname')
    n.addKnob(k)
    n.knob('project').setValue(projectDef)
    n.knob('project').setFlag(nuke.STARTLINE)

    # Department
    k = nuke.Enumeration_Knob('dept', 'Dept', listDepts)
    k.setTooltip('Department. Changes tasks and servers.')
    n.addKnob(k)
    n.knob('dept').clearFlag(nuke.STARTLINE)

    # Task
    k = nuke.Enumeration_Knob('task', 'Task', listTasks)
    n.addKnob(k)
    n.knob('task').clearFlag(nuke.STARTLINE)

    k = nuke.String_Knob('element', 'Element')
    k.setTooltip('Optional Element.')
    n.addKnob(k)
    n.knob('element').setValue('')
    n.knob('element').clearFlag(nuke.STARTLINE)

    # Update from KEnv
    k = nuke.PyScript_Knob("reloadConfig", "Reload", "sceneControl.kenvDelete()")
    k.setTooltip("Reload project config file.")
    n.addKnob(k)

    # Season
    k = nuke.String_Knob('season', 'Season')
    n.addKnob(k)
    n.knob('season').setValue(seasonDef)
    n.knob('season').setVisible(False)

    # Episode
    k = nuke.String_Knob('episode', 'Episode')
    n.addKnob(k)
    n.knob('episode').setValue(episodeDef)
    n.knob('episode').setVisible(False)

    # _______________________________________________________________
    k = nuke.Text_Knob("divider1", "")
    n.addKnob(k)
    # _______________________________________________________________

    # Sequence
    k = nuke.String_Knob('sequence', 'Seq')
    k.setTooltip(
        "can be a sequence number or gen when doing generic tasks.\n\ncomp_001_010.comp_v01.ms.nk\ncomp_gen.footageIngest_v01.ms.nk")
    n.addKnob(k)
    n.knob('sequence').setValue(seqDef)

    # Shot
    k = nuke.String_Knob('shot', 'Shot')
    k.setTooltip(
        "can be a shot number or gen in a multiShot context.\n\ncomp_001_010.comp_v01.ms.nk\ncomp_001_gen.comp_v01.ms.nk")
    n.addKnob(k)
    n.knob('shot').setValue(shotDef)
    n.knob('shot').clearFlag(nuke.STARTLINE)

    # Major Version
    k = nuke.Int_Knob('major_version', 'Major')
    n.addKnob(k)
    k.setTooltip('Increment Major Version and save script')
    n.knob('major_version').setValue(major_version)
    k = nuke.PyScript_Knob('increment_major_version', '+', 'sceneControl.increment_major_version()')
    n.addKnob(k)

    # Minor Version
    k = nuke.Int_Knob('minor_version', 'Minor')
    n.addKnob(k)
    k.setTooltip('Increment Minor Version and save script')
    n.knob('minor_version').setValue(minor_version)
    n.knob('minor_version').clearFlag(nuke.STARTLINE)
    k = nuke.PyScript_Knob('increment_minor_version', '+', 'sceneControl.increment_minor_version()')
    n.addKnob(k)

    # Save
    k = nuke.PyScript_Knob('save_script', 'Save', 'sceneControl.save_script()')
    k.setTooltip('Save Script with current Major and Minor')
    n.addKnob(k)

    # Overwrite
    k = nuke.Boolean_Knob('overwrite', 'Overwrite')
    k.setTooltip('Automatically overwrite Scriptfiles without asking.')
    n.addKnob(k)
    n.knob('overwrite').setValue(0)
    n.knob('overwrite').setVisible(True)

    # Info / Comment
    k = nuke.String_Knob('info', 'Info')
    k.setTooltip('Additional (mandatory) File Info.')
    n.addKnob(k)
    n.knob('info').setValue(info)

    # User Short
    k = nuke.String_Knob('user', 'User')
    n.addKnob(k)
    k.setTooltip('User Short. Reading Env Variable: USER')
    n.knob('user').setValue(user)
    n.knob('user').clearFlag(nuke.STARTLINE)

    # Divider _______________________________________________________________
    k = nuke.Text_Knob("divider2", "")
    n.addKnob(k)
    # _______________________________________________________________


    # Foldername preview
    k = nuke.String_Knob('folder', 'Folder')
    n.addKnob(k)
    n.knob('folder').setValue('')
    n.knob('folder').setEnabled(False)
    k.setTooltip('Save folder Preview.')

    # Foldername preview
    k = nuke.Boolean_Knob('useEnvProjectRoot', 'Use Env Project Root')
    n.addKnob(k)
    n.knob('useEnvProjectRoot').setValue(USE_ENV_PROJECT_ROOT)
    k.setTooltip('Use env variables for 2d and 3d servers set in the site_config.\nUse these env variables before nuke startup.')
    n.knob('useEnvProjectRoot').clearFlag(nuke.STARTLINE)

    # Filename preview
    k = nuke.String_Knob('file', 'File')
    n.addKnob(k)
    n.knob('file').setValue('')
    n.knob('file').setEnabled(False)
    k.setTooltip('Save file Preview.')

    #  Divider _______________________________________________________________
    k = nuke.Text_Knob("divider3", "")
    n.addKnob(k)
    # _______________________________________________________________

    # FrameStart
    k = nuke.Int_Knob('fStart', 'Start')
    n.addKnob(k)
    k.setTooltip('Startframe')
    n.knob('fStart').setValue(start)

    # FrameCutIn
    k = nuke.Int_Knob('fCutIn', 'CutIn')
    n.addKnob(k)
    k.setTooltip('CutIn')
    n.knob('fCutIn').setValue(cutIn)
    n.knob('fCutIn').clearFlag(nuke.STARTLINE)

    # FrameCutOut
    k = nuke.Int_Knob('fCutOut', 'CutOut')
    n.addKnob(k)
    k.setTooltip('CutOut')
    n.knob('fCutOut').setValue(cutOut)
    n.knob('fCutOut').clearFlag(nuke.STARTLINE)

    # FrameEnd
    k = nuke.Int_Knob('fEnd', 'End')
    n.addKnob(k)
    k.setTooltip('Endframe')
    n.knob('fEnd').setValue(end)
    n.knob('fEnd').clearFlag(nuke.STARTLINE)

    # Button Get Framerange (ftrack)
    k = nuke.PyScript_Knob("get_framerange", "Get Range", "sceneControl.get_framerange(nuke.thisNode())")
    n.addKnob(k)
    n.knob("get_framerange").setTooltip("Get Framerange from FTrack.\nPlease check you firewall rules and and allow ftrack ip 104.155.3.128 on port 443")

    # Button Set Framerange
    k = nuke.PyScript_Knob("set_framerange", "Set Range", "sceneControl.set_framerange(nuke.thisNode())")
    n.addKnob(k)
    n.knob("set_framerange").setTooltip("Set Framerange from SceneControl Interface")
    n.knob("set_framerange").clearFlag(nuke.STARTLINE)

    # Comment
    k = nuke.Multiline_Eval_String_Knob("comment", "Comment")
    n.addKnob(k)
    n.knob("comment").setValue(comment)

    # Update / publish
    if UPDATE_TOOLSET:
        # Button update Layer
        k = nuke.PyScript_Knob("update_layer", "Update Layer", "sceneControl.update_layer()")
        n.addKnob(k)
        n.knob("update_layer").setFlag(nuke.STARTLINE)
    
        # Button connect all Layers
        k = nuke.PyScript_Knob("autoconnect_layers", "Connect Layers", "sceneControl.autoconnect_layers(nuke.thisNode())")
        n.addKnob(k)
        n.knob("autoconnect_layers").setFlag(nuke.STARTLINE)
    
        # Button remove all layers
        k = nuke.PyScript_Knob("remove_all_layers", "Remove All Layers", "sceneControl.remove_all_layers(nuke.thisNode())")
        n.addKnob(k)
        n.knob("remove_all_layers").setTooltip("Removes all Layers in SceneControl.")
    
        # Button delete all reads
        k = nuke.PyScript_Knob("remove_scnctrl_reads", "Delete All Reads",
                               "sceneControl.remove_scnctrl_reads(nuke.thisNode())")
        n.addKnob(k)
        n.knob("remove_scnctrl_reads").setTooltip("Deletes all reads created by SceneControl.")
        n.knob("remove_scnctrl_reads").setFlag(nuke.STARTLINE)
        n.knob("remove_scnctrl_reads").setVisible(False)
    
        # Button publish Shot
        k = nuke.PyScript_Knob("publish_shot", "Publish", "sceneControl.publish_shot()")
        n.addKnob(k)
        n.knob("publish_shot").setFlag(nuke.STARTLINE)

    # invisible helpers
    # helper
    k = nuke.Int_Knob("layerNum", "Slots")
    n.addKnob(k)
    n.knob("layerNum").setValue(0)
    n.knob("layerNum").setVisible(False)

    # used for resolving expressions
    k = nuke.EvalString_Knob("eval_helper", "eval_helper")
    n.addKnob(k)
    n.knob("eval_helper").setValue("")
    n.knob("eval_helper").setVisible(False)
    # for debug disable above

    k = nuke.Boolean_Knob("stereoToggle", "Stereo Toggle")
    n.addKnob(k)
    n.knob("stereoToggle").setValue(0)
    n.knob("stereoToggle").setVisible(False)

    # used for resolving expressions
    k = nuke.EvalString_Knob("precomp_output", "Precomp Output")
    n.addKnob(k)
    n.knob("precomp_output").setValue("")
    n.knob("precomp_output").setVisible(False)
    # for debug disable above

    k = nuke.Boolean_Knob("debug", "Debug")
    n.addKnob(k)
    n.knob("debug").setValue(1)
    n.knob("debug").setVisible(False)

    # end helper

    # return sceneControl Object
    sc = nuke.toNode(n.name())
    return sc


def initSceneControlValues(sceneControl):
    if sceneControl is not None:
        k = sceneControl.knobs()
        # debug
        k['debug'].setValue(DEBUG)
        proj = checkEnvEntry('PROJECT')
        if proj is None:
            proj = GENFOLDER
        kenvReloadTasks()

        proj = checkEnvEntry('PROJECT')
        k['project'].setValue(proj)

        try:
            k['user'].setValue(checkEnvEntry('USER'))
        except:
            print('SceneControl: Warning. Please enter your shortname.')



# KEnv functions
def kenvCheck():
    try:
        nuke.kenv
    except:
        kenvCreate()
        print('SceneControl: Info. Creating kenv.')


def kenvModuleLoaded():
    from imp import reload
    try:
        import KEnv
        reload(KEnv)
    except:
        print('SceneControl: Error. No KEnv module found')
        return False
    return KEnv


def kenvCreate():
    try:
        project = os.environ['PROJECT']
    except:
        project = GENFOLDER

    # KEnv
    env = KEnv.create(PROJECT=project, APP_ID='nuke')
    # save KEnv to Nuke to access if by other nodes / tools
    nuke.kenv = env


def kenvDelete():
    try:
        del(nuke.kenv)
        print('SceneControl: Info. Deleting nuke.kenv.')
    except:
        print('SceneControl: Info. nuke.kenv not found.')


def kenvReloadTasks():
    sceneControl = getSceneControl()
    k = sceneControl.knobs()
    kenvCheck()
    # KEnv query
    dept = nuke.kenv.get('DEPARTMENTS')
    k['dept'].setValues(dept)
    tasks = nuke.kenv.get('TASKS', DEPT=k['dept'].value(), APP_ID='nuke')
    k['task'].setValues(tasks)
    return tasks


def kenvGetWriteOutput(writeTask, writeElement, writeInfo, ext):
    sceneControl = getSceneControl()
    k = sceneControl.knobs()
    kenvCheck()
    # debug
    if k["debug"].getValue():
        print(('SceneControl: Debug. WriteTask: %s, WriteElement: %s, WriteInfo: %s') % (writeTask, writeElement, writeInfo))

    # useEnvProjectRoot
    useEnv = k['useEnvProjectRoot'].value()

    if writeElement == '':
        writeElement = None
    if writeInfo == '':
        writeInfo = None
    if writeTask.lower() == 'scripttask':
        # get task from sceneControl and not from the write node
        # sceneControl task
        task = k["task"].value()
        writeTask = task
        # KEnv query
        renderpath = kenvQuery('RENDER_2D_FILE', element=writeElement, task=writeTask, minor_version=None, info=writeInfo, ext=ext, USE_ENV_PROJECTROOT=useEnv)
    else:
        # KEnv query
        renderpath = kenvQuery('PRECOMP_FILE', element=writeElement, task=writeTask, minor_version=None, info=writeInfo, ext=ext, USE_ENV_PROJECTROOT=useEnv)

    return renderpath


def kenvGetWorkFile():
    sceneControl = getSceneControl()
    k = sceneControl.knobs()
    kenvCheck()

    info = k['info'].value()
    if info == '':
        info = None

    element = k['element'].value()
    if element == '':
        element = None

    # KEnv query
    script = kenvQuery('WORK_FILE', element=element, info=info)
    dir = kenvQuery('WORK_DIR', element=element, info=info)
    try:
        k['folder'].setValue(dir+'/')
    except:
        print(('SceneControl: Error. Error setting directory: %s') % dir)
    try:
        k['file'].setValue(script.split('/')[-1])
    except:
        print(('SceneControl: Error. Error setting file: %s') % script)



# main Kenv Query
def kenvQuery(query , **kwargs):
    # sceneControl
    sceneControl = getSceneControl()
    k = sceneControl.knobs()
    kenvCheck()

    # sceneControl values:
    debug = k['debug'].getValue()
    project = k['project'].value()
    dept = k['dept'].value()
    sequence = k['sequence'].value()
    shot = k['shot'].value()
    element = k['element'].value()
    task = k['task'].value()
    major_version = int(k['major_version'].value())
    minor_version = int(k['minor_version'].value())
    user = k['user'].value()
    info = k['info'].value()
    ext = 'exr'
    app_id = 'nuke'
    # useEnvProjectRoot
    useEnv = k['useEnvProjectRoot'].value()

    # read out kwargs
    for k,v in kwargs.items():
        if k == 'project':
            project = v
        if k == 'dept':
            dept = v
        if k == 'sequence':
            sequence = v
        if k == 'shot':
            shot = v
        if k == 'element':
            element = v
        if k == 'task':
            task = v
        if k == 'major_version':
            major_version = v
        if k == 'minor_version':
            minor_version = v
        if k == 'user':
            user = v
        if k == 'info':
            info = v
        if k == 'ext':
            ext = v
        if k == 'app_id':
            app_id = v
        if k == 'useEnv':
            useEnv = v

    # info
    infostr=''
    if info == '':
        info = None
        infostr = 'None'

    # element
    elementstr=''
    if element == '':
        element = None
        elementstr = 'None'


    # debug
    if debug:
        print('SceneControl: Debug kenv query:')
        print('PROJECT: ' + project)
        print('SHOT: ' + shot)
        print('SEQUENCE: ' + sequence)
        print('DEPT: ' + dept)
        print('TASK: ' + task)
        print('MAJOR_VERSION: ' + str(int(major_version)))
        if minor_version is None:
            print('MINOR_VERSION: ' + 'None')
        else:
            print('MINOR_VERSION: ' + str(int(minor_version)))
        print('ELEMENT: ' + elementstr)
        print('INFO: ' + infostr)
        print('USER: ' + user)
        print('EXT: ' + ext)
        print('APP_ID: ' + app_id)
    # KEnv
    if minor_version is None:
        result = nuke.kenv.get(query, PROJECT=project, DEPT=dept, SEQUENCE=sequence, SHOT=shot, ELEMENT=element, TASK=task, MAJOR_VERSION=int(major_version), INFO=info, EXT=ext, USER=user, APP_ID=app_id, USE_ENV_PROJECTROOT=useEnv)
    else:
        result = nuke.kenv.get(query, PROJECT=project, DEPT=dept, SEQUENCE=sequence, SHOT=shot, ELEMENT=element, TASK=task, MAJOR_VERSION=int(major_version), MINOR_VERSION=int(minor_version), INFO=info, EXT=ext, USER=user, APP_ID=app_id, USE_ENV_PROJECTROOT=useEnv)
    if debug:
        print('SceneControl: Debug kenv query: ' + result)
    return result


# called from write nodes
def kenvWriteSetPath(n):
    print('Our_Write: Info. Setting output file path')
    sceneControl = getSceneControl()
    k = sceneControl.knobs()
    kenvCheck()
    #debug
    if k["debug"].getValue():
        print(('SceneControl: Debug. Setting path on: %s') % n.name())
    subtask = n.knob('subtask').value()
    if subtask is None:
        subtask = ''
    element = n.knob('element').value()
    if element == '':
        element = None
    info = n.knob('info').value()
    if info == '':
        info = None

    ext = n.knob('extension').value()
    # dummy
    file = ''
    file = kenvGetWriteOutput(subtask, element, info, ext)
    if file != '':
        try:
            n.knob('file').setValue(file)
        except:
            pass
    return


def kenvWriteReloadSubTasks(n):
    sceneControl = getSceneControl()
    kenvCheck()

    # KEnv query
    tasks = nuke.kenv.get('SUBTASKS_2D')
    try:
        n.knob('subtask').setValues(tasks)
    except:
        pass
    return


# helpers
# todo: set selected Reads to framerange

def setIgnoreFlag(state):
    s = nuke.selectedNodes()
    if len(s) == 0:
        nuke.message("Please select some Nodes first.")
        return

    for n in s:
        if n.Class() == 'Write' or n.Class() == 'DeepWrite':
            try:
                n.knobs()['ignore'].setValue(state)
            except:
                print(('SceneControl: Warning. Cannot find ignore flag on: %s') % n.name())


def setErrorMode():
    n = nuke.selectedNodes()
    if len(n) == 0:
        nuke.message("Please select some Nodes first.")
        return
    w = nuke.nodes.Read()
    onerror = w['on_error'].values()
    # spaces in the names
    quoted = ['{%s}' % c for c in onerror]
    p = nuke.Panel('Missing Frames')
    p.addEnumerationPulldown('Missing Frames', ' '.join(quoted))
    p.show()
    ret = p.value('Missing Frames')

    sel = nuke.selectedNodes()
    for s in sel:
        if s.Class() == "Read" or s.Class() == "DeepRead":
            s.knobs()['on_error'].setValue(ret)


def setOcioRole():
    n = nuke.selectedNodes()
    if len(n) == 0:
        nuke.message("No node(s) selected.")

    # create temporary write node
    w = nuke.nodes.Write(file_type='exr')
    colorspace = w['colorspace'].values()
    # delete write node
    nuke.delete(w)

    choice = []
    for s in colorspace:
        if not s.startswith('Colorspaces/'):
            choice.append(s.split('\t')[0])
        else:
            choice.append(s)

    # spaces in the names
    quoted = ['{%s}' % c for c in choice]

    # TODO: create cascading Enumeration pulldown. Not possible with panel?
    p = nuke.Panel('Colorspace')
    p.addEnumerationPulldown('Colorspace', ' '.join(quoted))
    p.show()
    ret = p.value('Colorspace')
    if ret is not None:
        for s in n:
            if s.Class() == "Read" or s.Class() == "Write":
                s.knobs()['colorspace'].setValue(ret)


def setDebug(state):
    sceneControl = getSceneControl()
    if sceneControl is None:
        print('SceneControl: Error. No SceneControl node found. Exiting.')
        return
    k = sceneControl.knobs()
    k['debug'].setValue(state)
    
    if state is False:
        print('SceneControl: Info. Set SceneControl Debug Mode to: False')
    else:
        print('SceneControl: Info. Set SceneControl Debug Mode to: True')


def deselectAll():
    for each in nuke.allNodes():
        each.knob("selected").setValue(False)
    return


def getFilename():
    return nuke.Root()["name"].getValue()


def checkEnvEntry(value):
    try:
        val = os.environ[value]
    except:
        print(('SceneControl: Info. Env variable %s not set.') %value)
        return None
    return val


def find_node_by_type(nodename, nodeclass):
    nodes = nuke.allNodes()
    for n in nodes:
        if n.Class() == nodeclass:
            if n.knob("label").getValue().lower() == nodename.lower():
                return n
    return None


def updateWriteNodePaths():
    nodes = nuke.allNodes()
    for n in nodes:
        if n.Class() == 'Write' or n.Class() == 'DeepWrite':
            try:
                if n.knobs()['ignore'].value() == True:
                    print('SceneControl: Info. Found ignore flag on %s. Skipping.' % n.name())
                else:
                    try:
                        print('SceneControl: Info. Setting output file on %s.' % n.name())
                        nuke.toNode(n.name()).knobs()['set'].execute()
                    except:
                        print('SceneControl: Error. Error setting output file on %s.' % n.name())
            except:
                print ('SceneControl: Info. Skipping Node %s. Old Write Node. Consider creating a new one.' % n.name())


def updateWriteNodeConfig():
    import sceneControl

    # 'task' for legacy write nodes
    customKnobs = (
    'extension', 'ext', 'ver', 'explore', 'divider3', 'playinrv', 'pushtorv', 'pushtorvappend', 'divider2', 'ignore', 'divider1', 'set',
    'info', 'element', 'subtask', 'task', 'w_reload', 'keller')

    # save these for reapplying later on
    saveKnobs = ('info', 'element', 'subtask', 'ignore')

    # get all reads
    nodes = [node for node in nuke.selectedNodes() if node.Class() == 'Write']

    for n in nodes:
        knobs = n.knobs()
        info = ''
        element = ''
        subtask = ''
        for c in customKnobs:
            # save config
            try:
                info = knobs['info'].value()
                element = knobs['element'].value()
                subtask = knobs['subtask'].value()
                ignore = knobs['ignore'].value()
            except:
                pass
            try:
                n.removeKnob(knobs[c])
            except:
                pass

        # create new Keller tab
        sceneControl.createCustomWrite(n)

        # refresh subtasks
        sceneControl.kenvWriteReloadSubTasks(n)

        # restore old values
        try:
            n.knobs()['info'].setValue(info)
        except:
            print('SceneControl: Error. Node %s. Cannot set value on knob: %s') % (n.name(), info)
        try:
            n.knobs()['element'].setValue(element)
        except:
            print('SceneControl: Error. Node %s. Cannot set value on knob: %s') % (n.name(), element)
        try:
            n.knobs()['subtask'].setValue(subtask)
        except:
            print('SceneControl: Error. Node %s. Cannot set value on knob: %s') % (n.name(), subtask)

    return


def refresh_read_nodes():
    nodes = nuke.selectedNodes()
    if len(nodes)==0:
        nodes = nuke.allNodes()
        print('SceneControl: Info. No node selected. Reloading all reads.')
    for n in nodes:
        if n.Class() == 'Read' or n.Class() == 'DeepRead':
            try:
                nuke.toNode(n.name()).knobs()['reload'].execute()
                print('SceneControl: Info. Reloading %s.' % n.name())
            except:
                pass


def autoconnect_layers(node):
    n = nuke.thisNode()
    nu = n["layerNum"].getValue()
    num = int(nu)

    for i in range(1, num + 1):
        create_deepreadnode(i, autoconnect=True)
        create_readnode(i, autoconnect=True)
    return



# write nodes
def createCustomWrite(n):
    # Task
    '''
    taskList = ("comp",)
    try:
        taskList = sceneControl.kenvReloadTasks()
    except:
        print("Our_Write: Error. Cannot call sceneControl.kenvReloadTasks()")
        pass
    '''
    try:
        tab = n.knobs()['keller'].value()
    except:
        tab = None
    if tab is None:
        pass
    else:
        # already existing
        return
    # create tab
    print("Our_Write: Info. Creating KellerTab")
    k = nuke.Tab_Knob('keller', 'Keller')
    n.addKnob(k)

    exts = n.knobs()['file_type'].values()
    k = nuke.Enumeration_Knob('extension', 'Extension', exts)
    n.addKnob(k)
    n.knob('extension').setValue('exr')
    n.knob('extension').setFlag(nuke.STARTLINE)

    # task
    subTaskList = ('--------------->',)
    k = nuke.Enumeration_Knob('subtask', 'Subtask', subTaskList)
    k.setTooltip('Defaults to the Task selected in sceneControl, ignoring Element and Info.\nAll other subtasks are pre-renders and get rendered into the precomp (=prerender) directory.')
    n.addKnob(k)
    n.knob('subtask').setFlag(nuke.STARTLINE)

    # Reload
    k = nuke.PyScript_Knob('w_reload', 'Reload', 'sceneControl.kenvWriteReloadSubTasks(nuke.thisNode())')
    k.setTooltip('Reloads the subtasks. If the project_config.py was changed you need to re-init the config with the SceneControl button \'reload\'.')
    k.setTooltip('Reload Tasks')
    n.addKnob(k)

    # element
    k = nuke.String_Knob('element', 'Element')
    k.setTooltip('Optional Specifier. For example [BG]_denoise. [FG]_denoise.')
    n.addKnob(k)
    n.knob('element').setValue('')

    # info
    k = nuke.String_Knob('info', 'Info')
    k.setTooltip('Optional Info before Framenumber.\nPRO_comp3d_001_010.comp3d_v008.[acescg].%04d.exr')
    n.addKnob(k)
    n.knob('info').setValue('')

    # set
    k = nuke.PyScript_Knob('set', 'Set', 'sceneControl.kenvWriteSetPath(nuke.thisNode())')
    k.setTooltip('Set Output Path of this node')
    n.addKnob(k)
    n.knob('set').setFlag(nuke.STARTLINE)


    # _______________________________________________________________
    k = nuke.Text_Knob("divider1", "")
    n.addKnob(k)
    # _______________________________________________________________

    # ignore
    k = nuke.Boolean_Knob("ignore", "ignore in sceneControl")
    n.addKnob(k)
    n.knob("ignore").setValue(0)

    # _______________________________________________________________
    k = nuke.Text_Knob("divider2", "")
    n.addKnob(k)
    # _______________________________________________________________

    # play in new rv
    k = nuke.PyScript_Knob("playinrv", "Play in RV", "playInRV.playInRV(nuke.thisNode().knob('file').getValue(),0)")
    n.addKnob(k)
    n.knob("playinrv").setTooltip("Opens new instance of RV")
    n.knob("playinrv").setFlag(nuke.STARTLINE)

    # push to rv
    k = nuke.PyScript_Knob("pushtorv", "Push to RV", "playInRV.playInRV(nuke.thisNode().knob('file').getValue(),1)")
    n.addKnob(k)
    n.knob("pushtorv").setTooltip("Push to tagged RV. Will open RV and uses this instance to directly push sequences.")

    # push to rv / append
    k = nuke.PyScript_Knob("pushtorvappend", "Push to RV (append)", "playInRV.playInRV(nuke.thisNode().knob('file').getValue(),2)")
    n.addKnob(k)
    n.knob("pushtorvappend").setTooltip("Push to RV and append to existing sources")
    n.knob("pushtorvappend").clearFlag(nuke.STARTLINE)

    # _______________________________________________________________
    k = nuke.Text_Knob("divider3", "")
    n.addKnob(k)
    # _______________________________________________________________

    # explore
    k = nuke.PyScript_Knob("explore", "Explore", "exploreThis.exploreThis()")
    n.addKnob(k)
    n.knob("explore").setTooltip("Open Folder")

    # version
    k = nuke.Array_Knob("ver", "Version")
    n.addKnob(k)
    n.knob("ver").setValue(WRITENODE_VERSION)
    n.knob("ver").setVisible(False)

    # label
    if n.knob("label").value() != "":
        n.knob("label").setValue('\n' + WRITENODE_LABEL)
    else:
        n.knob("label").setValue(WRITENODE_LABEL)



# saving
def save_script():
    sceneControl = getSceneControl()
    k = sceneControl.knobs()
    # overwrite existing scene without notice?
    owrite = k['overwrite'].value()

    # info
    info = k['info'].value()
    if info == '':
        info = None

    # element
    element = k['element'].value()
    if element == '':
        element = None

    # useEnvProjectRoot
    useEnv = k['useEnvProjectRoot'].value()

    # KEnv Query
    script = kenvQuery('WORK_2D_SCENE_FILE',useEnv = False)
    # get work_2d_scene_file
    print(('SceneControl: Info. Checking script file: %s') %script)

    # old Scriptname
    oldname = nuke.Root()["name"].value()
    # Nuke set filename
    nuke.Root()["name"].setValue(script)

    # check if folder exists
    folder = os.path.dirname(script)
    if not os.path.exists(folder):
        os.makedirs(folder)
    else:
        # folder existing. Moving on
        pass

    # check if file exists
    if os.path.isfile(script):
        if owrite:
            # good to go: change write nodes first
            updateWriteNodePaths()
            nuke.scriptSave()
        else:
            s = "SceneControl. Overwrite Nuke Script? %s" % script
            overwrite = nuke.ask(s)
            if overwrite:
                # good to go: change write nodes first
                updateWriteNodePaths()
                nuke.scriptSave()
            else:
                nuke.Root()["name"].setValue(oldname)
    else:
        # good to go: change write nodes first
        updateWriteNodePaths()
        nuke.scriptSave()


def increment_major_version():
    sceneControl = getSceneControl()
    k = sceneControl.knobs()
    major = k["major_version"].getValue()
    major = int(major) + 1
    k["major_version"].setValue(major)
    k["minor_version"].setValue(1)
    # call save script
    save_script()
    return


def increment_minor_version():
    sceneControl = getSceneControl()
    k = sceneControl.knobs()
    minor = k["minor_version"].getValue()
    minor = int(minor) + 1
    k["minor_version"].setValue(minor)
    # call save script
    save_script()
    return




# framerange
def get_framerange_OLD(node):
    '''
    # TODO: ftrack query or KEnv query
    # Connect to FTrack
    frameStart = 1001
    frameCutIn = 1010
    frameCutOut = 1100
    frameEnd = 1109

    n = nuke.thisNode()
    k = n.knobs()
    sequence = k["sequence"].getText()
    shot = k["shot"].getText()
    user = k["shortname"].getText()
    if user == "":
        nuke.message("Please fill out your shortname in the User field. E.g. \"ms\"")
        return
    try:
        conn = FTrackConnector(shortname=user)
        project = conn.getProject("drr")
        shot = project.getShot(sequence, shot)
        frameStart = shot.get("custom_attributes").get("fstart")
        frameCutIn = shot.get("custom_attributes").get("fcutin")
        frameCutOut = shot.get("custom_attributes").get("fcutout")
        frameEnd = shot.get("custom_attributes").get("fend")
    except Exception as e:
        nuke.message(
            "No Connection could be established. Check Firewall and enable 104.155.61.233 Port 443\n\n" + str(e))

    node.knob("fStart").setValue(int(frameStart))
    node.knob("fCutIn").setValue(int(frameCutIn))
    node.knob("fCutOut").setValue(int(frameCutOut))
    node.knob("fEnd").setValue(int(frameEnd))
    return None
    '''


def get_framerange(node):
    import ftrack_tools

    sceneControl = getSceneControl()
    k = sceneControl.knobs()
    proj = k['project'].value()
    seq = k['sequence'].value()
    shot = k['shot'].value()

    # ftrack query
    p = ftrack_tools.get_project(proj)
    if proj == 'HOTZ':
        proj = 'HOT'
    shotcode = proj + '_' + seq + '_' + shot

    if k["debug"].getValue():
        print(('SceneControl: Debug. Project: %s') %proj)
        print(('SceneControl: Debug. Sequence: %s') % seq)
        print(('SceneControl: Debug. Shot: %s') % shot)
        print(('SceneControl: Debug. FTrack Shotcode: %s') %shotcode)

    s = p.get_shot(shotcode)
    st,en = s.get_framerange()
    ha = s.get_handles()
    k['fStart'].setValue(int(st))
    k['fCutIn'].setValue(int(st) + int(ha))
    k['fEnd'].setValue(int(en))
    k['fCutOut'].setValue(int(en) - int(ha))
    return None


def set_framerange(node):
    frameCutIn = node.knob("fCutIn").getValue()
    frameCutOut = node.knob("fCutOut").getValue()

    nuke.root()["first_frame"].setValue(frameCutIn)
    nuke.root()["last_frame"].setValue(frameCutOut)
    return None


def remove_expressions():
    #todo: create **kwargs for replacement
    n = nuke.thisNode()
    k = n.knobs()
    nodes = nuke.allNodes()
    for no in nodes:
        if no.Class() == "Read" or no.Class() == "DeepRead" or no.Class() == "Write":
            s = no.knob("file").getValue()
            k["eval_helper"].setValue(s)
            res = k["eval_helper"].evaluate()
            res = res.replace("\\", "/")
            res = res.replace("//hades/p/_projekte/DRR", "$env(JOB)")
            s = no.knob("file").setValue(res)
    return None


def remove_expression_links():
    nodes = nuke.allNodes()
    for n in nodes:
        if n.Class() == "Read" or n.Class() == "DeepRead" or n.Class() == "Write":
            for k in n.knobs():
                n.knobs()[k].clearAnimated()
    return None


def replace_frame_with_padded_frames():
    nodes = nuke.allNodes()
    for n in nodes:
        if n.Class() == "Read" or n.Class() == "DeepRead":
            file = n.knob("file").getValue()
            sub = file.split(".")[-2]
            file = file.replace(sub, "####")
            n.knob("file").setValue(file)
    return None



# layer
def get_layer_versions():
    # TODO: filter out temporary files: tmp, temp, ifd, ass
    sceneControl = getSceneControl()
    k = sceneControl.knobs()

    # get renderpath to look for layers
    path = kenvQuery('RENDER_3D_DIR')

    t = k["task"].value()
    task = '_' + t

    folder = os.path.dirname(str(path))
    if not os.path.exists(folder):
        msg = "SceneControl. Error.\nNo renders found in:\n%s\nIs the task %s correct?" % (path, t)
        nuke.message(msg)
        return
    # find top folders in renderdir of current shot in current department
    folders = [name for name in os.listdir(path) if os.path.isdir(os.path.join(path, name))]
    # debug
    if k["debug"].getValue():
        print(('SceneControl: Debug. Folders found: %s') %folders)
    # dict holding info about layer and their version.
    layer_dict = {}

    for f in folders:
        print(('SceneControl: Info: Adding folder: %s') %f)

        # extract layer name
        lay = f.split('.')[1]
        pattern = re.compile('_[vV]\d+')
        layer = re.sub(pattern, "", lay)
        layer = layer.replace(task, '')
        if k["debug"].getValue():
            print(('SceneControl: Debug. Layer: %s') % layer)

        # extract version string
        pattern2 = re.compile('[vV]\d+')
        ver = pattern2.findall(f)
        version = ver[-1].replace('v', '').replace('V', '')
        version = int(version)
        if k["debug"].getValue():
            print(('SceneControl: Debug. Version: %s') % version)

        # if layer is already loaded
        if layer in layer_dict:
            # check if version in dict is smaller than found version
            if layer_dict[layer] < version:
                layer_dict[layer] = version
            else:
                pass


        else:
            layer_dict[layer] = version
    if k["debug"].getValue():
        print(('SceneControl: Debug. get_layer_version()) Layerdict: %s') % layer_dict)
    return layer_dict


def get_layer_versions_OLD():
    sceneControl = getSceneControl()
    k = sceneControl.knobs()
    # renderpath = '//hades/p/_projekte/HOTZ/500_renders/Shots/001/010'
    # path = kenvGetRenderPath()
    path = kenvQuery('RENDER_3D_DIR')
    task = k["task"].value()
    folder = os.path.dirname(str(path))
    if not os.path.exists(folder):
        msg = "SceneControl. Error.\nNo renders found in:\n%s\nIs the Task %s correct?" % (path, task)
        nuke.message(msg)
        return
    # find top folders in renderdir of current shot in current department
    folders = [name for name in os.listdir(path) if os.path.isdir(os.path.join(path, name))]
    # debug
    if k["debug"].getValue():
        print(('SceneControl: Debug. Folders found: %s') %folders)
    # dict holding info about layer and their version. BEN:3, SOR:4, ENV:1
    layer_dict = {}

    for f in folders:
        print(('SceneControl: Info: Adding folder: %s') %f)
        # TODO: also add layers with variants. Eg. DRR Layer example: HOT_shots_001_010.beauty_light_v001/HOT_shots_001_010.beauty_light_v001.1023.exr

        try:
            layer = f.split('.')[1].split('_')[0]
        except:
            print(('SceneControl: Error. Layer %s is not conform in naming. Skipping.') %f)
            break
        version = int(f.split('_')[-1].replace('v', ''))
        if layer in layer_dict:
            # check if version in dict is smaller than found version
            if layer_dict[layer] < version:
                layer_dict[layer] = version
            else:
                pass
        else:
            layer_dict[layer] = version
    if k["debug"].getValue():
        print(('SceneControl: Debug. get_layer_version()) Layerdict: %s') % layer_dict)
    return layer_dict


def update_layer():
    n = nuke.thisNode()
    # get newest files on disk
    layer_dict = get_layer_versions()
    if bool(layer_dict) is True:
        layer_dict_new_entries = OrderedDict(sorted(layer_dict.items(), key=lambda t: t[0]))
        nu = n['layerNum'].getValue()
        num = int(nu)

        # get new entries
        for layer, version in layer_dict.items():
            if num < 1:
                c = 0
            else:
                c = num
            for i in range(1, num + 1):
                if n.knob("layer_name_" + str(i)) is not None and n.knob("layer_name_" + str(i)).getValue() == layer:
                    # layer already in list. Just update version
                    n.knob("layer_version_" + str(i)).setValue(version)
                    del layer_dict_new_entries[layer]
                    break

        # new entries
        if len(layer_dict_new_entries) > 0:

            c += 1
            for layer, version in layer_dict_new_entries.items():
                k = nuke.String_Knob("layer_name_" + str(c), str(c))
                n.addKnob(k)
                n.knob("layer_name_" + str(c)).setValue(layer)

                # Version
                k = nuke.Int_Knob("layer_version_" + str(c), "version")
                n.addKnob(k)
                n.knob("layer_version_" + str(c)).clearFlag(nuke.STARTLINE)
                n.knob("layer_version_" + str(c)).setValue(version)

                # Button Read
                func = "sceneControl.create_readnode(" + str(c) + ")"
                name = "create_readnode_" + str(c)
                k = nuke.PyScript_Knob(name, "Read", func)
                n.addKnob(k)

                # Button Deep Read
                func = "sceneControl.create_deepreadnode(" + str(c) + ")"
                name = "create_deepreadnode_" + str(c)
                k = nuke.PyScript_Knob(name, "Deep", func)
                n.addKnob(k)

                # Button Crypto
                #func = "sceneControl.create_readnode(" + str(c) + ")"
                #name = "create_readnode" + str(c)
                #k = nuke.PyScript_Knob(name, "Crypto", func)
                #n.addKnob(k)

                # Include in publish
                k = nuke.Boolean_Knob("include_in_publish_" + str(c), "Publish")
                n.addKnob(k)
                n.knob("include_in_publish_" + str(c)).clearFlag(nuke.STARTLINE)
                n.knob("include_in_publish_" + str(c)).setValue(1)
                n.knob("include_in_publish_" + str(c)).setTooltip("Include this layer in publish.")

                num = num + 1
                c = c + 1
                n.knob("layerNum").setValue(c - 1)
        layer_dict = None

        return
    else:
        # dict is empty
        return


def remove_layer(c):
    n = nuke.thisNode()
    # remove entire line
    k = "layer_name_" + str(c)
    n.removeKnob(n.knobs()[k])
    k = "layer_version_" + str(c)
    n.removeKnob(n.knobs()[k])
    k = "create_readnode_" + str(c)
    n.removeKnob(n.knobs()[k])
    k = "create_deepreadnode_" + str(c)
    n.removeKnob(n.knobs()[k])
    k = "include_in_publish_" + str(c)
    n.removeKnob(n.knobs()[k])

    # adjust number of layers
    nu = n["layerNum"].getValue()
    nu = nu - 1
    n.knob("layerNum").setValue(int(nu))
    if n.knob("layerNum").getValue() < 0:
        n.knob("layerNum").setValue(0)
    return


def remove_all_layers(node):
    n = nuke.thisNode()
    nu = n["layerNum"].getValue()
    num = int(nu)
    for i in range(num, 0, -1):
        remove_layer(i)
    return



# publish
def publish_shot():
    n = nuke.thisNode()
    k = n.knobs()

    print ("SceneControl: Checking Versions...")
    maximum = return_highest_layer_version()
    major = k["major_version"].getValue()
    if major < maximum:
        if nuke.ask(
                'SceneControl: Layer found with higher version than the Major file version. Continue with publish?'):
            pass
        else:
            "SceneControl: Terminating Publish"
            return
    print ("SceneControl: Publishing Shot")

    # sequence
    sequence = k["sequence"].getText()
    # shot
    shot = k["shot"].getText()
    # cutIn and cutOut
    frameCutIn = n.knob("fCutIn").getValue()
    frameCutOut = n.knob("fCutOut").getValue()
    # precompCutIn and precompCutOut
    precompframeCutIn = n.knob("pCutIn").getValue()
    precompframeCutOut = n.knob("pCutOut").getValue()
    # eye
    eye = n.knob("eye").getValue()
    # rendered on studio funk farm
    studioFunkRender = n.knob("studio_funk_render").getValue()
    # comment
    comment = k["comment"].getText()
    # shortname
    shortname = k["user"].getText()
    if shortname == "":
        nuke.message("Please fill out your shortname in the User field. E.g. \"ms\"")
        return
    # precomp render path
    major = k["major_version"].getValue()
    major = "v" + str(int(major)).zfill(3)
    path = k["comp_output_path"].getText()
    path = path.replace("MAJORVERSION", str(major))
    output = k["comp_output_file"].getText()
    output = output.replace("MAJORVERSION", str(major))
    path = path.replace("\\", "/")
    precomp = "%s/%s" % (path, output)
    # evaluate expressions
    k["eval_helper"].setValue(precomp)
    precomp = k["eval_helper"].evaluate()
    precomp = precomp.replace("\\", "/")
    frames = precomp.split(".")[-2]
    precomp = precomp.replace(frames, "####")
    precomp_dir = os.path.dirname(precomp)
    # debug
    debug = k["Debug"].getValue()

    # gather Layers and versions to publish (exclude flagged Layers)
    layernum = k["layerNum"].getValue()
    num = int(layernum)
    layer = {}
    publish = {}
    metadata = {}
    skip_copy_layers = []

    for c in range(1, num + 1, 1):
        layername = n.knob("layer_name_" + str(c)).getValue()
        layerversion = n.knob("layer_version_" + str(c)).getValue()

        if n.knob("include_in_publish_" + str(c)).getValue() == 1:
            layer[layername] = str(int(layerversion)).zfill(3)

        if n.knob("copy_layer_" + str(c)).getValue() == 1:
            skip_copy_layers.append(layername)

            # search for readnodes that are linked in SceneControl
            meta = return_readnodes("layer_version_" + str(c))
            node = nuke.toNode(str(meta))
            if node is not None:
                if node.metadata() != {}:
                    for k, v in node.metadata().iteritems():
                        # print (k > v)
                        if k == "exr/DRR_Scene":
                            metadata[layername + "_Scene"] = v
                        if k == "exr/DRR_Shader":
                            metadata[layername + "_Shader"] = v
                        if k == "exr/DRR_FXAssembly":
                            metadata[layername + "_FXAssembly"] = v
                else:
                    print ("SceneControl: No Metadata availible")
        else:
            # should not be included in publish
            pass

    """
    publish["nukescript"] = nukescript
    # //hades/p/_projekte/DRR/02_Shots/SEQ_0200/SHOT_0200_0010/04_Lighting/02_work/nuke/lighting/
    publish["sequence"] = sequence
    # 0160
    publish["shot"] = shot
    # 0040
    publish["cut_in"] = frameCutIn
    # 1009  
    publish["cut_out"] = frameCutOut
    # 1109 
    publish["precomp_cut_in"] = precomp_cut_in
    # 1009
    publish["precomp_cut_out"] = precomp_cut_out
    # 1009
    publish["comment"] = comment
    # "My Comment\nAnother comment.\nYet another comment."
    publish["shortname"] = shortname
    # "ms"
    publish["layer"] = layer
    # {"CHAR": "011", "VOL": "011", "DUS": "009", "ENV": "011"}
    publish["skip_copy_layers"] = skip_copy_layers
    # ("CHAR","ENV")
    publish["metadata"] = layer
    # {"CHAR_Scene": "/path/to/desertRuins_MOD_v037.003.json", "CHAR_Shader": "/path/to/desertRuins_MOD_v037.003.shdAssembly.json", "CHAR_FXAssembly": "/path/to/FXAssembly"}
    publish["precomp_dir"] = precomp_dir
    # //hades/p/_projekte/DRR/02_Shots/SEQ_0160/SHOT_0160_0040/04_Lighting/02_work/nuke/lighting/render/SHOT_0160_0040_LIG_v001
    publish["email_recipients"] = ["martin@saechsinger.de"]
    """

    save_script(publish=True)

    # nukescript
    nukescript = nuke.Root()["name"].getValue()

    # prepare publish dict
    publish["nukescript"] = nukescript
    publish["sequence"] = sequence
    publish["cut_in"] = frameCutIn
    publish["cut_out"] = frameCutOut
    publish["shot"] = shot
    publish["comment"] = comment
    publish["shortname"] = shortname
    publish["layer"] = layer
    publish["skip_copy_layers"] = skip_copy_layers
    publish["precomp_dir"] = precomp_dir
    publish["metadata"] = metadata
    publish["eye"] = eye
    if studioFunkRender:
        publish["precomp_cut_in"] = precompframeCutIn
        publish["precomp_cut_out"] = precompframeCutOut
    # save script (scene control will get deleted)

    # do the publish
    if debug == 1.0:
        reload(publisher)
        print ("SceneControl: ____Test Publish:____")
        for k, v in publish.items(): print (k, '>', v)
    else:
        reload(publisher)
        for k, v in publish.items(): print (k, '>', v)
        publisher.Lighting(**publish).publish()
    return None


def return_readnodes(layername):
    nodes = nuke.allNodes()
    for n in nodes:
        if n.Class() == "Read":
            filepath = n.knob("file").getValue()
            if layername in filepath:
                return n.name()
    return None


def create_readnode_old(c, autoconnect=None):
    # TODO: create just one function for read, deep read and cryptomatte
    n = nuke.thisNode()
    k = n.knobs()
    layer = n.knob("layer_name_" + str(c)).getValue()
    a = "layer_version_" + str(c)
    version = "v[format %%03d [value SceneControl.%s]]" % a

    # replace [ASSETVERSION] with version of SceneControl
    # Read
    path = k["output_path"].getText()
    output = k["output_file"].getText()
    path = path.replace("LAYERVERSION", str(version))
    path = path.replace("\\", "/")
    output = output.replace("LAYERVERSION", str(version))
    path = path.replace("LAYER", str(layer))
    output = output.replace("LAYER", str(layer))

    file = "%s/%s" % (path, output)

    k["eval_helper"].setValue(file)
    checkfile = k["eval_helper"].evaluate()
    checkfile = checkfile.replace("\\", "/")

    # create Read __________________________________________________
    read = nuke.nodes.Read()
    read.setName(layer)

    read["file"].setValue(file)
    missing = k["missing_frames"].getText()
    if missing == "error":
        read["on_error"].setValue(0)
    elif missing == "black":
        read["on_error"].setValue(1)
    elif missing == "checkerboard":
        read["on_error"].setValue(2)
    elif missing == "nearest frame":
        read["on_error"].setValue(3)

    read["first"].setExpression("[value SceneControl.fStart]")
    read["origfirst"].setExpression("[value SceneControl.fStart]")
    read["last"].setExpression("[value SceneControl.fEnd]")
    read["origlast"].setExpression("[value SceneControl.fEnd]")
    read["label"].setValue("scnCtrl")

    # position Read
    if autoconnect is None:
        # connect to selectedNode
        try:
            selectedNode = nuke.selectedNode()
        except:
            selectedNode = None

        if selectedNode is not None:
            selectedNode.setInput(0, read)
            read.setXYpos(selectedNode.xpos(), selectedNode.ypos() - 150)
    else:
        # connect to dots with starts with layer name
        dot = find_node_by_type(layer, "Dot")
        if dot is not None:
            dot.setInput(0, read)
            read.setXYpos(dot.xpos() - 37, dot.ypos() - 150)
        else:
            pass
        dot = None
    return


def create_deepreadnode_old(c, autoconnect=None):
    n = nuke.thisNode()
    k = n.knobs()
    layer = n.knob("layer_name_" + str(c)).getValue()
    a = "layer_version_" + str(c)
    version = "v[format %%03d [value SceneControl.%s]]" % a

    # replace [ASSETVERSION] with version of SceneControl
    # DeepRead __________________________________________________
    path = k["output_path"].getText()
    output = k["deep_output_file"].getText()
    path = path.replace("LAYERVERSION", str(version))
    path = path.replace("\\", "/")
    output = output.replace("LAYERVERSION", str(version))
    path = path.replace("LAYER", str(layer))
    output = output.replace("LAYER", str(layer))

    deep_subfolder = k["deep_subfolder"].getText()
    if not deep_subfolder:
        file = "%s/%s" % (path, output)
    else:
        file = "%s/%s/%s" % (path, deep_subfolder, output)

    k["eval_helper"].setValue(file)
    checkfile = k["eval_helper"].evaluate()
    checkfile = checkfile.replace("\\", "/")

    # create DeepRead
    read = nuke.nodes.DeepRead()
    read.setName(layer + "_Deep")

    read["file"].setValue(file)
    missing = k["missing_frames"].getValue()
    if missing == "error":
        read["on_error"].setValue(0)
    elif missing == "black":
        read["on_error"].setValue(1)
    elif missing == "checkerboard":
        read["on_error"].setValue(2)
    elif missing == "nearest frame":
        read["on_error"].setValue(3)

    read["on_error"].setValue(1)
    read["first"].setExpression("[value SceneControl.fStart]")
    read["origfirst"].setExpression("[value SceneControl.fStart]")
    read["last"].setExpression("[value SceneControl.fEnd]")
    read["origlast"].setExpression("[value SceneControl.fEnd]")
    read["label"].setValue("scnCtrl")

    # position Deep Read
    if autoconnect is None:
        # connect to selectedNode
        try:
            selectedNode = nuke.selectedNode()
        except:
            selectedNode = None

        if selectedNode is not None:
            read.setXYpos(selectedNode.xpos() - 37, selectedNode.ypos() - 25)
    else:
        # connect to dots with starts with layer name
        dot = find_node_by_type(layer + "_Deepread", "Dot")
        if dot is not None:
            dot.setInput(0, read)
            read.setXYpos(dot.xpos() - 50, dot.ypos() - 150)
        else:
            pass
        dot = None
    return


def return_highest_layer_version():
    n = nuke.thisNode()
    k = n.knobs()

    # gather Layers and versions to publish (exclude flagged Layers)
    layernum = k["layerNum"].getValue()
    num = int(layernum)
    maximum = 1
    for c in range(1, num + 1, 1):
        value = n.knob("layer_version_" + str(c)).getValue()
        if value > maximum:
            maximum = value
    print ("SceneControl: Highest Version is: %s" % int(maximum))
    return int(maximum)


def debugQuery():
    sceneControl = getSceneControl()
    k = sceneControl.knobs()

    # element
    element = k['element'].value()
    if element is None or len(element)==0:
        element = 'None'
    # info
    info = k['info'].value()
    if info is None or len(info)==0:
        info = 'None'


    print('SceneControl: Debug kenv query:')
    print('PROJECT: ' + os.environ['PROJECT'])
    print('SEQUENCE: ' + k['sequence'].value())
    print('SHOT: ' + k['shot'].value())
    print('DEPT: ' + k['dept'].value())
    print('TASK: ' + k['task'].value())
    print('MAJOR_VERSION: ' + str(int(k['major_version'].value())))
    print('MINOR_VERSION: ' + str(int(k['minor_version'].value())))
    print('ELEMENT: ' + element)
    print('INFO: ' + info)
    print('USER: ' + k['user'].value())
    print('EXT: exr')
    print('APP_ID: nuke')
    return


# deprecated
def load_precomp():
    major = nuke.thisNode().knob("major_version").getValue()
    major = "v" + str(int(major)).zfill(3)
    n = nuke.thisNode()
    k = n.knobs()

    path = k["comp_output_path"].getText()
    path = path.replace("MAJORVERSION", str(major))
    output = k["comp_output_file"].getText()
    output = output.replace("MAJORVERSION", str(major))
    path = path.replace("\\", "/")

    file = "%s/%s" % (path, output)
    # dance the resolve dance
    k["precomp_output"].setValue(file)
    precomp = k["precomp_output"].evaluate()
    precomp = precomp.replace("\\", "/")
    sub = precomp.split(".")[-2]
    precomp = precomp.replace(sub, "####")

    # create the read file
    read = nuke.nodes.Read()
    read.setName("Precomp")
    read["file"].setValue(precomp)
    read["first"].setExpression("[value SceneControl.fStart]")
    read["origfirst"].setExpression("[value SceneControl.fStart]")
    read["last"].setExpression("[value SceneControl.fEnd]")
    read["origlast"].setExpression("[value SceneControl.fEnd]")

    try:
        selectedNode = nuke.selectedNode()
    except:
        selectedNode = None

    if selectedNode is not None:
        read.setXYpos(selectedNode.xpos() + 100, selectedNode.ypos())

    return None


def create_writenode():
    major = nuke.thisNode().knob("major_version").getValue()
    major = "v" + str(int(major)).zfill(3)
    write = nuke.nodes.Write()
    write.setName("Precomp")
    n = nuke.thisNode()
    k = n.knobs()

    path = k["comp_output_path"].getText()
    # path = path.replace("MAJORVERSION", str(major))
    output = k["comp_output_file"].getText()
    # output = output.replace("MAJORVERSION", str(major))
    path = path.replace("\\", "/")

    file = "%s/%s" % (path, output)
    write["file"].setValue(file)
    write["views"].setValue("left")
    write["file_type"].setValue("exr")
    write["create_directories"].setValue(1)
    write["metadata"].setValue(4)

    try:
        selectedNode = nuke.selectedNode()
    except:
        selectedNode = None

    if selectedNode is not None:
        write.setInput(0, selectedNode)
        write.setXYpos(selectedNode.xpos(), selectedNode.ypos() + 66)
    return


def remove_scnctrl_reads(node):
    nodes = nuke.allNodes()
    for n in nodes:
        if n.Class() == "Read" or n.Class() == "DeepRead":
            s = n.knob("label").getValue()
            if s.startswith("scnCtrl"):
                nuke.delete(n)
        else:
            pass
    return


