# 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 typing import List, Optional

import carb
import omni.graph.core as og
import omni.ui as ui

from . import UINodeCommon


class OgnVStack(UINodeCommon.OgWidgetNode):
    @staticmethod
    def compute(db) -> bool:

        if db.inputs.create != og.ExecutionAttributeState.DISABLED:

            direction = UINodeCommon.to_ui_direction(db.inputs.direction)
            if not direction:
                db.log_warning("Unexpected direction input")
                return False

            parent_widget_path = db.inputs.parentWidgetPath
            if not parent_widget_path:
                db.log_error("No parentWidgetPath supplied.")
                return False

            parent_widget = UINodeCommon.find_widget_among_all_windows(parent_widget_path)
            if parent_widget is None:
                db.log_error("Could not find parent widget.")
                return False

            style = {}
            try:
                style = UINodeCommon.to_ui_style(db.inputs.style)
            except SyntaxError as err:
                db.log_error(f"'inputs:style': {err.msg}")
                return False

            widget_identifier = UINodeCommon.get_unique_widget_identifier(db)

            with parent_widget:
                stack = ui.Stack(direction, identifier=widget_identifier)
                if style:
                    stack.set_style(style)

            OgnVStack.register_widget(db.abi_context, widget_identifier, stack)
            db.outputs.created = og.ExecutionAttributeState.ENABLED
            db.outputs.widgetPath = UINodeCommon.find_widget_path(stack)
            return True

        db.log_warning("Unexpected execution with no execution input enabled")
        return False

    @staticmethod
    def get_property_names(stack: ui.Stack, writeable: bool) -> Optional[List[str]]:
        props = super(OgnVStack, OgnVStack).get_property_names(stack, writeable)
        if props is not None:
            if not isinstance(stack, ui.Stack):
                carb.log_warn(f"Attempt to retrieve property names from non-stack object '{stack}'.")
                return None

            props += ["content_clipping", "direction", "spacing"]  # bool  # str  # float
        return props

    @staticmethod
    def resolve_output_property(stack: ui.Stack, property_name: str, attribute: og.Attribute) -> bool:
        if not isinstance(stack, ui.Stack):
            carb.log_warn(f"Attempt to resolve property on non-stack object '{stack}'.")
            return False
        if property_name not in OgnVStack.get_property_names(stack, False):
            carb.log_warn(f"'{property_name}' is not a readable property of stack '{stack.identifier}'")
            return False
        return super(OgnVStack, OgnVStack).resolve_output_property(stack, property_name, attribute)

    @staticmethod
    def get_property_value(stack: ui.Stack, property_name: str, attribute: og.RuntimeAttribute) -> bool:
        if not isinstance(stack, ui.Stack):
            carb.log_warn(f"Attempt to get value of property {property_name} on non-stack object '{stack}'.")
            return False
        if property_name not in OgnVStack.get_property_names(stack, False):
            carb.log_warn(f"'{property_name}' is not a readable property of stack '{stack.identifier}'")
            return False
        return super(OgnVStack, OgnVStack).get_property_value(stack, property_name, attribute)

    @staticmethod
    def set_property_value(stack: ui.Stack, property_name: str, attribute: og.RuntimeAttribute) -> bool:
        if not isinstance(stack, ui.Stack):
            carb.log_warn(f"Attempt to set value of property {property_name} on non-stack object '{stack}'.")
            return False
        if property_name not in OgnVStack.get_property_names(stack, True):
            carb.log_warn(f"'{property_name}' is not a writeable property of stack '{stack.identifier}'")
            return False
        return super(OgnVStack, OgnVStack).set_property_value(stack, property_name, attribute)

    @staticmethod
    def get_style_element_names(stack: ui.Stack, writeable: bool) -> List[str]:
        element_names = super(OgnVStack, OgnVStack).get_style_element_names(stack, writeable)
        if element_names is not None:  # noqa: SIM102
            if not isinstance(stack, ui.Stack):
                carb.log_warn(f"Attempt to retrieve style element names from non-stack widget '{stack}'.")
                return None

            # TBD
        return element_names

    @staticmethod
    def get_style_value(stack: ui.Stack, element_name: str, attribute: og.RuntimeAttribute) -> bool:
        if not isinstance(stack, ui.Stack):
            carb.log_warn(f"Attempt to get style element from non-stack object '{stack}'.")
            return False
        return super(OgnVStack, OgnVStack).get_style_value(stack, element_name, attribute)

    @staticmethod
    def set_style_value(stack: ui.Stack, element_name: str, attribute: og.RuntimeAttribute) -> bool:
        if not isinstance(stack, ui.Stack):
            carb.log_warn(f"Attempt to set style element on non-stack object '{stack}'.")
            return False
        return super(OgnVStack, OgnVStack).set_style_value(stack, element_name, attribute)
