# AUTOGENERATED! DO NOT EDIT! File to edit: nbs/02a_right_menu_widget.ipynb (unless otherwise specified).

__all__ = []

# Internal Cell
from ipywidgets import HBox, Dropdown, Layout, VBox, Checkbox
from functools import partial
from typing import List, Optional, Callable
from .custom_input.coordinates import CoordinateInput
from .mltypes import BboxCoordinate, BboxVideoCoordinate
from .custom_input.buttons import ActionButton

# Internal Cell

class BBoxItem(VBox):
    """BBox row with select button, coordinates inputs and delete button"""

    def __init__(
        self,
        bbox_coord: BboxCoordinate,
        max_coord_input_values: Optional[BboxCoordinate],
        index: int,
        options: List[str] = None,
        readonly: bool = False
    ):
        super().__init__()

        self.readonly = readonly
        self.bbox_coord = bbox_coord
        self.index = index
        self._max_coord_input_values = max_coord_input_values
        self.layout = Layout(display='flex', overflow='hidden')
        self.dropdown_classes = self._dropdown_classes(options)
        self.btn_select = self._btn_select(index)
        self.input_coordinates = self._coordinate_inputs(bbox_coord)

        elements = [
            self.btn_select,
            self.dropdown_classes,
            self.input_coordinates,
        ]

        if not self.readonly:
            self.btn_delete = self._btn_delete(index)
            elements.append(self.btn_delete)

        self.children = [HBox(elements)]

    def _btn_delete(self, index: int) -> ActionButton:
        return ActionButton(
            layout=Layout(width='auto'),
            icon="trash",
            button_style="danger",
            value=index
        )

    def _dropdown_classes(self, options: Optional[List[str]], value: str = None) -> Dropdown:
        return Dropdown(
            layout=Layout(width='auto'),
            options=options,
            value=value,
            disabled=self.readonly
        )

    def _btn_select(self, index: int) -> ActionButton:
        return ActionButton(
            icon="lightbulb-o",
            layout=Layout(width='auto'),
            value=index
        )

    def _coordinate_inputs(self, bbox_coord: BboxCoordinate):
        return CoordinateInput(
            bbox_coord=bbox_coord,
            input_max=self._max_coord_input_values,
            disabled=self.readonly
        )

# Internal Cell

class BBoxVideoItem(BBoxItem):
    def __init__(
        self,
        bbox_video_coord: BboxVideoCoordinate,
        index: int,
        label: List[str],
        options: List[str],
        selected: bool = False,
        btn_delete_enabled: bool = True,
        readonly: bool = False
    ):
        super(VBox, self).__init__()  # type: ignore
        self.readonly = readonly
        self.selected = selected
        self.bbox_video_coord = bbox_video_coord
        self.object_checkbox = self._object_checkbox()
        self.btn_select = self._btn_select(index)
        self.btn_delete = self._btn_delete(index)
        self.dropdown_classes = self._dropdown_classes(
            options=options,
            value=label[0] if label else None
        )

        self._options = [
            self.object_checkbox,
            self.btn_select,
            self.dropdown_classes,
        ]

        if btn_delete_enabled:
            self._options.append(self.btn_delete)

        self.children = [
            HBox(self._options)
        ]

    def _object_checkbox(self) -> Checkbox:
        return Checkbox(
            value=self.selected,
            indent=False,
            description=str(self.bbox_video_coord.id),
            layout=Layout(width='auto')
        )

# Internal Cell

class BBoxList(VBox):
    """Render the list of bbox items and set the interactions"""

    def __init__(
        self,
        classes: list,
        max_coord_input_values: Optional[BboxCoordinate],
        on_coords_changed: Optional[Callable],
        on_label_changed: Callable,
        on_btn_delete_clicked: Callable,
        on_btn_select_clicked: Optional[Callable],
        readonly: bool = False
    ):
        super().__init__()
        self._classes = classes
        self._max_coord_input_values = max_coord_input_values
        self._on_coords_changed = on_coords_changed
        self._on_btn_delete_clicked = on_btn_delete_clicked
        self._on_label_changed = on_label_changed
        self._on_btn_select_clicked = on_btn_select_clicked
        self.readonly = readonly

    @property
    def max_coord_input_values(self) -> Optional[BboxCoordinate]:
        return self._max_coord_input_values

    @max_coord_input_values.setter
    def max_coord_input_values(self, value: BboxCoordinate):
        for children in self.children:  # type: ignore
            children.input_max = value
        self._max_coord_input_values = value

    def render_btn_list(self, bbox_coords: List[BboxCoordinate], classes: List[List[str]]):
        elements: List[BBoxItem] = []
        num_children = len(self.children)  # type: ignore

        for index, coord in enumerate(bbox_coords[num_children:], num_children):
            bbox_item = BBoxItem(
                index=index,
                options=self._classes,
                bbox_coord=coord,
                max_coord_input_values=self._max_coord_input_values,
                readonly=self.readonly
            )

            if not self.readonly:
                bbox_item.btn_delete.on_click(self.del_element)
            bbox_item.input_coordinates.uuid = index
            bbox_item.input_coordinates.coord_changed = self._on_coords_changed
            bbox_item.btn_select.on_click(self._on_btn_select_clicked)
            if classes and classes[index]:
                bbox_item.dropdown_classes.value = classes[index][0] or None
            bbox_item.dropdown_classes.observe(
                partial(self._on_label_changed, index=index),
                names="value",
            )

            elements.append(bbox_item)

        self.children = [*list(self.children), *elements]  # type: ignore

    def __getitem__(self, index: int):
        return self.children[index]

    def clear(self):
        self.children = []

    def _update_bbox_list_index(self, elements: list, index: int):
        for index, element in enumerate(elements[index:], index):
            # updates select btn
            element.btn_select.value = index
            # update label dropdown
            dropdown = element.dropdown_classes
            dropdown.unobserve_all()
            dropdown.observe(
                partial(self._on_label_changed, index=index),
                names="value"
            )
            # update inputs
            element.children[0].children[2].uuid = index
            # updates delete btn
            element.btn_delete.value = index

    def del_element(self, btn: ActionButton):
        index = btn.value
        elements = list(self.children)
        del elements[index]
        self._update_bbox_list_index(elements, index)
        self.children = elements
        self._on_btn_delete_clicked(index)  # type: ignore

# Internal Cell

class BBoxVideoList(BBoxList):
    def __init__(
        self,
        classes: list,
        on_label_changed: Callable,
        on_btn_delete_clicked: Callable,
        on_btn_select_clicked: Optional[Callable],
        on_checkbox_object_clicked: Callable,
        btn_delete_enabled: bool = True
    ):
        super().__init__(
            classes=classes,
            max_coord_input_values=None,
            on_coords_changed=None,
            on_label_changed=on_label_changed,
            on_btn_delete_clicked=on_btn_delete_clicked,
            on_btn_select_clicked=on_btn_select_clicked
        )
        self.elements: List[BBoxVideoItem] = []
        self._btn_delete_enabled = btn_delete_enabled
        self._on_checkbox_object_clicked = on_checkbox_object_clicked

    # error: Signature of "render_btn_list" incompatible with supertype "BBoxList"
    def render_btn_list(  # type: ignore
        self,
        bbox_video_coords: List[BboxVideoCoordinate],
        classes: list,
        labels: List[List[str]],
        selected: List[int] = []
    ):
        if not bbox_video_coords:
            self.elements.clear()

        for index, bbox_video_coord in enumerate(bbox_video_coords):
            try:
                if self.elements[index]:
                    if self.elements[index].bbox_video_coord.id == bbox_video_coord.id:
                        self.elements[index].bbox_video_coord = bbox_video_coord
                    else:
                        del self.elements[index]
                        for i, _ in enumerate(bbox_video_coords[index:], index):
                            self.elements[i].index = i
            except Exception:
                bbox_item = BBoxVideoItem(
                    index=index,
                    options=self._classes,
                    bbox_video_coord=bbox_video_coord,
                    label=labels[index],
                    selected=index in selected,
                    btn_delete_enabled=self._btn_delete_enabled
                )

                bbox_item.btn_delete.on_click(self.del_element)
                bbox_item.btn_select.on_click(self._on_btn_select_clicked)

                if classes and classes[index]:
                    bbox_item.dropdown_classes.value = classes[index][0] or None

                bbox_item.dropdown_classes.observe(
                    partial(self._on_label_changed, index=index),
                    names="value",
                )

                bbox_item.object_checkbox.observe(
                    partial(
                        self._on_checkbox_object_clicked,
                        index=index,
                        bbox_video_coord=bbox_video_coord
                    ),
                    names="value",
                )

                self.elements.append(bbox_item)

        self.children = self.elements

    def clear(self):
        self.elements = []
        self.children = []

    def _update_bbox_list_index(self, elements: list, index: int):
        for index, element in enumerate(elements[index:], index):
            #updates checkbox
            checkbox = element.object_checkbox
            checkbox.unobserve_all()
            checkbox.observe(
                partial(self._on_checkbox_object_clicked, index=index),
                names="value",
            )
            # updates select btn
            element.btn_select.value = index
            # update label dropdown
            dropdown = element.dropdown_classes
            dropdown.unobserve_all()
            dropdown.observe(
                partial(self._on_label_changed, index=index),
                names="value"
            )
            # updates delete btn
            element.btn_delete.value = index

    def del_element(self, btn: ActionButton):
        index = btn.value
        elements = self.elements
        del elements[index]
        self._update_bbox_list_index(elements, index)
        self.children = elements
        self.elements = elements
        self._on_btn_delete_clicked(index)