# ##### BEGIN GPL LICENSE BLOCK #####
#
#  Copyright (C) 2022 VFX Grace - All Rights Reserved
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
# ##### END GPL LICENSE BLOCK #####

import bpy
from bpy.types import PropertyGroup
from bpy.props import (BoolProperty, FloatProperty, EnumProperty, IntProperty,
                       FloatVectorProperty, StringProperty, PointerProperty)
from .draw_hair import show_hair_color


def get_enum_item_num(enum_items, value, default):
    for ei in enum_items:
        if ei[0] == value:
            return ei[3]
    return default


OrientModeEnumItems = [('ORIENT', "Orient", "Use orient mode", 0),
                       ('SUNDER', "Sunder", "Use sunder mode", 1),
                       ('REPEL', "Repel", "Use repel mode", 2)]

WeightModeEnumItems = [('DEFAULT', "Default", "Default weight brush", 0),
                       ('INCREASE', "Increase", "Increase weight", 1),
                       ('DECREASE', "Decrease", "Decrease weight", 2),
                       ('BLUR', "Smooth", "Smooth weight", 3)]

CloneCoordinateEnumItems = [("VIEW", "View", "Use view coordinate", 0),
                            ("HAIR", "Hair", "Use clone hair coordinate", 1),
                            ("BRUSH", "Brush", "Use clone brush coordinate", 2)]

NoiseFlagDict = {
    'use_lock_x': 1 << 2,
    'use_lock_y': 1 << 3,
    'use_lock_z': 1 << 4,
    'use_rough': 1 << 5,
    'reset_pose': 1 << 6,
    'automatic_seed': 1 << 7
}


class HairColorFlag:
    OP_ASSIGN = 0
    OP_DELETE = 1
    OP_SELECT_ONLY = 2
    OP_SELECT_ADD = 3


def get_noise_flag(hb3):
    flag = 0
    for key, v in NoiseFlagDict.items():
        if getattr(hb3, key, 0):
            flag |= v
    return flag


class HairBrush3DCommonProps(PropertyGroup):
    def show_color_updated(self, context):
        show_hair_color(context, self.show_hair_color)
        context.area.tag_redraw()

    @classmethod
    def get_brush_data(cls, hb3):
        if hb3.brush_data:
            return hb3.brush_data
        elif "ParticleToolBrush" in bpy.data.brushes:
            return bpy.data.brushes['ParticleToolBrush']
        else:
            return bpy.data.brushes.new("ParticleToolBrush", mode='PARTICLE_EDIT')

    auto_switch_mode: BoolProperty(
        name="Auto Switch",
        description="Enable auto switch",
        default=True)

    scale_size: BoolProperty(
        name="Brush Scale",
        description="Toggle between 2D space and 3D space where the brush is in when zooming",
        default=False)

    use_3d_brush: BoolProperty(
        name="Enable 3D Brush",
        default=True)

    strength_adjust: FloatProperty(
        name="Strength-3D",
        description="Control the strength of the brush in 3D mode, multiplied by the value of Strength",
        min=0.001,
        max=1.0,
        default=1.0,
        subtype='FACTOR')

    smooth_mode: EnumProperty(
        name="Smooth Mode",
        items=[('SHAPE', "Default", "Default smooth brush", 0),
               ('LENGTH', "Length", "Smooth the length of hair", 1)])

    limited_length: FloatProperty(
        name="Target Length",
        description="Maximum or minimum length",
        min=0.0,
        default=0.0)

    orient_mode: EnumProperty(
        name="Orient Mode",
        items=OrientModeEnumItems)

    curving: FloatProperty(
        name="Curve",
        description="Curve strength",
        min=0,
        max=1,
        default=0,
        subtype='FACTOR')

    weight_mode: EnumProperty(
        name="Weight Mode",
        items=WeightModeEnumItems)

    attract_method: EnumProperty(
        name="Attract Method",
        items=[("HEAD", "HEAD", "Attract from hair tip", 0),
               ("SYNC", "ROOT", "Attract from hair root", 1)])

    continuous_attract: BoolProperty(
        name="Continuous Attract",
        default=False)

    random_control: FloatProperty(
        name="Random Control",
        min=0,
        max=1,
        default=0)

    percent_control: FloatProperty(
        name="Range Control",
        min=0.001,
        max=1,
        default=1,
        precision=3)

    attract_mode: EnumProperty(
        name="Attract Mode",
        items=[("POINT", "Hair", "Set the closest hair to the brush as target", 0),
               ("CENTER", "Brush", "Set the center of the brush as target", 1)])

    use_rough: BoolProperty(
        name="Use Roughness",
        default=False)

    reset_pose: BoolProperty(
        name="Fix Shape",
        default=False)

    automatic_seed: BoolProperty(
        name="Auto Seeding",
        description="Change Seed with per stroke",
        default=False)

    use_lock_x: BoolProperty(
        name="X",
        description="Lock X axis",
        default=False)
    use_lock_y: BoolProperty(
        name="Y",
        description="Lock Y axis",
        default=False)
    use_lock_z: BoolProperty(
        name="Z",
        description="Lock Z axis",
        default=False)

    rough_seed: IntProperty(
        name="Seed",
        min=0,
        default=0,
        description="Random seed of roughness")

    head_strength: FloatProperty(
        name="Head Strength",
        min=0.001,
        max=1,
        default=0.1,
        precision=3)

    middle_strength: FloatProperty(
        name="Middle Strength",
        min=0,
        max=1,
        default=0.1,
        precision=3)

    unprojected_rad: FloatProperty(
        name="Unprojected Radius",
        min=0.001,
        soft_max=1,
        step=1,
        precision=-1,
        subtype='DISTANCE')

    clone_mode: EnumProperty(
        name="Clone Mode",
        items=[("CLONE_DRAW", "Clone_Draw", "Clone the source", 0),
               ("CLONE_SOURCE", "Clone_Source", "Set clone source", 1)])

    clone_coordinate: EnumProperty(
        name="Clone Coordinate",
        items=CloneCoordinateEnumItems)

    clone_rotation_angle: FloatProperty(
        name="Rotation Angle",
        min=-360,
        max=360,
        default=0,
        precision=1,
        description="Set the angle of rotation")

    clone_realtime_show: BoolProperty(
        name="Preview Source",
        description="Show the source in real time",
        default=False)

    update_color_realtime: BoolProperty(
        name="Real-time Update",
        description="Enable it to update the color in real time. Disable it to update the color after releasing mouse. Note, too much hair may cause freezing UI when enabled",
        default=True)

    brush_color: FloatVectorProperty(
        name="Brush Color", min=0.0, max=1.0,
        default=(1.0, 1.0, 1.0),
        description="The color of the brush",
        size=3, subtype="COLOR")

    show_hair_color: BoolProperty(
        name="Show Hair Color",
        description="Show hair color",
        default=False,
        update=show_color_updated)

    falloff_shape: EnumProperty(
        name="Falloff Shape",
        description="Use projected or spherical falloff",
        items=[("SPHERE", "Sphere", "Apply brush influence in a Sphere, outwards from the center", 0),
               ("PROJECTED", "Projected", "Apply brush influence in a 2D circle, projected from the view", 1)])

    brush_data: PointerProperty(
        name="Brush Data",
        type=bpy.types.Brush
    )

    @classmethod
    def register(cls):
        bpy.types.Scene.hair_brush_3d = bpy.props.PointerProperty(type=cls)

    @classmethod
    def unregister(cls):
        del bpy.types.Scene.hair_brush_3d


class HairColorGroup(PropertyGroup):
    def get_color(self):
        return self.rgb

    def set_color(self, val):
        return

    name: StringProperty(name="color_index")
    rgb: FloatVectorProperty(min=0.0, max=1.0, default=(1.0, 1.0, 1.0),
                             subtype="COLOR")

    rgb_show: FloatVectorProperty(size=3, subtype="COLOR", get=get_color, set=set_color)

    @classmethod
    def register(cls):
        bpy.types.ParticleSettings.hair_color_groups = bpy.props.CollectionProperty(type=HairColorGroup)
        bpy.types.ParticleSettings.color_group_idx = IntProperty(name="color_group_idx", default=0)

    @classmethod
    def unregister(cls):
        del bpy.types.ParticleSettings.hair_color_groups
        del bpy.types.ParticleSettings.color_group_idx
