"""
* Copyright (c) 2020, NVIDIA CORPORATION.  All rights reserved.
*
* NVIDIA CORPORATION and its licensors retain all intellectual property
* and proprietary rights in and to this software, related documentation
* and any modifications thereto.  Any use, reproduction, disclosure or
* distribution of this software and related documentation without an express
* license agreement from NVIDIA CORPORATION is strictly prohibited.
"""
import carb
import omni.ui as ui
from . import delegate, model


class FastSearchWidget(object):
    def __init__(self, items_dict):
        self._items_dict = items_dict
        self._is_visible = False
        self._current_selection = []
        self._menus_global_selection = []
        self._tab_first_item_set = False
        self._current_global_selection_index = 0
        self._style = {"Menu.ItemSelected": {"color": 0xFFC8C8C8}, "Menu.ItemUnseleted": {"color": 0xFF646464}}

        self._default_attr = {
            "_model": None,
            "_delegate": None,
            "_window": None,
            "_search_field": None,
            "_tree_view": None,
            "_menu_all": None,
            "_menu_latest": None,
            "_menu_favorites": None,
            "_menu_blocklist": None,
            "_subscription_item_mouse_released": None,
        }
        for attr, value in self._default_attr.items():
            setattr(self, attr, value)

    def create_widget(self):
        """Create the widget UI"""
        self._model = model.SimpleModel(column_count=1)
        self._delegate = delegate.FastSearchDelegate()
        self._window = ui.Window(
            "Graph search",
            width=400,
            height=400,
            flags=ui.WINDOW_FLAGS_POPUP | ui.WINDOW_FLAGS_NO_TITLE_BAR | ui.WINDOW_FLAGS_MENU_BAR,
        )
        menu_bar = self._window.menu_bar
        menu_bar.set_style(self._style)
        with menu_bar:
            self._menu_all = ui.MenuItem(
                "All", triggered_fn=self.show_all, style_type_name_override="Menu.ItemSelected"
            )
            self._menu_latest = ui.MenuItem(
                "Latest", triggered_fn=self.show_only_latest, style_type_name_override="Menu.ItemUnseleted"
            )
            self._menu_favorites = ui.MenuItem(
                "Favorites", triggered_fn=self.show_only_favorites, style_type_name_override="Menu.ItemUnseleted"
            )
            self._menu_blocklist = ui.MenuItem(
                "Blocklist", triggered_fn=self.show_only_blocklist, style_type_name_override="Menu.ItemUnseleted"
            )
            self._menus_global_selection.extend(
                [self._menu_all, self._menu_latest, self._menu_favorites, self._menu_blocklist]
            )
        self._window.frame.set_key_pressed_fn(self.__on_key_pressed)
        with self._window.frame:
            with ui.VStack():
                with ui.Frame(height=20):
                    with ui.VStack():
                        self._search_field = ui.StringField()
                        self._search_field.model.add_value_changed_fn(self._filter)
                ui.Spacer(height=5)
                with ui.ScrollingFrame(
                    horizontal_scrollbar_policy=ui.ScrollBarPolicy.SCROLLBAR_ALWAYS_OFF,
                    vertical_scrollbar_policy=ui.ScrollBarPolicy.SCROLLBAR_ALWAYS_ON,
                    style_type_name_override="TreeView",
                ):
                    self._tree_view = ui.TreeView(
                        self._model,
                        delegate=self._delegate,
                        root_visible=False,
                        header_visible=False,
                        style={"TreeView.Item": {"margin": 4}},
                    )
                    self._tree_view.set_selection_changed_fn(self._on_widget_attr_selection_changed)
        self._model.set_items(
            "items", [model.SimpleItem(self._model, ui.SimpleStringModel(attr)) for attr in self._items_dict.keys()]
        )
        self._model.previous_items = self._model.items

        self._subscription_item_mouse_released = self._model.subscribe_item_mouse_released(
            self.item_mouse_released
        )

        self._select_first_item()

    def show_all(self):
        print("show all")

    def show_only_latest(self):
        print("show latest")

    def show_only_favorites(self):
        print("show favorites")

    def show_only_blocklist(self):
        print("show blocklist")

    def _select_first_item(self):
        """Select first item of the list"""
        if self._model.items:
            self._tree_view.selection = [self._model.items[0]]

    def _select_down_item(self):
        """Select the item down"""
        if self._tree_view.selection:
            current_index = self._model.items.index(self._tree_view.selection[-1])
            index = current_index + 1
            if index >= len(self._model.items) - 1:
                index = len(self._model.items) - 1
            self._tree_view.selection = [self._model.items[index]]

    def _select_up_item(self):
        """Select the item up"""
        if self._tree_view.selection:
            current_index = self._model.items.index(self._tree_view.selection[-1])
            index = current_index - 1
            if index <= 0:
                index = 0
            self._tree_view.selection = [self._model.items[index]]

    def _filter(self, str_model):
        """Filter from the windows"""
        # set the global mode (all, latest...)
        if self._current_global_selection_index == 0:
            self._model.items = self._model.previous_items
            self._model.refresh()
        elif self._current_global_selection_index == 1:
            self._model.items = self._model.latest
            self._model.refresh()
        elif self._current_global_selection_index == 2:
            self._model.items = self._model.favorites
            self._model.refresh()
        elif self._current_global_selection_index == 3:
            self._model.items = self._model.blocklist
            self._model.refresh()

        value = str_model.get_value_as_string()
        if not value.strip():
            self._select_first_item()
            return
        items = []
        for item in self._model.items:
            current_attr = item.name.get_value_as_string()
            if value.lower() not in current_attr.lower():
                continue
            items.append(item)
        if not items:
            self._model.items = []
            self._model.refresh()
            return
        self._model.items = items
        self._model.refresh()
        self._select_first_item()

    def _on_widget_attr_selection_changed(self, selection):
        """Fill self.current_attrs_selection when the selection change
        into the attribute chooser"""
        self._current_selection = selection

    def set_window_visible(self, visible):
        """Set the widget visible"""
        self._window.visible = visible
        if visible:
            self._search_field.model.set_value("")
            self._search_field.focus_keyboard()
            self._select_first_item()

    def item_mouse_released(self, item):
        self.execute_item(item)

    def __key_enter_pressed(self):
        """Called when key enter is pressed.
        Add the item in the latest list"""
        if self.is_visible:
            if self._current_selection:
                self.execute_item(self._current_selection[0])

    def execute_item(self, item):
        selection_str = item.name.get_value_as_string()
        self._items_dict[selection_str]()
        current_latest = [x.name.get_value_as_string() for x in self._model.latest]
        if not current_latest or current_latest[-1] != selection_str:
            if selection_str in current_latest:
                current_latest.remove(selection_str)
            current_latest.insert(0, selection_str)
            self._model.set_items(
                "latest", [model.SimpleItem(self._model, ui.SimpleStringModel(attr)) for attr in current_latest]
            )
        self.set_window_visible(False)

    def __key_escape_pressed(self):
        if self.is_visible:
            self.set_window_visible(False)
            self._tab_first_item_set = False

    def __key_tab_pressed(self):
        """Roll modes"""
        if self.is_visible and self._model.items and not self._tab_first_item_set:
            selection_str = self._current_selection[0].name.get_value_as_string()
            self._search_field.model.set_value(selection_str)
            self._tab_first_item_set = True
        elif self.is_visible and self._model.items and self._tab_first_item_set:
            self.__key_enter_pressed()
            self._tab_first_item_set = False

    def __key_ctrl_tab_pressed(self):
        """Roll modes"""
        if self.is_visible:
            if self._current_global_selection_index == len(self._menus_global_selection) - 1:
                self._current_global_selection_index = 0
            else:
                self._current_global_selection_index += 1
            for i, menu in enumerate(self._menus_global_selection):
                if i == self._current_global_selection_index:
                    menu.style_type_name_override = "Menu.ItemSelected"
                else:
                    menu.style_type_name_override = "Menu.ItemUnseleted"
            self._filter(self._search_field.model)

    def __key_select_down_pressed(self):
        if self.is_visible:
            self._select_down_item()

    def __key_select_up_pressed(self):
        if self.is_visible:
            self._select_up_item()

    def __on_key_pressed(self, key_index, key_flags, key_down):
        key_mod = key_flags & ~ui.Widget.FLAG_WANT_CAPTURE_KEYBOARD
        if key_index == int(carb.input.KeyboardInput.ESCAPE) and key_mod == 0 and key_down:
            self.__key_escape_pressed()
        if key_index == int(carb.input.KeyboardInput.DOWN) and key_mod == 0 and key_down:
            self.__key_select_down_pressed()
        if key_index == int(carb.input.KeyboardInput.UP) and key_mod == 0 and key_down:
            self.__key_select_up_pressed()
        if key_index == int(carb.input.KeyboardInput.ENTER) and key_mod == 0 and key_down:
            self.__key_enter_pressed()
        if key_index == int(carb.input.KeyboardInput.TAB) and key_mod == 0 and key_down:
            self.__key_tab_pressed()
        if key_index == int(carb.input.KeyboardInput.TAB) and key_mod == 2 and key_down:
            self.__key_ctrl_tab_pressed()
        if key_index == int(carb.input.KeyboardInput.BACKSPACE) and key_mod == 0 and key_down:
            self._tab_first_item_set = False

    @property
    def is_visible(self):
        return self._window.visible

    def destroy(self):
        """Delete the UI"""
        for attr, value in self._default_attr.items():
            m_attr = getattr(self, attr)
            del m_attr
            setattr(self, attr, value)
