# 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.dictionary
import carb.settings
import omni.timeline
import omni.ui as ui
from carb.input import KeyboardInput as Key
from omni.kit.commands import execute
from omni.kit.widget.toolbar.hotkey import Hotkey
from omni.kit.widget.toolbar.widget_group import WidgetGroup

from .models.timeline_model import TimelinePlayPauseModel

PLAY_TOOL_NAME = "Play"
PAUSE_TOOL_NAME = "Pause"

class PlayButtonGroup(WidgetGroup):
    PLAY_ANIMATIONS_SETTING = "/app/player/playAnimations"
    PLAY_AUDIO_SETTING = "/app/player/audio/enabled"
    PLAY_SIMULATIONS_SETTING = "/app/player/playSimulations"
    PLAY_COMPUTEGRAPH_SETTING = "/app/player/playComputegraph"

    all_settings_paths = [
        PLAY_ANIMATIONS_SETTING,
        PLAY_AUDIO_SETTING,
        PLAY_SIMULATIONS_SETTING,
        PLAY_COMPUTEGRAPH_SETTING,
    ]

    def __init__(self):
        super().__init__()
        self._play_button = None
        self._play_hotkey = None
        self._stop_button = None
        self._settings = carb.settings.get_settings()
        self._dict = carb.dictionary.get_dictionary()
        self._timeline_play_pause_model = TimelinePlayPauseModel()
        self._timeline = omni.timeline.get_timeline_interface()

        self._settings.set_default_bool(self.PLAY_ANIMATIONS_SETTING, True)
        self._settings.set_default_bool(self.PLAY_AUDIO_SETTING, True)
        self._settings.set_default_bool(self.PLAY_SIMULATIONS_SETTING, True)
        self._settings.set_default_bool(self.PLAY_COMPUTEGRAPH_SETTING, True)

        stream = self._timeline.get_timeline_event_stream()
        self._sub = stream.create_subscription_to_pop(self._on_timeline_event)
        self._register_context_menu()

        self._show_menu_task = None
        self._visible = True

    def clean(self):
        super().clean()
        self._sub = None
        if self._timeline_play_pause_model:
            self._timeline_play_pause_model.clean()
            self._timeline_play_pause_model = None
        self._play_button = None
        self._stop_button = None
        self._animations_menu = None
        self._audio_menu = None
        self._simulations_menu = None
        self._compute_graph_menu = None
        self._play_filter_menu = None
        self._filter_menu = None
        self._sep_menu = None
        self._sep_menu2 = None
        self._select_all_menu = None
        if self._show_menu_task:  # pragma: no cover
            self._show_menu_task.cancel()
        self._show_menu_task = None
        if self._play_hotkey:
            self._play_hotkey.clean()
            self._play_hotkey = None
        self._visible = True

    def get_style(self):
        style = {
            "Button.Image::play": {"image_url": "${glyphs}/toolbar_play.svg"},
            "Button.Image::play:checked": {"image_url": "${glyphs}/toolbar_pause.svg"},
            "Button.Image::stop": {"image_url": "${glyphs}/toolbar_stop.svg"},
        }
        return style

    def create(self, default_size):
        # Build Play button
        self._play_button = ui.ToolButton(
            model=self._timeline_play_pause_model,
            name="play",
            tooltip=f"{PLAY_TOOL_NAME} ('Space')",
            width=default_size,
            height=default_size,
            mouse_pressed_fn=lambda x, y, b, _: self._on_mouse_pressed(b, "play"),
            mouse_released_fn=lambda x, y, b, _: self._on_mouse_released(b),
            checked=self._timeline_play_pause_model.get_value_as_bool(),
        )

        def on_play_hotkey_changed(hotkey: str):
            if self._play_button:
                self._play_button.tooltip = f"{PLAY_TOOL_NAME} ({hotkey})"

        # Assign Play button Hotkey
        self._play_hotkey = Hotkey(
            "toolbar::play",
            Key.SPACE,
            lambda: self._timeline_play_pause_model.set_value(not self._timeline_play_pause_model.get_value_as_bool()),
            lambda: self._play_button is not None and self._play_button.enabled and self._is_in_context(),
            on_hotkey_changed_fn=lambda hotkey: on_play_hotkey_changed(hotkey),
        )

        self._visible = True

        def on_stop_clicked(*_):
            self._acquire_toolbar_context()
            execute("ToolbarStopButtonClicked")

        self._stop_button = ui.Button(
            name="stop",
            tooltip="Stop",
            width=default_size,
            height=default_size,
            visible=False,
            clicked_fn=on_stop_clicked,
        )

        return {"play": self._play_button, "stop": self._stop_button}

    def _on_setting_changed(self, item, event_type, menu_item):  # pragma: no cover
        menu_item.checked = self._dict.get(item)

    def _on_timeline_event(self, e):
        if e.type == int(omni.timeline.TimelineEventType.PLAY):
            if self._play_button:
                self._play_button.set_tooltip(f"{PAUSE_TOOL_NAME} ({self._play_hotkey.get_as_string('Space')})")
            if self._stop_button:
                self._stop_button.visible = self._visible
        if e.type == int(omni.timeline.TimelineEventType.PAUSE):
            if self._play_button:
                self._play_button.set_tooltip(f"{PLAY_TOOL_NAME} ({self._play_hotkey.get_as_string('Space')})")
        if e.type == int(omni.timeline.TimelineEventType.STOP):
            if self._stop_button:
                self._stop_button.visible = False
            if self._play_button:
                self._play_button.set_tooltip(f"{PLAY_TOOL_NAME} ({self._play_hotkey.get_as_string('Space')})")
        if hasattr(omni.timeline.TimelineEventType, 'DIRECTOR_CHANGED') and\
            e.type == int(omni.timeline.TimelineEventType.DIRECTOR_CHANGED):  # pragma: no cover
            self._visible = not e.payload['hasDirector']
            if self._stop_button:
                self._stop_button.visible = self._visible
            if self._play_button:
                self._play_button.visible = self._visible

    def _on_filter_changed(self, filter_setting, enabled):  # pragma: no cover
        execute("ToolbarPlayFilterChecked", setting_path=filter_setting, enabled=enabled)

    def _select_all(self):  # pragma: no cover
        execute("ToolbarPlayFilterSelectAll", settings=self.all_settings_paths)

    def _register_context_menu(self):
        context_menu = omni.kit.context_menu.get_instance()

        def is_button(objects: dict, button_name: str):  # pragma: no cover
            return objects.get("widget_name", None) == button_name

        def create_menu_entry(name, setting_path):
            menu = {
                "name": name,
                "show_fn": [lambda object: is_button(object, "play")],
                "onclick_fn": lambda object: self._on_filter_changed(
                    setting_path, not self._settings.get(setting_path)
                ),
                "checked_fn": lambda object: self._settings.get(setting_path),
            }

            return omni.kit.context_menu.add_menu(menu, "play", "omni.kit.widget.toolbar")

        def create_seperator(name=""):
            menu = {
                "name": name,
                "show_fn": [lambda object: is_button(object, "play")],
            }
            return omni.kit.context_menu.add_menu(menu, "play", "omni.kit.widget.toolbar")

        if context_menu:
            menu = {
                "name": "Filter",
                "show_fn": [lambda object: is_button(object, "play")],
                "enabled_fn": lambda object: False,
            }
            self._filter_menu = omni.kit.context_menu.add_menu(menu, "play", "omni.kit.widget.toolbar")

            self._sep_menu = create_seperator("sep/")

            self._animations_menu = create_menu_entry("Animation", self.PLAY_ANIMATIONS_SETTING)
            self._audio_menu = create_menu_entry("Audio", self.PLAY_AUDIO_SETTING)
            self._simulations_menu = create_menu_entry("Simulations", self.PLAY_SIMULATIONS_SETTING)
            self._compute_graph_menu = create_menu_entry("OmniGraph", self.PLAY_COMPUTEGRAPH_SETTING)

            self._sep_menu2 = create_seperator("sep2/")

            menu = {
                "name": "Select All",
                "show_fn": [lambda object: is_button(object, "play")],
                "onclick_fn": lambda object: self._select_all(),
            }
            self._select_all_menu = omni.kit.context_menu.add_menu(menu, "play", "omni.kit.widget.toolbar")
