## Copyright (c) 2021, 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 os
import sys
import math
import omni.kit.app
from omni.kit.test.async_unittest import AsyncTestCase
import omni.usd

from omni.kit import ui_test
from pxr import Sdf, UsdShade
from omni.kit.test_suite.helpers import (
    open_stage,
    get_test_data_path,
    select_prims,
    wait_stage_loading,
    arrange_windows
    )


class SoftRangeUI(AsyncTestCase):
    # Before running each test
    async def setUp(self):
        await arrange_windows("Stage", 64)
        await open_stage(get_test_data_path(__name__, "usd/soft_range.usda"))

    # After running each test
    async def tearDown(self):
        # de-select prims to prevent _delayed_dirty_handler exception
        await select_prims([])
        await wait_stage_loading()

    def _verify_values(self, widget_name: str, expected_value, model_soft_min, model_soft_max, min, max, places=4):
        for widget in ui_test.find_all(f"Property//Frame/**/.identifier=='{widget_name}'"):
            self.assertAlmostEqual(widget.model.get_value(), expected_value, places=places)
            if model_soft_min != None:
                self.assertAlmostEqual(widget.model._soft_range_min, model_soft_min, places=places)
            if model_soft_max != None:
                self.assertAlmostEqual(widget.model._soft_range_max, model_soft_max, places=places)
            self.assertAlmostEqual(widget.widget.min, min, places=places)
            self.assertAlmostEqual(widget.widget.max, max, places=places)

    async def _click_type_verify(self, widget_name: str, value, expected_value, model_soft_min, model_soft_max, min, max, places=4):
        for widget in ui_test.find_all(f"Property//Frame/**/.identifier=='{widget_name}'"):
            await widget.input(str(value))
            self._verify_values(widget_name, expected_value, model_soft_min, model_soft_max, min, max, places=places)

    async def _hide_frames(self, show_list):
        for w in ui_test.find_all("Property//Frame/**/CollapsableFrame[*]"):
            if show_list == None:
                w.widget.collapsed = False
            elif w.widget.title in show_list:
                w.widget.collapsed = False
            else:
                w.widget.collapsed = True
        await ui_test.human_delay()

    async def test_l2_softrange_ui(self):
        await ui_test.find("Property").focus()

        range_name = "float_slider_inputs:glass_ior"

        # select prim
        await select_prims(["/World/Looks/OmniGlass/Shader"])

        # wait for material to load & UI to refresh
        await wait_stage_loading()

        # test soft_range unlimited inputs:glass_ior
        await self._hide_frames(["Shader", "Refraction"])

        # check default values
        self._verify_values(range_name, 1.491, None, None, 1, 4)

        # something not right here, accuracy of 0.2 ?
        await self._click_type_verify(range_name, 1500, 1500, 1, 1500, 1, 1500)       # value & max 1500
        await self._click_type_verify(range_name, -150, -150, -150, 1500, -150, 1500) # value & min -150 & max 1500
        await self._click_type_verify(range_name, 500, 500, -150, 1500, -150, 1500)   # value 500 & min -150 & max 1500
        await self._click_type_verify(range_name, 0, 0, -150, 1500, -150, 1500)       # value 0 & min -150 & max 1500

        # reset values
        await ui_test.find(f"Property//Frame/**/ImageWithProvider[*].identifier=='control_state_inputs:glass_ior'").click()

        # verify
        self._verify_values(range_name, 1.491, None, None, 1, 4)
