## 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.
##
import omni.kit.app
import omni.kit.test
import omni.kit.ui_test
import omni.ui as ui
import omni.usd
import omni.timeline
import carb.tokens
import omni.usd.audio
from omni.ui.tests.test_base import OmniUiTest

import pathlib
import asyncio;


class TestOscilloscopeWindow(OmniUiTest):  # pragma: no cover

    async def _dock_window(self):
        await self.docked_test_window(
            window=self._win.window,
            width=512,
            height=540)

    # Before running each test
    async def setUp(self):
        await super().setUp()

        import omni.kit.material.library

        # wait for material to be preloaded so create menu is complete & menus don't rebuild during tests
        await omni.kit.material.library.get_mdl_list_async()

        extension_path = carb.tokens.get_tokens_interface().resolve("${omni.kit.window.audio.oscilloscope}")
        self._test_path = pathlib.Path(extension_path).joinpath("data").joinpath("tests").absolute()
        self._golden_img_dir = self._test_path.joinpath("golden")

        # open the dropdown
        window_menu = omni.kit.ui_test.get_menubar().find_menu("Window")
        self.assertIsNotNone(window_menu)
        await window_menu.click()

        # click the oscilloscope window to open it
        oscilloscope_menu = omni.kit.ui_test.get_menubar().find_menu("Oscilloscope")
        self.assertIsNotNone(oscilloscope_menu)
        await oscilloscope_menu.click()

        self._win = omni.kit.ui_test.find("Audio Oscilloscope")
        self.assertIsNotNone(self._win)

        self._record_button = self._win.find("**/Button[*]")
        self.assertIsNotNone(self._record_button)


    # After running each test
    async def tearDown(self):
        self._win = None
        await super().tearDown()

    async def _test_just_opened(self):
        await self._dock_window()
        await self.finalize_test(golden_img_dir=self._golden_img_dir, golden_img_name="test_just_opened.png")

    async def _test_recording(self):
        # docking the window breaks the UI system entirely for some reason
        #await self._dock_window()

        await self._record_button.click() # the user hit the record button

        await asyncio.sleep(4.0) # wait for the bar to fill up

        await self._dock_window()
        await self.finalize_test(golden_img_dir=self._golden_img_dir, golden_img_name="test_recording.png")

        await self._record_button.click() # the user hit stop

        await asyncio.sleep(0.25) # wait so the window will be updated

        await self._dock_window()
        await self.finalize_test(golden_img_dir=self._golden_img_dir, golden_img_name="test_stopped.png")


    async def _test_real_audio(self):
        # Comment this out to run the test.
        # Since this test is timing dependent, it'll never work 100% and we don't
        # have any sort of smart comparison that could handle a shift in the image.
        # It works about 80% of the time.
        return

        context = omni.usd.get_context()
        self.assertIsNotNone(context)

        context.new_stage()
        stage = context.get_stage()
        self.assertIsNotNone(stage)

        audio = omni.usd.audio.get_stage_audio_interface()
        self.assertIsNotNone(audio)

        prim_path = "/test_sound"
        prim = stage.DefinePrim(prim_path, "OmniSound")
        self.assertIsNotNone(prim)
        prim.GetAttribute("filePath").Set(str(self._test_path / "1hz.oga"))
        prim.GetAttribute("auralMode").Set("nonSpatial")

        i = 0
        while audio.get_sound_asset_status(prim) == omni.usd.audio.AssetLoadStatus.IN_PROGRESS:
            await asyncio.sleep(0.001)
            if i > 5000:
                raise Exception("asset load timed out")
            i += 1

        await self._record_button.click() # the user hit the record button

        # use a voice to bypass the timeline
        voice = audio.spawn_voice(prim)
        i = 0
        while voice.is_playing():
            await asyncio.sleep(0.001)
            i += 1
            if (i == 5000):
                self.assertFalse("test timed out")

        await self._dock_window()
        await self.finalize_test(golden_img_dir=self._golden_img_dir, golden_img_name="test_real_audio.png")

    # tests need to be run sequentially, so we can only have 1 test function in this module
    async def test_all(self):
        await self._test_just_opened()
        await self._test_recording()
        await self._test_real_audio()
