import maya.api.OpenMaya as om
import maya.api.OpenMayaUI as omui
import maya.api.OpenMayaRender as omr
import maya.cmds as cmds

import const, mayaUtils
import clippingPlaneTpl

import pluginUtils
log = pluginUtils.log.getLogger('V3D-MY')

NODE_TYPE = 'v3dClippingPlane'

# just for convenience to use from other modules
NODE_NAME = 'v3dClippingPlane'
NODE_SHELF_NAME = 'v3dClippingPlaneShape'

DRAW_CLASSIFICATION = 'drawdb/geometry/v3dClippingPlane'
DRAW_REGISTRANT_ID = 'v3dClippingPlane'

# colors in the linear space, converted to sRGB in Maya's viewport
COL_LIGHT_BLUE = om.MColor((0.1329, 0.4078, 0.9463, 1))
COL_LIGHT_GREEN = om.MColor((0.0562, 1, 0.366, 1))

# setting it other than 1 leads to rendering issues on certain drivers/devices
LINE_WIDTH = 1

PLANE_SIZE = 1
UP_SIZE = 0.2

RENDER_SIDE_FRONT = 0
RENDER_SIDE_BACK = 1
RENDER_SIDE_DOUBLE = 2
RENDER_SIDE_ENUM = ['FRONT', 'BACK', 'DOUBLE']
RENDER_SIDE_ENUM_UI = ['Front Side', 'Back Side', 'Double-Sided']

def maya_useNewAPI():
    pass

class Shape(om.MPxSurfaceShape):

    @classmethod
    def creator(cls):
        return cls()

    @classmethod
    def initializer(cls):
        mAttr = om.MFnMessageAttribute()
        nAttr = om.MFnNumericAttribute()
        eAttr = om.MFnEnumAttribute()

        affectedObjects = mAttr.create('affectedObjects', 'ao')
        cls.addAttribute(affectedObjects)

        negated = nAttr.create('negated', 'ng', om.MFnNumericData.kBoolean, False)
        cls.addAttribute(negated)

        clipShadows = nAttr.create('clipShadows', 'cs', om.MFnNumericData.kBoolean, False)
        cls.addAttribute(clipShadows)

        unionPlanes = nAttr.create('unionPlanes', 'ul', om.MFnNumericData.kBoolean, True)
        cls.addAttribute(unionPlanes)

        crossSection = nAttr.create('crossSection', 'cr', om.MFnNumericData.kBoolean, False)
        cls.addAttribute(crossSection)

        crossSectionColor = nAttr.createColor('crossSectionColor', 'csc')
        nAttr.default = (0.5, 0.0, 0.0)
        cls.addAttribute(crossSectionColor)

        crossSectionRenderSide = eAttr.create('crossSectionRenderSide', 'rs', 0)
        eAttr.addField(RENDER_SIDE_ENUM_UI[0], RENDER_SIDE_FRONT)
        eAttr.addField(RENDER_SIDE_ENUM_UI[1], RENDER_SIDE_BACK)
        eAttr.addField(RENDER_SIDE_ENUM_UI[2], RENDER_SIDE_DOUBLE)
        cls.addAttribute(crossSectionRenderSide)

        crossSectionSize = nAttr.create('crossSectionSize', 'css', om.MFnNumericData.kFloat, 100)
        nAttr.setMin(0)
        cls.addAttribute(crossSectionSize)


    def __init__(self):
        super(Shape, self).__init__()

    def setDependentsDirty(self, plugBeingDirtied, affectedPlugs):
        return super(Shape, self).setDependentsDirty(plugBeingDirtied, affectedPlugs)

    def getShapeSelectionMask(self):
        return om.MSelectionMask(om.MSelectionMask.kSelectMeshes)


class ShapeUI(omui.MPxSurfaceShapeUI):

    @classmethod
    def creator(cls):
        return cls()

    def __init__(self):
        super(ShapeUI, self).__init__()


class ShapeUserData(om.MUserData):

    def __init__(self):
        super(ShapeUserData, self).__init__()
        self.selected = False

class ShapeDrawOverride(omr.MPxDrawOverride):

    @classmethod
    def creator(cls, obj):
        return cls(obj)

    def __init__(self, obj):
        super(ShapeDrawOverride, self).__init__(obj, None, False)

    def hasUIDrawables(self):
        return True

    def supportedDrawAPIs(self):
        return omr.MRenderer.kAllDevices

    def prepareForDraw(self, objPath, cameraPath, frameContext, oldData):
        depNode = om.MFnDependencyNode(objPath.node())

        data = ShapeUserData()
        data.selected = shapeIsSelected(objPath)

        return data

    def addUIDrawables(self, objPath, drawManager, frameContext, data):
        # sys -> cm
        planeSize = PLANE_SIZE / mayaUtils.getScaleFactor()
        upSize = UP_SIZE / mayaUtils.getScaleFactor()

        drawManager.beginDrawable()
        drawManager.setLineWidth(LINE_WIDTH)
        drawManager.setColor(COL_LIGHT_GREEN if data.selected else COL_LIGHT_BLUE)

        # rectangle
        drawManager.line(om.MPoint(planeSize, 0, -planeSize), om.MPoint(planeSize, 0, planeSize))
        drawManager.line(om.MPoint(-planeSize, 0, -planeSize), om.MPoint(-planeSize, 0, planeSize))
        drawManager.line(om.MPoint(-planeSize, 0, -planeSize), om.MPoint(planeSize, 0, -planeSize))
        drawManager.line(om.MPoint(-planeSize, 0, planeSize), om.MPoint(planeSize, 0, planeSize))

        # up lines
        drawManager.line(om.MPoint(planeSize, 0, -planeSize), om.MPoint(planeSize, upSize, -planeSize))
        drawManager.line(om.MPoint(planeSize, 0, planeSize), om.MPoint(planeSize, upSize, planeSize))
        drawManager.line(om.MPoint(-planeSize, 0, -planeSize), om.MPoint(-planeSize, upSize, -planeSize))
        drawManager.line(om.MPoint(-planeSize, 0, planeSize), om.MPoint(-planeSize, upSize, planeSize))

        # hatching
        drawManager.line(om.MPoint(0, 0, -planeSize), om.MPoint(-planeSize, 0, 0))
        drawManager.line(om.MPoint(planeSize, 0, -planeSize), om.MPoint(-planeSize, 0, planeSize))
        drawManager.line(om.MPoint(planeSize, 0, 0), om.MPoint(0, 0, planeSize))

        drawManager.endDrawable()


def shapeIsSelected(objPath):
    selList = om.MGlobal.getActiveSelectionList()
    if selList.hasItem(objPath):
        return True

    parents = cmds.listRelatives(om.MDagPath(objPath), parent=True, fullPath=True)
    if parents:
        parentSelList = om.MSelectionList()
        parentSelList.add(parents[0])
        parentDagPath = parentSelList.getDagPath(0)
        if selList.hasItem(parentDagPath):
            return True

    return False

def getAffectedObjectsSet(nodeName):
    conn = cmds.listConnections(nodeName + '.affectedObjects')
    aos = cmds.ls(conn, sets=True)
    if aos:
        return aos[0]
    else:
        return ''

def getRenderSideName(idx):
    return RENDER_SIDE_ENUM[idx]

def register(mplugin):
    try:
        clippingPlaneTpl.register(NODE_TYPE)
        mplugin.registerShape(NODE_TYPE, const.V3D_CLIPPING_PLANE_ID, Shape.creator,
                Shape.initializer, ShapeUI.creator, DRAW_CLASSIFICATION)
        omr.MDrawRegistry.registerDrawOverrideCreator(
                DRAW_CLASSIFICATION, DRAW_REGISTRANT_ID,
                ShapeDrawOverride.creator)
    except:
        log.error('Failed to register shape node: {}'.format(NODE_TYPE))
        raise


def unregister(mplugin):
    try:
        omr.MDrawRegistry.deregisterDrawOverrideCreator(
                DRAW_CLASSIFICATION, DRAW_REGISTRANT_ID)
        mplugin.deregisterNode(const.V3D_CLIPPING_PLANE_ID)
    except:
        log.error('Failed to unregister shape node: {}'.format(NODE_TYPE))
        raise
