## 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


class HardSoftRangeUI(AsyncTestCase):
    # Before running each test
    async def setUp(self):
        from omni.kit import ui_test
        from omni.kit.test_suite.helpers import open_stage, get_test_data_path, arrange_windows

        await arrange_windows("Stage", 64, 800)
        await open_stage(get_test_data_path(__name__, "usd/soft_range.usda"))
        await ui_test.find("Property").focus()

    # After running each test
    async def tearDown(self):
        from omni.kit import ui_test
        from omni.kit.test_suite.helpers import select_prims, wait_stage_loading

        # de-select prims to prevent _delayed_dirty_handler exception
        await select_prims([])
        await wait_stage_loading()

    async def _hide_frames(self, show_list):
        from omni.kit import ui_test

        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_hard_softrange_float_ui(self):
        from omni.kit import ui_test
        from omni.kit.test_suite.helpers import select_prims, wait_stage_loading

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


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

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

        # test hard range 0-1000 & soft range 0-1 inputs:depth
        await self._hide_frames(["Shader", "Color"])

        # check default values
        verify_values("float_slider_inputs:depth",
                      expected_value=0.001,
                      model_soft_min=None,
                      model_soft_max=None,
                      hard_min=0,
                      hard_max=1)

        # something not right here, accuracy of 0.2 ?

        # change values
        await ui_test.find(f"Property//Frame/**/.identifier=='float_slider_inputs:depth'").input("1500")

        # verify changed value
        verify_values("float_slider_inputs:depth",
                      expected_value=1000,
                      model_soft_min=0,
                      model_soft_max=1000,
                      hard_min=0,
                      hard_max=1000)

        # change values
        await ui_test.find(f"Property//Frame/**/.identifier=='float_slider_inputs:depth'").input("-150")

        # verify changed value
        verify_values("float_slider_inputs:depth",
                      expected_value=0,
                      model_soft_min=0,
                      model_soft_max=1000,
                      hard_min=0,
                      hard_max=1000)

        # change values
        await ui_test.find(f"Property//Frame/**/.identifier=='float_slider_inputs:depth'").input("500")

        # verify changed value
        verify_values("float_slider_inputs:depth",
                      expected_value=500,
                      model_soft_min=0,
                      model_soft_max=1000,
                      hard_min=0,
                      hard_max=1000)

        # change values
        await ui_test.find(f"Property//Frame/**/.identifier=='float_slider_inputs:depth'").input("0")

        # verify changed value
        verify_values("float_slider_inputs:depth",
                      0,
                      model_soft_min=0,
                      model_soft_max=1000,
                      hard_min=0,
                      hard_max=1000)

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

        # verify
        verify_values("float_slider_inputs:depth",
                      expected_value=0.001,
                      model_soft_min=None,
                      model_soft_max=None,
                      hard_min=0,
                      hard_max=1)
