## Copyright (c) 2022, 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__ = ['TestViewportReady']


import omni.kit.test
from ..viewport_ready import ViewportReadyDelegate, ViewportReady

import omni.usd
import omni.ui
from omni.ui.tests.test_base import OmniUiTest
from pathlib import Path
import carb

EXTENSION_PATH = Path(carb.tokens.get_tokens_interface().resolve("${omni.kit.viewport.ready}")).resolve().absolute()
TEST_PATH = EXTENSION_PATH.joinpath("data", "tests")
WIDTH, HEIGHT = 512, 512

class TestViewportReady(OmniUiTest):
    async def setUp(self):
        await super().setUp()

    async def tearDown(self):
        await super().tearDown()

    @staticmethod
    def __test_image_name(base_name: str):
        settings = carb.settings.get_settings()
        if settings.get("/exts/omni.kit.viewport.ready/activity_progress/enabled"):
             base_name += "_progress"
        if settings.get("/exts/omni.kit.viewport.window/startup/windowName"):
             base_name += "_viewport"
        return base_name + ".png"

    async def test_ready_delegate_begin(self):
        '''Test the Viewport readys status message is placed inside a ui.Window named Viewport'''
        await self.create_test_area(WIDTH, HEIGHT)
        test_window = omni.ui.Window(
            "Viewport",
            dockPreference=omni.ui.DockPreference.DISABLED,
            flags=omni.ui.WINDOW_FLAGS_NO_SCROLLBAR | omni.ui.WINDOW_FLAGS_NO_TITLE_BAR | omni.ui.WINDOW_FLAGS_NO_RESIZE,
            width=WIDTH,
            height=HEIGHT
        )
        await self.wait_n_updates()

        delegate = ViewportReadyDelegate()
        delegate.build_ui()
        await self.wait_n_updates()

        await self.finalize_test(golden_img_dir=TEST_PATH, golden_img_name=self.__test_image_name("test_ready_delegate_begin"))

    async def test_ready_delegate_end(self):
        '''Test the Viewport readys status message is removed from the Viewport'''
        await self.create_test_area(WIDTH, HEIGHT)
        test_window = omni.ui.Window(
            "Viewport",
            dockPreference=omni.ui.DockPreference.DISABLED,
            flags=omni.ui.WINDOW_FLAGS_NO_SCROLLBAR | omni.ui.WINDOW_FLAGS_NO_TITLE_BAR | omni.ui.WINDOW_FLAGS_NO_RESIZE,
            width=WIDTH,
            height=HEIGHT
        )
        await self.wait_n_updates()

        delegate = ViewportReadyDelegate()
        delegate.build_ui()
        await self.wait_n_updates()

        delegate.on_complete()
        await self.wait_n_updates()

        await self.finalize_test(golden_img_dir=TEST_PATH, golden_img_name=self.__test_image_name("test_ready_delegate_end"))

    async def test_settings(self):
        '''Test carb.settings usage for default delegate'''
        # Make sure the values being set aren't the defaults!
        delegate = ViewportReadyDelegate()
        self.assertNotEqual(delegate.message, 'TEST MESSAGE')
        self.assertNotEqual(delegate.font_size, 128)

        import carb
        settings = carb.settings.get_settings()
        # Save all the defaults for restoration for later tests
        preferences = [
            '/exts/omni.kit.viewport.ready/message',
            '/exts/omni.kit.viewport.ready/font_size',
        ]
        defaults = {k: settings.get(k) for k in preferences}

        try:
            settings.set('/exts/omni.kit.viewport.ready/message', 'TEST MESSAGE')
            settings.set('/exts/omni.kit.viewport.ready/font_size', 128)
            delegate = ViewportReadyDelegate(viewport_name='Not a Viewport', usd_context_name='Not a UsdContext')
            self.assertEqual(delegate.message, 'TEST MESSAGE')
            self.assertEqual(delegate.font_size, 128)
            self.assertEqual(delegate.viewport_name, 'Not a Viewport')
            self.assertEqual(delegate.usd_context_name, 'Not a UsdContext')
        except Exception as e:
            raise e
        finally:
            # Restore the defaults
            for k, v in defaults.items():
                settings.set(k, v)

    async def test_throw_in_log_message(self):
        '''Test the Viewport readys status message is removed from the Viewport when log_message throws an Exception'''
        await self.create_test_area(WIDTH, HEIGHT)
        test_window = omni.ui.Window(
            "Viewport",
            dockPreference=omni.ui.DockPreference.DISABLED,
            flags=omni.ui.WINDOW_FLAGS_NO_SCROLLBAR | omni.ui.WINDOW_FLAGS_NO_TITLE_BAR | omni.ui.WINDOW_FLAGS_NO_RESIZE,
            width=WIDTH,
            height=HEIGHT
        )
        await self.wait_n_updates()

        log_complete_threw = False

        class LocalExpection(RuntimeError):
            pass

        class ThrowingViewportReadyDelegate(ViewportReadyDelegate):
            def log_complete(self):
                nonlocal log_complete_threw
                log_complete_threw = True
                raise LocalExpection("Expected to throw")

        try:
            delegate = ThrowingViewportReadyDelegate()
            delegate.build_ui()
            await self.wait_n_updates()
            await self.capture_and_compare(golden_img_dir=TEST_PATH, golden_img_name=self.__test_image_name("test_ready_delegate_threw_begin"))

            delegate.on_complete()
        except LocalExpection:
            pass

        self.assertTrue(log_complete_threw)
        await self.wait_n_updates()

        await self.finalize_test(golden_img_dir=TEST_PATH, golden_img_name=self.__test_image_name("test_ready_delegate_threw_end"))
