# SPDX-FileCopyrightText: 2017-2022 Blender Foundation
#
# SPDX-License-Identifier: GPL-2.0-or-later

import bpy
from bpy.types import (
        Operator,
        Menu,
        )
from bpy.props import BoolProperty
from . import utils_core
from . import brushes
from bl_ui.properties_paint_common import UnifiedPaintPanel

class BrushOptionsMenu(Menu):
    bl_label = "Brush Options"
    bl_idname = "VIEW3D_MT_sv3_brush_options"

    @classmethod
    def poll(self, context):
        return utils_core.get_mode() in (
                    'SCULPT', 'VERTEX_PAINT',
                    'WEIGHT_PAINT', 'TEXTURE_PAINT',
                    'PARTICLE_EDIT'
                    )

    def draw(self, context):
        mode = utils_core.get_mode()
        layout = self.layout

        # add generic menu items
        layout.operator_context = 'INVOKE_REGION_WIN'
        layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM')
        layout.operator("wm.toolbar", text="Tools", icon='TOOL_SETTINGS')
        layout.menu("SCREEN_MT_user_menu", text="Quick Favorites", icon='HEART')
        layout.operator_menu_enum("object.mode_set", "mode",
                                  text="Interactive Mode", icon='VIEW3D')
        layout.separator()


        # add mode specific menu items
        if mode == 'SCULPT':
            self.sculpt(mode, layout, context)

        elif mode in ('VERTEX_PAINT', 'WEIGHT_PAINT'):
            self.vw_paint(mode, layout, context)

        elif mode == 'TEXTURE_PAINT':
            self.texpaint(mode, layout, context)

        else:
            self.particle(layout, context)

    def sculpt(self, mode, layout, context):
        has_brush = utils_core.get_brush_link(context, types="brush")
        icons = brushes.get_brush_icon(mode, has_brush.sculpt_tool) if \
                has_brush else "BRUSH_DATA"

        layout.row().menu("VIEW3D_MT_sv3_brushes_menu",
                            icon=icons)

        layout.row().menu(BrushRadiusMenu.bl_idname)

        if has_brush:
            # if the active brush is unlinked these menus don't do anything
            layout.row().menu(BrushStrengthMenu.bl_idname)
            layout.row().menu(BrushAutosmoothMenu.bl_idname)
            layout.row().menu(BrushModeMenu.bl_idname)
            layout.row().menu("VIEW3D_MT_sv3_texture_menu")
            layout.row().menu("VIEW3D_MT_sv3_stroke_options")
            layout.row().menu("VIEW3D_MT_sv3_brush_curve_menu")

        layout.row().menu("VIEW3D_MT_sv3_dyntopo")
        layout.row().menu("VIEW3D_MT_sv3_master_symmetry_menu")

    def vw_paint(self, mode, layout, context):
        has_brush = utils_core.get_brush_link(context, types="brush")
        icons = brushes.get_brush_icon(mode, has_brush.vertex_tool) if \
                has_brush else "BRUSH_DATA"

        if mode == 'VERTEX_PAINT':
            layout.row().operator(ColorPickerPopup.bl_idname, icon="COLOR")
            layout.row().separator()

        layout.row().menu("VIEW3D_MT_sv3_brushes_menu",
                            icon=icons)

        if mode == 'VERTEX_PAINT':
            layout.row().menu(BrushRadiusMenu.bl_idname)

            if has_brush:
                # if the active brush is unlinked these menus don't do anything
                layout.row().menu(BrushStrengthMenu.bl_idname)
                layout.row().menu(BrushModeMenu.bl_idname)
                layout.row().menu("VIEW3D_MT_sv3_texture_menu")
                layout.row().menu("VIEW3D_MT_sv3_stroke_options")
                layout.row().menu("VIEW3D_MT_sv3_brush_curve_menu")

        if mode == 'WEIGHT_PAINT':
            layout.row().menu(BrushWeightMenu.bl_idname)
            layout.row().menu(BrushRadiusMenu.bl_idname)

            if has_brush:
                # if the active brush is unlinked these menus don't do anything
                layout.row().menu(BrushStrengthMenu.bl_idname)
                layout.row().menu(BrushModeMenu.bl_idname)
                layout.row().menu("VIEW3D_MT_sv3_stroke_options")
                layout.row().menu("VIEW3D_MT_sv3_brush_curve_menu")

        layout.row().menu("VIEW3D_MT_sv3_master_symmetry_menu")

    def texpaint(self, mode, layout, context):
        toolsettings = context.tool_settings.image_paint

        has_brush = utils_core.get_brush_link(context, types="brush")
        icons = brushes.get_brush_icon(mode, has_brush.image_tool) if \
                    has_brush else "BRUSH_DATA"

        if context.image_paint_object and not toolsettings.detect_data():
            if toolsettings.missing_uvs:
                layout.row().label(text="Missing UVs", icon='ERROR')
                layout.row().operator("paint.add_simple_uvs")

                return

            elif toolsettings.missing_materials or toolsettings.missing_texture:
                layout.row().label(text="Missing Data", icon='ERROR')
                layout.row().operator_menu_enum("paint.add_texture_paint_slot", \
                                                  "type", \
                                                  icon='ADD', \
                                                  text="Add Texture Paint Slot")

                return

            elif toolsettings.missing_stencil:
                layout.row().label(text="Missing Data", icon='ERROR')
                layout.row().label(text="See Mask Properties", icon='FORWARD')
                layout.row().separator()
                layout.row().menu("VIEW3D_MT_sv3_brushes_menu",
                                    icon=icons)

                return

            else:
                layout.row().label(text="Missing Data", icon="INFO")

        else:
            if has_brush and has_brush.image_tool in {'DRAW', 'FILL'} and \
               has_brush.blend not in {'ERASE_ALPHA', 'ADD_ALPHA'}:
                layout.row().operator(ColorPickerPopup.bl_idname, icon="COLOR")
                layout.row().separator()

            layout.row().menu("VIEW3D_MT_sv3_brushes_menu",
                                icon=icons)

            if has_brush:
                # if the active brush is unlinked these menus don't do anything
                if has_brush and has_brush.image_tool in {'MASK'}:
                    layout.row().menu(BrushWeightMenu.bl_idname, text="Mask Value")

                if has_brush and has_brush.image_tool not in {'FILL'}:
                    layout.row().menu(BrushRadiusMenu.bl_idname)

                layout.row().menu(BrushStrengthMenu.bl_idname)

                if has_brush and has_brush.image_tool in {'DRAW'}:
                    layout.row().menu(BrushModeMenu.bl_idname)

                layout.row().menu("VIEW3D_MT_sv3_texture_menu")
                layout.row().menu("VIEW3D_MT_sv3_stroke_options")
                layout.row().menu("VIEW3D_MT_sv3_brush_curve_menu")

            layout.row().menu("VIEW3D_MT_sv3_master_symmetry_menu")

    def particle(self, layout, context):
        particle_edit = context.tool_settings.particle_edit

        layout.row().menu("VIEW3D_MT_sv3_brushes_menu",
                            icon="BRUSH_DATA")
        layout.row().menu(BrushRadiusMenu.bl_idname)

        if particle_edit.tool != 'ADD':
            layout.row().menu(BrushStrengthMenu.bl_idname)
        else:
            layout.row().menu(ParticleCountMenu.bl_idname)
            layout.row().separator()
            layout.row().prop(particle_edit, "use_default_interpolate", toggle=True)

            layout.row().prop(particle_edit.brush, "steps", slider=True)
            layout.row().prop(particle_edit, "default_key_count", slider=True)

        if particle_edit.tool == 'LENGTH':
            layout.row().separator()
            layout.row().menu(ParticleLengthMenu.bl_idname)

        if particle_edit.tool == 'PUFF':
            layout.row().separator()
            layout.row().menu(ParticlePuffMenu.bl_idname)
            layout.row().prop(particle_edit.brush, "use_puff_volume", toggle=True)

        layout.row().menu("VIEW3D_MT_sv3_master_symmetry_menu")


class BrushRadiusMenu(Menu):
    bl_label = "Radius"
    bl_idname = "VIEW3D_MT_sv3_brush_radius_menu"
    bl_description = "Change the size of the brushes"

    def init(self):
        if utils_core.get_mode() == 'PARTICLE_EDIT':
            settings = (("100", 100),
                        ("70", 70),
                        ("50", 50),
                        ("30", 30),
                        ("20", 20),
                        ("10", 10))

            datapath = "tool_settings.particle_edit.brush.size"
            proppath = bpy.context.tool_settings.particle_edit.brush

        else:
            settings = (("200", 200),
                        ("150", 150),
                        ("100", 100),
                        ("50", 50),
                        ("35", 35),
                        ("10", 10))

            datapath = "tool_settings.unified_paint_settings.size"
            proppath = bpy.context.tool_settings.unified_paint_settings

        return settings, datapath, proppath

    def draw(self, context):
        settings, datapath, proppath = self.init()
        layout = self.layout

        # add the top slider
        layout.row().prop(proppath, "size", slider=True)
        layout.row().separator()

        # add the rest of the menu items
        for i in range(len(settings)):
            utils_core.menuprop(
                    layout.row(), settings[i][0], settings[i][1],
                    datapath, icon='RADIOBUT_OFF', disable=True,
                    disable_icon='RADIOBUT_ON'
                    )


class BrushStrengthMenu(Menu):
    bl_label = "Strength"
    bl_idname = "VIEW3D_MT_sv3_brush_strength_menu"

    def init(self):
        mode = utils_core.get_mode()
        settings = (("1.0", 1.0),
                    ("0.7", 0.7),
                    ("0.5", 0.5),
                    ("0.3", 0.3),
                    ("0.2", 0.2),
                    ("0.1", 0.1))

        proppath = utils_core.get_brush_link(bpy.context, types="brush")

        if mode == 'SCULPT':
            datapath = "tool_settings.sculpt.brush.strength"

        elif mode == 'VERTEX_PAINT':
            datapath = "tool_settings.vertex_paint.brush.strength"

        elif mode == 'WEIGHT_PAINT':
            datapath = "tool_settings.weight_paint.brush.strength"

        elif mode == 'TEXTURE_PAINT':
            datapath = "tool_settings.image_paint.brush.strength"

        else:
            datapath = "tool_settings.particle_edit.brush.strength"
            proppath = bpy.context.tool_settings.particle_edit.brush

        return settings, datapath, proppath

    def draw(self, context):
        settings, datapath, proppath = self.init()
        layout = self.layout

        # add the top slider
        if proppath:
            layout.row().prop(proppath, "strength", slider=True)
            layout.row().separator()

            # add the rest of the menu items
            for i in range(len(settings)):
                utils_core.menuprop(
                        layout.row(), settings[i][0], settings[i][1],
                        datapath, icon='RADIOBUT_OFF', disable=True,
                        disable_icon='RADIOBUT_ON'
                        )
        else:
            layout.row().label(text="No brushes available", icon="INFO")


class BrushModeMenu(Menu):
    bl_label = "Brush Mode"
    bl_idname = "VIEW3D_MT_sv3_brush_mode_menu"

    def init(self):
        mode = utils_core.get_mode()
        has_brush = utils_core.get_brush_link(bpy.context, types="brush")

        if mode == 'SCULPT':
            enum = has_brush.bl_rna.properties['sculpt_plane'].enum_items if \
                   has_brush else None
            path = "tool_settings.sculpt.brush.sculpt_plane"

        elif mode == 'VERTEX_PAINT':
            enum = has_brush.bl_rna.properties['blend'].enum_items if \
                   has_brush else None
            path = "tool_settings.vertex_paint.brush.blend"

        elif mode == 'WEIGHT_PAINT':
            enum = has_brush.bl_rna.properties['blend'].enum_items if \
                   has_brush else None
            path = "tool_settings.weight_paint.brush.blend"

        elif mode == 'TEXTURE_PAINT':
            enum = has_brush.bl_rna.properties['blend'].enum_items if \
                   has_brush else None
            path = "tool_settings.image_paint.brush.blend"

        else:
            enum = None
            path = ""

        return enum, path

    def draw(self, context):
        enum, path = self.init()
        layout = self.layout
        colum_n = utils_core.addon_settings()

        layout.row().label(text="Brush Mode")
        layout.row().separator()

        if enum:
            if utils_core.get_mode() != 'SCULPT':
                column_flow = layout.column_flow(columns=colum_n)

                # add all the brush modes to the menu
                for brush in enum:
                    utils_core.menuprop(
                            column_flow.row(), brush.name,
                            brush.identifier, path, icon='RADIOBUT_OFF',
                            disable=True, disable_icon='RADIOBUT_ON'
                            )
            else:
                # add all the brush modes to the menu
                for brush in enum:
                    utils_core.menuprop(
                            layout.row(), brush.name,
                            brush.identifier, path, icon='RADIOBUT_OFF',
                            disable=True, disable_icon='RADIOBUT_ON'
                            )
        else:
            layout.row().label(text="No brushes available", icon="INFO")


class BrushAutosmoothMenu(Menu):
    bl_label = "Autosmooth"
    bl_idname = "VIEW3D_MT_sv3_brush_autosmooth_menu"

    def init(self):
        settings = (("1.0", 1.0),
                    ("0.7", 0.7),
                    ("0.5", 0.5),
                    ("0.3", 0.3),
                    ("0.2", 0.2),
                    ("0.1", 0.1))

        return settings

    def draw(self, context):
        settings = self.init()
        layout = self.layout
        has_brush = utils_core.get_brush_link(context, types="brush")

        if has_brush:
            # add the top slider
            layout.row().prop(has_brush, "auto_smooth_factor", slider=True)
            layout.row().separator()

            # add the rest of the menu items
            for i in range(len(settings)):
                utils_core.menuprop(
                        layout.row(), settings[i][0], settings[i][1],
                        "tool_settings.sculpt.brush.auto_smooth_factor",
                        icon='RADIOBUT_OFF', disable=True,
                        disable_icon='RADIOBUT_ON'
                        )
        else:
            layout.row().label(text="No Smooth options available", icon="INFO")


class BrushWeightMenu(Menu):
    bl_label = "Weight"
    bl_idname = "VIEW3D_MT_sv3_brush_weight_menu"

    def init(self):
        settings = (("1.0", 1.0),
                    ("0.7", 0.7),
                    ("0.5", 0.5),
                    ("0.3", 0.3),
                    ("0.2", 0.2),
                    ("0.1", 0.1))

        if utils_core.get_mode() == 'WEIGHT_PAINT':
            brush = bpy.context.tool_settings.unified_paint_settings
            brushstr = "tool_settings.unified_paint_settings.weight"
            name = "Weight"

        else:
            brush = bpy.context.tool_settings.image_paint.brush
            brushstr = "tool_settings.image_paint.brush.weight"
            name = "Mask Value"

        return settings, brush, brushstr, name

    def draw(self, context):
        settings, brush, brushstr, name = self.init()
        layout = self.layout

        if brush:
            # add the top slider
            layout.row().prop(brush, "weight", text=name, slider=True)
            layout.row().separator()

            # add the rest of the menu items
            for i in range(len(settings)):
                utils_core.menuprop(
                        layout.row(), settings[i][0], settings[i][1],
                        brushstr,
                        icon='RADIOBUT_OFF', disable=True,
                        disable_icon='RADIOBUT_ON'
                        )
        else:
            layout.row().label(text="No brush available", icon="INFO")


class ParticleCountMenu(Menu):
    bl_label = "Count"
    bl_idname = "VIEW3D_MT_sv3_particle_count_menu"

    def init(self):
        settings = (("50", 50),
                    ("25", 25),
                    ("10", 10),
                    ("5", 5),
                    ("3", 3),
                    ("1", 1))

        return settings

    def draw(self, context):
        settings = self.init()
        layout = self.layout

        # add the top slider
        layout.row().prop(context.tool_settings.particle_edit.brush,
                             "count", slider=True)
        layout.row().separator()

        # add the rest of the menu items
        for i in range(len(settings)):
            utils_core.menuprop(
                    layout.row(), settings[i][0], settings[i][1],
                    "tool_settings.particle_edit.brush.count",
                    icon='RADIOBUT_OFF', disable=True,
                    disable_icon='RADIOBUT_ON'
                    )


class ParticleLengthMenu(Menu):
    bl_label = "Length Mode"
    bl_idname = "VIEW3D_MT_sv3_particle_length_menu"

    def draw(self, context):
        layout = self.layout
        path = "tool_settings.particle_edit.brush.length_mode"

        # add the menu items
        for item in context.tool_settings.particle_edit.brush. \
          bl_rna.properties['length_mode'].enum_items:
            utils_core.menuprop(
                    layout.row(), item.name, item.identifier, path,
                    icon='RADIOBUT_OFF',
                    disable=True,
                    disable_icon='RADIOBUT_ON'
                    )


class ParticlePuffMenu(Menu):
    bl_label = "Puff Mode"
    bl_idname = "VIEW3D_MT_sv3_particle_puff_menu"

    def draw(self, context):
        layout = self.layout
        path = "tool_settings.particle_edit.brush.puff_mode"

        # add the menu items
        for item in context.tool_settings.particle_edit.brush. \
          bl_rna.properties['puff_mode'].enum_items:
            utils_core.menuprop(
                    layout.row(), item.name, item.identifier, path,
                    icon='RADIOBUT_OFF',
                    disable=True,
                    disable_icon='RADIOBUT_ON'
                    )


class FlipColorsAll(Operator):
    """Switch between Foreground and Background colors"""
    bl_label = "Flip Colors"
    bl_idname = "view3d.sv3_flip_colors_all"
    bl_description = "Switch between Foreground and Background colors"

    is_tex: BoolProperty(
                default=False,
                options={'HIDDEN'}
                )

    def execute(self, context):
        try:
            if self.is_tex is False:
                color = context.tool_settings.vertex_paint.brush.color
                secondary_color = context.tool_settings.vertex_paint.brush.secondary_color

                orig_prim = color.hsv
                orig_sec = secondary_color.hsv

                color.hsv = orig_sec
                secondary_color.hsv = orig_prim
            else:
                color = context.tool_settings.image_paint.brush.color
                secondary_color = context.tool_settings.image_paint.brush.secondary_color

                orig_prim = color.hsv
                orig_sec = secondary_color.hsv

                color.hsv = orig_sec
                secondary_color.hsv = orig_prim

            return {'FINISHED'}

        except Exception as e:
            utils_core.error_handlers(self, "view3d.sv3_flip_colors_all", e,
                                     "Flip Colors could not be completed")

            return {'CANCELLED'}


class ColorPickerPopup(Operator):
    """Open Color Picker"""
    bl_label = "Color"
    bl_idname = "view3d.sv3_color_picker_popup"
    bl_description = "Open Color Picker"
    bl_options = {'REGISTER'}

    @classmethod
    def poll(self, context):
        return utils_core.get_mode() in (
                        'VERTEX_PAINT',
                        'TEXTURE_PAINT'
                        )

    def check(self, context):
        return True

    def init(self):
        if utils_core.get_mode() == 'TEXTURE_PAINT':
            settings = bpy.context.tool_settings.image_paint
            brush = getattr(settings, "brush", None)
        else:
            settings = bpy.context.tool_settings.vertex_paint
            brush = settings.brush
            brush = getattr(settings, "brush", None)

        return settings, brush

    def draw(self, context):
        layout = self.layout
        settings, brush = self.init()


        if brush:
            layout.row().template_color_picker(brush, "color", value_slider=True)
            prim_sec_row = layout.row(align=True)
            prim_sec_row.prop(brush, "color", text="")
            prim_sec_row.prop(brush, "secondary_color", text="")

            if utils_core.get_mode() == 'VERTEX_PAINT':
                prim_sec_row.operator(
                                FlipColorsAll.bl_idname,
                                icon='FILE_REFRESH', text=""
                                ).is_tex = False
            else:
                prim_sec_row.operator(
                                FlipColorsAll.bl_idname,
                                icon='FILE_REFRESH', text=""
                                ).is_tex = True

            if settings.palette:
                layout.column().template_palette(settings, "palette", color=True)

            layout.row().template_ID(settings, "palette", new="palette.new")
        else:
            layout.row().label(text="No brushes currently available", icon="INFO")

            return

    def execute(self, context):
        return context.window_manager.invoke_popup(self, width=180)


classes = (
    BrushOptionsMenu,
    BrushRadiusMenu,
    BrushStrengthMenu,
    BrushModeMenu,
    BrushAutosmoothMenu,
    BrushWeightMenu,
    ParticleCountMenu,
    ParticleLengthMenu,
    ParticlePuffMenu,
    FlipColorsAll,
    ColorPickerPopup
    )

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

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