"""Support for simplified access to data on nodes of type omni.graph.ui.VStack

Contruct a Stack on the Viewport. All child widgets of Stack will be placed in a row, column or layer based on the direction
input.
"""

import omni.graph.core as og
import omni.graph.core._omni_graph_core as _og
import omni.graph.tools.ogn as ogn
import traceback
import sys
class OgnVStackDatabase(og.Database):
    """Helper class providing simplified access to data on nodes of type omni.graph.ui.VStack

    Class Members:
        node: Node being evaluated

    Attribute Value Properties:
        Inputs:
            inputs.create
            inputs.direction
            inputs.parentWidgetPath
            inputs.style
            inputs.widgetIdentifier
        Outputs:
            outputs.created
            outputs.widgetPath

    Predefined Tokens:
        tokens.BACK_TO_FRONT
        tokens.BOTTOM_TO_TOP
        tokens.FRONT_TO_BACK
        tokens.LEFT_TO_RIGHT
        tokens.RIGHT_TO_LEFT
        tokens.TOP_TO_BOTTOM
    """
    # This is an internal object that provides per-class storage of a per-node data dictionary
    PER_NODE_DATA = {}
    # This is an internal object that describes unchanging attributes in a generic way
    # The values in this list are in no particular order, as a per-attribute tuple
    #     Name, Type, ExtendedTypeIndex, UiName, Description, Metadata,
    #     Is_Required, DefaultValue, Is_Deprecated, DeprecationMsg
    # You should not need to access any of this data directly, use the defined database interfaces
    INTERFACE = og.Database._get_interface([
        ('inputs:create', 'execution', 0, 'Create', 'Input execution to create and show the widget', {}, True, None, False, ''),
        ('inputs:direction', 'token', 0, 'Direction', 'The direction the widgets will be stacked.', {ogn.MetadataKeys.ALLOWED_TOKENS: 'BACK_TO_FRONT,BOTTOM_TO_TOP,FRONT_TO_BACK,LEFT_TO_RIGHT,RIGHT_TO_LEFT,TOP_TO_BOTTOM', ogn.MetadataKeys.ALLOWED_TOKENS_RAW: '{"BACK_TO_FRONT": "BACK_TO_FRONT", "BOTTOM_TO_TOP": "BOTTOM_TO_TOP", "FRONT_TO_BACK": "FRONT_TO_BACK", "LEFT_TO_RIGHT": "LEFT_TO_RIGHT", "RIGHT_TO_LEFT": "RIGHT_TO_LEFT", "TOP_TO_BOTTOM": "TOP_TO_BOTTOM"}', ogn.MetadataKeys.DEFAULT: '"TOP_TO_BOTTOM"'}, True, 'TOP_TO_BOTTOM', False, ''),
        ('inputs:parentWidgetPath', 'token', 0, 'Parent Widget Path', 'The absolute path to the parent widget.', {}, True, '', False, ''),
        ('inputs:style', 'string', 0, None, 'Style to be applied to the stack and its children. This can later be changed with the\nWriteWidgetStyle node.', {}, False, None, False, ''),
        ('inputs:widgetIdentifier', 'token', 0, 'Widget Identifier', 'An optional unique identifier for the widget.\nCan be used to refer to this widget in other places such as the OnWidgetClicked node.', {}, False, None, False, ''),
        ('outputs:created', 'execution', 0, 'Created', 'Executed when the widget is created', {}, True, None, False, ''),
        ('outputs:widgetPath', 'token', 0, 'Widget Path', 'The absolute path to the created widget', {}, True, None, False, ''),
    ])
    class tokens:
        BACK_TO_FRONT = "BACK_TO_FRONT"
        BOTTOM_TO_TOP = "BOTTOM_TO_TOP"
        FRONT_TO_BACK = "FRONT_TO_BACK"
        LEFT_TO_RIGHT = "LEFT_TO_RIGHT"
        RIGHT_TO_LEFT = "RIGHT_TO_LEFT"
        TOP_TO_BOTTOM = "TOP_TO_BOTTOM"
    @classmethod
    def _populate_role_data(cls):
        """Populate a role structure with the non-default roles on this node type"""
        role_data = super()._populate_role_data()
        role_data.inputs.create = og.Database.ROLE_EXECUTION
        role_data.outputs.created = og.Database.ROLE_EXECUTION
        return role_data
    class ValuesForInputs(og.DynamicAttributeAccess):
        LOCAL_PROPERTY_NAMES = {"create", "direction", "parentWidgetPath", "style", "widgetIdentifier", "_setting_locked", "_batchedReadAttributes", "_batchedReadValues"}
        """Helper class that creates natural hierarchical access to input attributes"""
        def __init__(self, node: og.Node, attributes, dynamic_attributes: og.DynamicAttributeInterface):
            """Initialize simplified access for the attribute data"""
            context = node.get_graph().get_default_graph_context()
            super().__init__(context, node, attributes, dynamic_attributes)
            self._batchedReadAttributes = [self._attributes.create, self._attributes.direction, self._attributes.parentWidgetPath, self._attributes.style, self._attributes.widgetIdentifier]
            self._batchedReadValues = [None, "TOP_TO_BOTTOM", "", None, None]

        @property
        def create(self):
            return self._batchedReadValues[0]

        @create.setter
        def create(self, value):
            self._batchedReadValues[0] = value

        @property
        def direction(self):
            return self._batchedReadValues[1]

        @direction.setter
        def direction(self, value):
            self._batchedReadValues[1] = value

        @property
        def parentWidgetPath(self):
            return self._batchedReadValues[2]

        @parentWidgetPath.setter
        def parentWidgetPath(self, value):
            self._batchedReadValues[2] = value

        @property
        def style(self):
            return self._batchedReadValues[3]

        @style.setter
        def style(self, value):
            self._batchedReadValues[3] = value

        @property
        def widgetIdentifier(self):
            return self._batchedReadValues[4]

        @widgetIdentifier.setter
        def widgetIdentifier(self, value):
            self._batchedReadValues[4] = value

        def __getattr__(self, item: str):
            if item in self.LOCAL_PROPERTY_NAMES:
                return object.__getattribute__(self, item)
            else:
                return super().__getattr__(item)

        def __setattr__(self, item: str, new_value):
            if item in self.LOCAL_PROPERTY_NAMES:
                object.__setattr__(self, item, new_value)
            else:
                super().__setattr__(item, new_value)

        def _prefetch(self):
            readAttributes = self._batchedReadAttributes
            newValues = _og._prefetch_input_attributes_data(readAttributes)
            if len(readAttributes) == len(newValues):
                self._batchedReadValues = newValues
    class ValuesForOutputs(og.DynamicAttributeAccess):
        LOCAL_PROPERTY_NAMES = {"created", "widgetPath", "_batchedWriteValues"}
        """Helper class that creates natural hierarchical access to output attributes"""
        def __init__(self, node: og.Node, attributes, dynamic_attributes: og.DynamicAttributeInterface):
            """Initialize simplified access for the attribute data"""
            context = node.get_graph().get_default_graph_context()
            super().__init__(context, node, attributes, dynamic_attributes)
            self._batchedWriteValues = { }

        @property
        def created(self):
            value = self._batchedWriteValues.get(self._attributes.created)
            if value:
                return value
            else:
                data_view = og.AttributeValueHelper(self._attributes.created)
                return data_view.get()

        @created.setter
        def created(self, value):
            self._batchedWriteValues[self._attributes.created] = value

        @property
        def widgetPath(self):
            value = self._batchedWriteValues.get(self._attributes.widgetPath)
            if value:
                return value
            else:
                data_view = og.AttributeValueHelper(self._attributes.widgetPath)
                return data_view.get()

        @widgetPath.setter
        def widgetPath(self, value):
            self._batchedWriteValues[self._attributes.widgetPath] = value

        def __getattr__(self, item: str):
            if item in self.LOCAL_PROPERTY_NAMES:
                return object.__getattribute__(self, item)
            else:
                return super().__getattr__(item)

        def __setattr__(self, item: str, new_value):
            if item in self.LOCAL_PROPERTY_NAMES:
                object.__setattr__(self, item, new_value)
            else:
                super().__setattr__(item, new_value)

        def _commit(self):
            _og._commit_output_attributes_data(self._batchedWriteValues)
            self._batchedWriteValues = { }
    class ValuesForState(og.DynamicAttributeAccess):
        """Helper class that creates natural hierarchical access to state attributes"""
        def __init__(self, node: og.Node, attributes, dynamic_attributes: og.DynamicAttributeInterface):
            """Initialize simplified access for the attribute data"""
            context = node.get_graph().get_default_graph_context()
            super().__init__(context, node, attributes, dynamic_attributes)
    def __init__(self, node):
        super().__init__(node)
        dynamic_attributes = self.dynamic_attribute_data(node, og.AttributePortType.ATTRIBUTE_PORT_TYPE_INPUT)
        self.inputs = OgnVStackDatabase.ValuesForInputs(node, self.attributes.inputs, dynamic_attributes)
        dynamic_attributes = self.dynamic_attribute_data(node, og.AttributePortType.ATTRIBUTE_PORT_TYPE_OUTPUT)
        self.outputs = OgnVStackDatabase.ValuesForOutputs(node, self.attributes.outputs, dynamic_attributes)
        dynamic_attributes = self.dynamic_attribute_data(node, og.AttributePortType.ATTRIBUTE_PORT_TYPE_STATE)
        self.state = OgnVStackDatabase.ValuesForState(node, self.attributes.state, dynamic_attributes)
    class abi:
        """Class defining the ABI interface for the node type"""
        @staticmethod
        def get_node_type():
            get_node_type_function = getattr(OgnVStackDatabase.NODE_TYPE_CLASS, 'get_node_type', None)
            if callable(get_node_type_function):
                return get_node_type_function()
            return 'omni.graph.ui.VStack'
        @staticmethod
        def compute(context, node):
            try:
                per_node_data = OgnVStackDatabase.PER_NODE_DATA[node.node_id()]
                db = per_node_data.get('_db')
                if db is None:
                    db = OgnVStackDatabase(node)
                    per_node_data['_db'] = db
            except:
                db = OgnVStackDatabase(node)

            try:
                compute_function = getattr(OgnVStackDatabase.NODE_TYPE_CLASS, 'compute', None)
                if callable(compute_function) and compute_function.__code__.co_argcount > 1:
                    return compute_function(context, node)

                db.inputs._prefetch()
                db.inputs._setting_locked = True
                with og.in_compute():
                    return OgnVStackDatabase.NODE_TYPE_CLASS.compute(db)
            except Exception as error:
                stack_trace = "".join(traceback.format_tb(sys.exc_info()[2].tb_next))
                db.log_error(f'Assertion raised in compute - {error}\n{stack_trace}', add_context=False)
            finally:
                db.inputs._setting_locked = False
                db.outputs._commit()
            return False
        @staticmethod
        def initialize(context, node):
            OgnVStackDatabase._initialize_per_node_data(node)
            initialize_function = getattr(OgnVStackDatabase.NODE_TYPE_CLASS, 'initialize', None)
            if callable(initialize_function):
                initialize_function(context, node)
        @staticmethod
        def release(node):
            release_function = getattr(OgnVStackDatabase.NODE_TYPE_CLASS, 'release', None)
            if callable(release_function):
                release_function(node)
            OgnVStackDatabase._release_per_node_data(node)
        @staticmethod
        def update_node_version(context, node, old_version, new_version):
            update_node_version_function = getattr(OgnVStackDatabase.NODE_TYPE_CLASS, 'update_node_version', None)
            if callable(update_node_version_function):
                return update_node_version_function(context, node, old_version, new_version)
            return False
        @staticmethod
        def initialize_type(node_type):
            initialize_type_function = getattr(OgnVStackDatabase.NODE_TYPE_CLASS, 'initialize_type', None)
            needs_initializing = True
            if callable(initialize_type_function):
                needs_initializing = initialize_type_function(node_type)
            if needs_initializing:
                node_type.set_metadata(ogn.MetadataKeys.EXTENSION, "omni.graph.ui")
                node_type.set_metadata(ogn.MetadataKeys.UI_NAME, "Stack (BETA)")
                node_type.set_metadata(ogn.MetadataKeys.CATEGORIES, "graph:action,ui")
                node_type.set_metadata(ogn.MetadataKeys.DESCRIPTION, "Contruct a Stack on the Viewport. All child widgets of Stack will be placed in a row, column or layer based on the direction input.")
                node_type.set_metadata(ogn.MetadataKeys.LANGUAGE, "Python")
                OgnVStackDatabase.INTERFACE.add_to_node_type(node_type)
        @staticmethod
        def on_connection_type_resolve(node):
            on_connection_type_resolve_function = getattr(OgnVStackDatabase.NODE_TYPE_CLASS, 'on_connection_type_resolve', None)
            if callable(on_connection_type_resolve_function):
                on_connection_type_resolve_function(node)
    NODE_TYPE_CLASS = None
    GENERATOR_VERSION = (1, 17, 2)
    TARGET_VERSION = (2, 65, 4)
    @staticmethod
    def register(node_type_class):
        OgnVStackDatabase.NODE_TYPE_CLASS = node_type_class
        og.register_node_type(OgnVStackDatabase.abi, 1)
    @staticmethod
    def deregister():
        og.deregister_node_type("omni.graph.ui.VStack")
