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

from omni.kit.widget.settings import SettingType
import omni.ui as ui
import carb
import omni.kit.app

from omni.rtx.window.settings.rtx_settings_stack import RTXSettingsStack
from omni.rtx.window.settings.settings_collection_frame import SettingsCollectionFrame
from omni.rtx.window.settings.rendersettingsdefaults import SettingsDefaultHandler

class SceneSettingsFrame(SettingsCollectionFrame):
    def _build_ui(self):

        self._add_setting(
            SettingType.DOUBLE3,
            "Region of Interest Min",
            "/rtx/index/regionOfInterestMin",
            tooltip="Start of region of interest",
            has_reset=False,
        )

        self._add_setting(
            SettingType.DOUBLE3,
            "Region of Interest Max",
            "/rtx/index/regionOfInterestMax",
            tooltip="End of region of interest",
            has_reset=False,
        )

        self._change_cb1 = omni.kit.app.SettingChangeSubscription("/nvindex/dataBboxMin", self._on_change)
        self._change_cb2 = omni.kit.app.SettingChangeSubscription("/nvindex/dataBboxMax", self._on_change)

        dataBboxMin = self._settings.get("/nvindex/dataBboxMin")
        dataBboxMax = self._settings.get("/nvindex/dataBboxMax")

        def do_reset_to_scene_extent():
            self._settings.set("/rtx/index/regionOfInterestMin", dataBboxMin)
            self._settings.set("/rtx/index/regionOfInterestMax", dataBboxMax)

        if dataBboxMin and dataBboxMax:
            dataBboxValid = True
            for i in range(0, 3):
                if (dataBboxMin[i] >= dataBboxMax[i]):
                    dataBboxValid = False

            if dataBboxValid:
                ui.Button("Reset to Data Extent", tooltip="Resets the region of interest to contain all scene element",
                          clicked_fn=do_reset_to_scene_extent)

        self._add_setting(
            SettingType.FLOAT,
            "Default Point Width",
            "/rtx/index/defaultPointWidth",
            tooltip="Default point width for new point clouds loaded from USD. If set to 0, a simple heuristic will be used.",
        )

        if self._settings.get("/nvindex/showAdvancedSettings"):
            subdivisionModeItems = {
                "Default": "",
                "Grid": "grid",
                "KD-tree": "kd_tree",
            }
            self._add_setting_combo(
                "Override Subdivision Mode",
                "/rtx/index/overrideSubdivisionMode",
                subdivisionModeItems,
                tooltip="Override data subdivision mode, only affects newly added datasets."
            )

            self._add_setting(
                SettingType.INT,
                "Override Subdivision Part Count",
                "/rtx/index/overrideSubdivisionPartCount",
                0,
                256,
                tooltip="Override number of parts for kd_tree subdivision, only affects newly added datasets."
            )

    def destroy(self):
        self._change_cb1 = None
        self._change_cb2 = None
        super().destroy()


class RenderSettingsFrame(SettingsCollectionFrame):
    def _build_ui(self):

        composite_rendering = self._settings.get("/nvindex/compositeRenderingMode")
        if composite_rendering:
            self._add_setting(
                SettingType.FLOAT,
                "Color Scaling",
                "/rtx/index/colorScale",
                0.0,
                100.0,
                tooltip="Scale factor for color output",
            )
        else:
            self._add_setting(
                SettingType.COLOR3,
                "Background Color",
                "/rtx/index/backgroundColor",
                tooltip="Color of scene background",
            )

            if self._settings.get("/nvindex/showAdvancedSettings"):
                self._add_setting(
                    SettingType.FLOAT,
                    "Background Opacity",
                    "/rtx/index/backgroundOpacity",
                    0.0,
                    1.0,
                    tooltip="Opacity of scene background",
                )

                self._add_setting(
                    SettingType.BOOL,
                    "Frame Buffer Blending",
                    "/rtx/index/frameBufferBlending",
                    tooltip="Blend rendering result to frame buffer",
                )

        self._add_setting(
            SettingType.INT,
            "Rendering Samples",
            "/rtx/index/renderingSamples",
            1,
            32,
            tooltip="Number of samples per pixel used during rendering",
        )


class CompositingSettingsFrame(SettingsCollectionFrame):
    def _build_ui(self):

        self._add_setting(
            SettingType.BOOL,
            "Automatic Span Control",
            "/rtx/index/automaticSpanControl",
            tooltip="Automatically optimize the number of spans used for compositing",
        )

        self._change_cb = omni.kit.app.SettingChangeSubscription("/rtx/index/automaticSpanControl", self._on_change)

        if not self._settings.get("/rtx/index/automaticSpanControl"):
            self._add_setting(
                SettingType.INT,
                "Horizontal spans",
                "/rtx/index/nbSpans",
                1,
                100,
                tooltip="Number of spans used for compositing, when automatic span control is not used",
            )

        self._add_setting(
            SettingType.INT,
            "Host Span Limit",
            "/rtx/index/maxSpansPerMachine",
            1,
            100,
            tooltip="Maximum number of spans per host",
        )

    def destroy(self):
        self._change_cb = None
        super().destroy()


class AdvancedSettingsFrame(SettingsCollectionFrame):
    def _build_ui(self):

        self._add_setting(
            SettingType.BOOL,
            "Monitor Performance Values",
            "/rtx/index/monitorPerformanceValues",
            tooltip="Print performance statistics to stdout",
        )

        self._add_setting(
            SettingType.STRING,
            "Session Export File (optional)",
            "/nvindex/exportSessionFilename",
            tooltip="Absolute path where to write the session export to. If empty, the log will be used.",
        )

        self._change_cb = omni.kit.app.SettingChangeSubscription("/nvindex/exportSessionFilename", self._on_change)

        def do_export_session():
            self._settings.set("/nvindex/exportSession", True)

        exportTarget = "File" if self._settings.get("/nvindex/exportSessionFilename") else "Log"
        ui.Button("Export Session to " + exportTarget, tooltip="Export session information", clicked_fn=do_export_session)

        restart_msg = "changing it requires restarting IndeX"

        logLevelItems = {
            "Debug": "debug",
            "Verbose": "verbose",
            "Info": "info",
            "Warning": "warning",
            "Error": "error",
            "Fatal": "fatal",
        }
        self._add_setting_combo(
            "Log Level",
            "/nvindex/logLevel",
            logLevelItems,
            tooltip="Log level for IndeX log message, " + restart_msg,
        )

        def do_restart_index():
            self._settings.set("/nvindex/restartIndex", True)

        ui.Button("Restart IndeX", tooltip="Restart the NVIDIA IndeX session, reloading all data", clicked_fn=do_restart_index)

    def destroy(self):
        self._change_cb = None
        super().destroy()


class IndeXCommonSettingStack(RTXSettingsStack):
    def __init__(self) -> None:
        self._stack = ui.VStack(spacing=10)
        self._settings = carb.settings.get_settings()
        with self._stack:
            SceneSettingsFrame("Scene Settings", parent=self)
            RenderSettingsFrame("Render Settings", parent=self)

            if self._settings.get("/nvindex/showAdvancedSettings"):
                CompositingSettingsFrame("Compositing Settings", parent=self)
                AdvancedSettingsFrame("Advanced", parent=self)

            ui.Spacer()
