import maya.api.OpenMaya as om
import maya.cmds as cmds
import maya.mel as mel

import tplUtils


class VisibilitySetMenu(tplUtils.SetMenu):

    def __init__(self, linkedAttrName):
        super(VisibilitySetMenu, self).__init__(linkedAttrName)

    def createOptionMenu(self):
        super(VisibilitySetMenu, self).createOptionMenu('Visibility Set')
        cmds.optionMenu(self.optMenu, edit=True, annotation=(
                'Limit nodes that should appear on the reflection plane to\n'
                'this selection set. If not specified all scene nodes will be\n'
                'used.'
                ))

visSetMenu = VisibilitySetMenu('visibilitySelectionSet')

# NOTE: needs to be available for import to access them from the MEL callbacks
visSetMenuNew = visSetMenu.callbackNew
visSetMenuReplace = visSetMenu.callbackReplace


def template(nodeName):
    tplUtils.suppressDefaultShapeAttributes()

    # this attribute is hidden, because it's handled via a custom selection menu
    cmds.editorTemplate(suppress='visibilitySelectionSet')

    cmds.editorTemplate(beginLayout='General Settings', collapse=False)
    cmds.editorTemplate('influenceDistance', addControl=True,
            annotation='Influence distance of the probe.')
    cmds.editorTemplate('falloff', addControl=True,
            annotation='Control how fast the probe influence decreases.')
    cmds.editorTemplate('clipStart', addControl=True, label='Clipping Offset',
            annotation=(
            'Probe clip start, below which objects will not appear in reflections.'
            ))
    cmds.editorTemplate(endLayout=True)

    cmds.editorTemplate(beginLayout='Visibility Set', collapse=False)
    tplUtils.addControlCallCustom([__name__, 'visSetMenuNew'],
            [__name__, 'visSetMenuReplace'])
    cmds.editorTemplate('invertVisibilitySelectionSet', addControl=True,
            label='Invert Visibility', annotation=(
            'If "Visibility Set" is specified then this option makes it so only\n'
            'objects that don\'t belong to the set are rendered into the\n'
            'reflection cubemap.'
            ))
    cmds.editorTemplate(endLayout=True)




addedCbId = None
removedCbId = None
nameChangedCbId = None
afterSceneReadCbId = None

def register(nodeType):
    mel.eval("""
    global proc AE%sTemplate(string $nodeName) {
        python("import %s as tpl");
        python("tpl.template(\\"" + $nodeName + "\\")");
    };""" % (nodeType, __name__))


    menus = [visSetMenu]

    def objectSetAdded(objectSet, clientData):
        for menu in menus:
            menu.objectSetAddedCb(objectSet)

    def objectSetRemoved(objectSet, clientData):
        for menu in menus:
            menu.objectSetRemovedCb(objectSet)

    def nameChanged(node, prevName, clientData):
        """
        NOTE: Nodes cannot have empty names, an empty prevName means that the
        node was created just now and there was not actual renaming. Also, an
        empty name can collide with the empty menu option ('' means nothing
        selected), hence not doing anything here in this case.
        """
        if prevName == '':
            return

        """
        The "nameChanged" node callback itself doesn't support filtering nodes
        by type like "nodeAdded" and "nodeRemoved"
        """
        if node.apiType() != om.MFn.kSet:
            return

        for menu in menus:
            menu.objectSetNameChangedCb(node, prevName)

    def afterSceneRead(clientData):
        for menu in menus:
            menu.afterSceneReadCb()

    global addedCbId
    global removedCbId
    global nameChangedCbId
    global afterSceneReadCbId
    addedCbId = om.MDGMessage.addNodeAddedCallback(objectSetAdded, 'objectSet')
    removedCbId = om.MDGMessage.addNodeRemovedCallback(objectSetRemoved, 'objectSet')
    nameChangedCbId = om.MNodeMessage.addNameChangedCallback(om.MObject(), nameChanged)
    afterSceneReadCbId = om.MSceneMessage.addCallback(
            om.MSceneMessage.kAfterSceneReadAndRecordEdits, afterSceneRead)

def unregister():
    om.MMessage.removeCallback(addedCbId)
    om.MMessage.removeCallback(removedCbId)
    om.MMessage.removeCallback(nameChangedCbId)
    om.MMessage.removeCallback(afterSceneReadCbId)
