"""Management for the OmniGraph settings.

The setting can be checked directly using this model:

    import omni.graph.core as og

    if og.Settings()(og.Settings.MY_SETTING_NAME):
        # the setting value is True (for a boolean setting)
    else:
        # the setting value if False

You can also use the class as a context manager to temporarily modify the setting:

    import omni.graph.core as og

    while og.Settings.temporary(og.Settings.MY_SETTING_NAME, False):
        # Do something that needs the setting off
"""
from contextlib import contextmanager
from dataclasses import dataclass
from typing import Any

import carb
import omni.graph.tools as ogt


@dataclass
class Settings:
    """Class that packages up all of the OmniGraph settings handling into a common location. The settings themselves
    are handled through the Carbonite settings ABI, this just provides a nicer and more focused interface.
    Values here should also be reflected in the C++ OmniGraphSettings class.
    """

    ALLOW_IMPLICIT_GRAPH: str = "/persistent/omnigraph/allowGlobalImplicitGraph"
    """Constant for the setting to selectively disable the global implicit graph"""

    USE_SCHEMA_PRIMS: str = "/persistent/omnigraph/useSchemaPrims"
    """Constant for the setting to force OmniGraph prims to follow the schema"""

    ENABLE_LEGACY_PRIM_CONNECTIONS: str = "/persistent/omnigraph/enableLegacyPrimConnections"
    """Constant for the setting to enable connections between legacy Prims and OG Nodes"""

    DISABLE_PRIM_NODES: str = "/persistent/omnigraph/disablePrimNodes"
    """Constant for the setting to enable legacy Prim nodes to exist in the scene"""

    VERSION: str = "/persistent/omnigraph/settingsVersion"
    """Version number of these settings"""

    DEFAULT_EVALUATOR: str = "/persistent/omnigraph/defaultEvaluator"
    """Default evaluator type for new graphs"""

    PRIM_NODES: str = "/persistent/omnigraph/createPrimNodes"
    """Allow creation of the deprecated Prim node type"""

    UPDATE_TO_USD: str = "/persistent/omnigraph/updateToUsd"
    """Always update changes in OmniGraph to USD (can be slow)"""

    UPDATE_MESH_TO_HYDRA: str = "/persistent/omnigraph/updateMeshPointsToHydra"
    """Update mesh points directly to Hydra"""

    USE_DYNAMIC_SCHEDULER: str = "/persistent/omnigraph/useDynamicScheduler"
    """Force use of the dynamic scheduler"""

    REALM_ENABLED: str = "/persistent/omnigraph/realmEnabled"
    """Enable use of Realm for scheduling"""

    CACHED_CONNECTIONS_IN_FILE: str = "/persistent/omnigraph/useCachedConnectionsForFileLoad"
    """Use USD metadata with connection information as a cache to speed up file load"""

    USE_LEGACY_PIPELINE: str = "/persistent/omnigraph/useLegacySimulationPipeline"
    """Use the pre-1.3 simulation pipeline rather than the orchestration graph"""

    ENABLE_LEGACY_GRAPH_EDITOR: str = "REMOVED"
    """This setting has been removed"""

    PLAY_COMPUTE_GRAPH: str = "/app/player/playComputegraph"
    """Evaluate OmniGraph when the Kit 'Play' button is pressed"""

    OPTIMIZE_GENERATED_PYTHON: str = "/persistent/omnigraph/generator/pyOptimize"
    """Optimize the Python code being output by the node generator"""

    ENABLE_PATH_CHANGED_CALLBACK: str = "/persistent/omnigraph/enablePathChangedCallback"
    """Enable the deprecated Node.pathChangedCallback. This will affect performance."""

    DEPRECATIONS_ARE_ERRORS: str = "/persistent/omnigraph/deprecationsAreErrors"
    """Modify deprecation paths to raise errors or exceptions instead of logging warnings."""

    DISABLE_INFO_NOTICE_HANDLING_IN_PLAYBACK = "/persistent/omnigraph/disableInfoNoticeHandlingInPlayback"
    """Disable all processing of info-only notices by OG. This is an optimization for applications which do not
    require any triggering of OG via USD (value_changed and path_changed callbacks, lazy-graph etc"""

    ENABLE_USD_IN_PRERENDER = "/persistent/omnigraph/enableUSDInPreRender"
    """Enable nodes that read USD data to be safely used within a pre-render graph"""

    # --------------------------------------------------------------------------------------------------------------
    def __str__(self) -> str:
        """Returns a representation of all current settings"""
        settings = carb.settings.get_settings()
        return "\n".join(
            [
                f"{name} = {settings.get(field.default)}"
                for name, field in self.__dataclass_fields__.items()  # noqa: PLE1101
            ]
        )

    # --------------------------------------------------------------------------------------------------------------
    def __call__(self, setting_name: str) -> Any:
        """Look up and return the current value of the passed-in setting
        Call as og.Settings()(og.Settings.UPDATE_TO_USD)"""
        return carb.settings.get_settings().get(setting_name)

    # --------------------------------------------------------------------------------------------------------------
    @staticmethod
    def generator_settings() -> ogt.Settings:
        """Return the generator settings object corresponding to the current carb settings"""
        settings = ogt.Settings()
        carb_settings = carb.settings.get_settings()
        for setting_name in settings.all().keys():
            if carb_settings.get(f"/persistent/omnigraph/generator/{setting_name}"):
                setattr(settings, setting_name, True)
        return settings

    # --------------------------------------------------------------------------------------------------------------
    @staticmethod
    @contextmanager
    def temporary(setting_name: str, setting_value: Any):
        """Generator to temporarily use a new setting value

        with og.Settings.temporary(og.Settings.ALLOW_IMPLICIT_GLOBAL_GRAPH, True):
            do_something_that_needs_global_graph()
        """
        settings = carb.settings.get_settings()
        original_setting = settings.get(setting_name)
        try:
            settings.set(setting_name, setting_value)
            yield
        finally:
            settings.set(setting_name, original_setting)
