''' Replaces the default vertex group panel with a Blabels panel.

Adds the ability to sort vertex groups by labels.  Additional features may
be forthcoming.'''

'''
*******************************************************************************
    License and Copyright
    Copyright 2012 Jordan Hueckstaedt
    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 <http://www.gnu.org/licenses/>.
'''

import bpy
from bpy.types import Menu, Panel, UIList
from .blabels import *


class Vertex_Group_Blables(Blabels):
    @property
    def labels(self):
        return self.context.object.vertex_group_labels

    @property
    def selected_items(self):
        return self.context.object.selected_vertex_group

    @property
    def active_index(self):
        return self.co
ntext.object.active_vertex_group_label_index

    @active_index.setter
    def active_index(self, index):
        self.context.object.active_vertex_grou
p_label_index = index

    @property
    def active_item_index(self):
        return self.context.object.vertex_groups.active_index

    @active_item_index.setter
    def active_item_index(self, index):
        self.context.object.vertex_groups.active_index = index

    @property
    def items(self):
        obj = self.context.object
        return obj.vertex_groups

    @property
    def view_mode(self):
        return self.context.scene.vertex_group_view_mode

    @view_mode.setter
    def view_mode(self, mode):
        context.scene.vertex_group_view_mode = mode.upper()

    def add_item_orig(self, **add_item_kwargs):
        # I don't believe vertex groups have an optional parameter here yet.
        bpy.ops.object.vertex_group_add(**add_item_kwargs)

    def remove_item_orig(self, **remove_item_kwargs):
        bpy.ops.object.vertex_group_remove(**remove_item_kwargs)

    def move_item_orig(self, **move_item_kwargs):
        # move_item_kwargs: type = self.type
        bpy.ops.object.vertex_groups.move(**move_item_kwargs)

    def get_armature_groups(self):
        obj = self.context.object

        # Find armature group.
        bones = []
        armatures = 0
        for mod in obj.modifiers:
            if mod.type == 'ARMATURE' and mod.use_vertex_groups and mod.object:
                    bones = [bone.name for bone in mod.object.data.bones]
                    armatures += 1
                    if armatures == 2:
                        break

        # Get bone indexes
        return [group.index for group in obj.vertex_groups if group.name in bones]

    def filter_view_mode(self, indexes, selected):
        # Filter "ALL" label by view mode
        view_mode = self.view_mode
        items = self.items
        if view_mode == 'LOCKED':
            indexes = [i for i in indexes if items[i].lock_weight]
            selected = [i for i in selected if i in indexes]
        elif view_mode == 'UNLOCKED':
            indexes = [i for i in indexes if not items[i].lock_weight]
            selected = [i for i in selected if i in indexes]
        elif view_mode == 'ARMATURE':
            armature_groups = set(self.get_armature_groups())
            indexes = [i for i in indexes if i in armature_groups]
            selected = [i for i in selected if i in indexes]
        return indexes, selected

    def toggle_locked_item(self, inverse=False):
        items = self.items
        indexes, selected = self.get_visible_item_indexes()

        if inverse:
            # Hide or show all
            if any(1 for i in indexes if items[i].lock_weight):
                for i in indexes:
                    items[i].lock_weight = False
            else:
                for i in indexes:
                    items[i].lock_weight = True
        else:
            # Inverse Visible
            for i in indexes:
                items[i].lock_weight = not items[i].lock_weight


def get_selected_groups():
    ''' Easy access wrapper for Vertex_Group_Blables '''
    items = Vertex_Group_Blables().selected_items
    return [i.index for i in items]


def get_active_group():
    ''' Easy access wrapper for Vertex_Group_Blables '''
    return Vertex_Group_Blables().active_item_index


################################
##    UI classes - thin wrappers for Vertex_Group_Blables
def label_poll(context, test_groups=False, test_mode=True):
    # Simple function for most the poll methods in this module
    obj = context.object
    if not (obj and obj.type in {'MESH', 'LATTICE', 'CURVE', 'SURFACE'} and
            context.scene.render.engine in {'BLENDER_RENDER', 'BLENDER_GAME'}):
        return False

    if test_mode and context.mode == 'EDIT_MESH':
        return False

    if test_groups:
        return bool(Vertex_Group_Blables().items)

    return True


class VertexGroupsLabelAdd(bpy.types.Operator):
    bl_idname = "object.vertex_groups_label_add"
    bl_label = "Add Label"
    bl_description = "Add Label"
    bl_options = {'REGISTER', 'UNDO'}

    @classmethod
    def poll(cls, context):
        return label_poll(context, test_mode=False)

    def execute(self, context):
        Vertex_Group_Blables(context).add()
        return {'FINISHED'}


class VertexGroupsLabelRemove(bpy.types.Operator):
    bl_idname = "object.vertex_groups_label_remove"
    bl_label = "Remove Label"
    bl_description = "Remove Label"
    bl_options = {'REGISTER', 'UNDO'}

    @classmethod
    def poll(cls, context):
        return label_poll(context, test_mode=False)

    def execute(self, context):
        copied_to = Vertex_Group_Blables(context).remove()
        return {'FINISHED'}


class VertexGroupsLabelMove(bpy.types.Operator):
    bl_idname = "object.vertex_groups_label_move"
    bl_label = "Move Label"
    bl_description = "Move Label"
    bl_options = {'REGISTER', 'UNDO'}

    direction = bpy.props.EnumProperty(
        name="Move Label Direction",
        items = (
                    ('UP', "Up", "Up"),
                    ('DOWN', "Down", "Down"),
               ),
        default = 'UP'
       )

    @classmethod
    def poll(cls, context):
        return label_poll(context, test_mode=False)

    def execute(self, context):
        Vertex_Group_Blables(context).move(direction=self.direction)
        return {'FINISHED'}


class VertexGroupsSetIndex(bpy.types.Operator):
    bl_idname = "object.vertex_groups_set_index"
    bl_label = "Set Active Vertex Groups"
    bl_description = "Set Active Vertex Groups"
    bl_options = {'REGISTER', 'UNDO'}

    index = bpy.props.IntProperty(default=-1)
    shift = bpy.props.BoolProperty(default=False)

    @classmethod
    def poll(cls, context):
        return label_poll(context, test_groups=True, test_mode=False)

    def invoke(self, context, event):
        self.shift = event.shift
        return self.execute(context)

    def execute(self, context):
        Vertex_Group_Blables(context).select_item(self.index, self.shift)
        return {'FINISHED'}


class VertexGroupsCopyToLabel(bpy.types.Operator):
    bl_idname = "object.vertex_groups_copy_to_label"
    bl_label = "Copy To Label"
    bl_description = "Copy To Label"
    bl_options = {'REGISTER', 'UNDO'}

    index = bpy.props.IntProperty(default=-1)

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

    def execute(self, context):
        copied_to = Vertex_Group_Blables(context).copy_item(self.index)
        if copied_to is not None:
            self.report({'INFO'}, "Copied to %s" % copied_to)
        return {'FINISHED'}


class VertexGroupsAddToLabel(bpy.types.Operator):
    bl_idname = "object.vertex_groups_add_to_label"
    bl_label = "Add to Label