import bpy
from . import fn

## direct use (Pop up menu version below)
"""
class GPEXP_OT_clean_compo_tree(bpy.types.Operator):
    bl_idname = "gp.clean_compo_tree"
    bl_label = "Clean Compo Tree"
    bl_description = "Reorder inputs/outputs and clear unused viewlayers"
    bl_options = {"REGISTER"}

    @classmethod
    def poll(cls, context):
        return True

    # mode : bpy.props.StringProperty(default='NORMAL', options={'SKIP_SAVE'})

    def execute(self, context):
        render = bpy.data.scenes.get('Render')
        if not render:
            print('SKIP, no Render scene')
            return {"CANCELLED"}

        print('re-arranging frames')
        fn.rearrange_frames(render.node_tree)

        for n in render.node_tree.nodes:
            if n.name.startswith('NG_'):
                fn.reorder_inputs(n)
                fn.reorder_outputs(n)

                # get output node to reorder output
                out = None
                for s in n.outputs:
                    if not s.is_linked:
                        continue
                    out = s.links[0].to_node
                    if out.type == 'OUTPUT_FILE':
                        break
                if out:
                    fn.reorder_fileout(out, ng=n)


        ## clear disconnected fileout ??...
        # for fo in render.node_tree.nodes:
        #     if fo.type != 'OUTPUT_FILE':
        #         continue
        #     fn.clear_disconnected(fo)

        return {"FINISHED"}
"""

class GPEXP_OT_clean_compo_tree(bpy.types.Operator):
    bl_idname = "gp.clean_compo_tree"
    bl_label = "Clean Compo Tree"
    bl_description = "Pop up menu with cleaning options"
    bl_options = {"REGISTER", "UNDO"}

    # Internal prop (use when launching from python)
    use_render_scene : bpy.props.BoolProperty(name="Use Render Scene",
        description="Force the clean on scene named Render, abort if not exists (not exposed)",
        default=False, options={'SKIP_SAVE'})

    clear_unused_view_layers : bpy.props.BoolProperty(name="Clear unused view layers",
        description="Delete view layer that aren't used in the nodetree anymore",
        default=True)

    arrange_rl_nodes : bpy.props.BoolProperty(name="Arrange Render Node In Frames",
        description="Re-arrange Render Layer Nodes Y positions within each existing frames" ,
        default=True)

    arrange_frames : bpy.props.BoolProperty(name="Arrange Frames",
        description="Re-arrange all frames Y positions" ,
        default=True)

    reorder_inputs : bpy.props.BoolProperty(name="Reorder I/O Sockets",
        description="Reorder inputs/outputs of all 'NG_' nodegroup and their connected file output",
        default=True)

    clear_isolated_node_in_groups : bpy.props.BoolProperty(name="Clear Isolated Node In Groups",
        description="Clean content of 'NG_' nodegroup bpy deleting isolated nodes)",
        default=True)

    fo_clear_disconnected : bpy.props.BoolProperty(name="Remove Disconnected Export Inputs",
        description="Clear any disconnected intput of every 'file output' node",
        default=False)

    @classmethod
    def poll(cls, context):
        return True

    def invoke(self, context, event):
        return context.window_manager.invoke_props_dialog(self)

    def draw(self, context):
        layout = self.layout
        layout.prop(self, 'clear_unused_view_layers')
        layout.prop(self, 'arrange_rl_nodes')
        layout.prop(self, 'arrange_frames')
        layout.prop(self, 'reorder_inputs')
        layout.prop(self, 'clear_isolated_node_in_groups')

        layout.separator()
        layout.prop(self, 'fo_clear_disconnected')
        if self.fo_clear_disconnected:
            layout.label(text='Disconnected inputs are not exported', icon='INFO')

        # box = layout.box()
        # box.prop(self, 'arrange_frames')
        # box.prop(self, 'reorder_inputs')
        # box.prop(self, 'fo_clear_disconnected')

    def execute(self, context):
        if self.use_render_scene:
            render = bpy.data.scenes.get('Render')
            if not render:
                print('SKIP clean_compo_tree, No "Render" scene !')
                return {"CANCELLED"}
        else:
            render = context.scene

        nodes = render.node_tree.nodes
        for n in nodes:
            n.update()
        if self.clear_unused_view_layers:
            used_rlayer_names = [n.layer for n in nodes if n.type == 'R_LAYERS']
            for rl in reversed(render.view_layers):
                if rl.name in used_rlayer_names or rl.name == 'View Layer':
                    continue
                render.view_layers.remove(rl)

        if self.arrange_rl_nodes:
            fn.rearrange_rlayers_in_frames(render.node_tree)

        if self.arrange_frames:
            fn.rearrange_frames(render.node_tree)

        if self.reorder_inputs:
            for n in nodes:
                if n.type != 'GROUP' or not n.name.startswith('NG_'):
                    continue
                fn.reorder_inputs(n)
                fn.reorder_outputs(n)

                # get output node to reorder output
                out = None
                for s in n.outputs:
                    if not s.is_linked:
                        continue
                    out = s.links[0].to_node
                    if out.type == 'OUTPUT_FILE':
                        break
                if out:
                    fn.reorder_fileout(out, ng=n)

                # Clear input that do not exists
                fn.clean_nodegroup_inputs(n, skip_existing_pass=True)

                fn.bridge_reconnect_nodegroup(n)

        if self.clear_isolated_node_in_groups:
            for n in nodes:
                if n.type != 'GROUP' or not n.name.startswith('NG_'):
                    continue
                fn.clear_nodegroup_content_if_disconnected(n.node_tree)

        if self.fo_clear_disconnected:
            for fo in nodes:
                if fo.type != 'OUTPUT_FILE':
                    continue
                fn.clear_disconnected(fo)


        return {"FINISHED"}



classes=(
GPEXP_OT_clean_compo_tree,
)

def register():
    for cls in classes:
        bpy.utils.register_class(cls)

def unregister():
    for cls in reversed(classes):
        bpy.utils.unregister_class(cls)