# Copyright (c) 2018-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.
#
__all__ = ["StageExtension"]

import asyncio
import omni.ext
import omni.kit.ui
import omni.ui as ui
from omni.kit.menu.utils import MenuItemDescription
from .stage_window import StageWindow


class StageExtension(omni.ext.IExt):
    """The entry point for Stage Window"""

    WINDOW_NAME = "Stage"
    MENU_GROUP = "Window"

    def on_startup(self):
        self._window = None
        ui.Workspace.set_show_window_fn(StageExtension.WINDOW_NAME, self.show_window)

        self._menu = [MenuItemDescription(
            name=StageExtension.WINDOW_NAME,
            ticked=True,                # menu item is ticked
            ticked_fn=self._is_visible, # gets called when the menu needs to get the state of the ticked menu
            onclick_fn=self._toggle_window
        )]
        omni.kit.menu.utils.add_menu_items(self._menu, name=StageExtension.MENU_GROUP)

        ui.Workspace.show_window(StageExtension.WINDOW_NAME)

    def on_shutdown(self):
        omni.kit.menu.utils.remove_menu_items(self._menu, name=StageExtension.MENU_GROUP)
        self._menu = None
        if self._window:
            self._window.destroy()
            self._window = None

        ui.Workspace.set_show_window_fn(StageExtension.WINDOW_NAME, None)

    def _set_menu(self, value):
        """Set the menu to create this window on and off"""
        # this only tags test menu to update when menu is opening, so it
        # doesn't matter that is called before window has been destroyed
        omni.kit.menu.utils.refresh_menu_items(StageExtension.MENU_GROUP)

    async def _destroy_window_async(self):
        # wait one frame, this is due to the one frame defer
        # in Window::_moveToMainOSWindow()
        await omni.kit.app.get_app().next_update_async()
        if self._window:
            self._window.destroy()
            self._window = None

    def _visiblity_changed_fn(self, visible):
        self._set_menu(visible)
        if not visible:
            # Destroy the window, since we are creating new window
            # in show_window
            asyncio.ensure_future(self._destroy_window_async())

    def show_window(self, value):
        if value:
            self._window = StageWindow()
            self._window.set_visibility_changed_listener(self._visiblity_changed_fn)
        elif self._window:
            self._window.visible = False

    def _is_visible(self) -> bool:
        return False if self._window is None else self._window.visible

    def _toggle_window(self):
        if self._is_visible():
            self.show_window(False)
        else:
            self.show_window(True)
