"""Support for simplified access to data on nodes of type omni.graph.examples.cpp.Adjacency

Computes chosen adjacency information from specified input mesh topology data.
"""


import carb
import omni.graph.core as og
import omni.graph.core._omni_graph_core as _og
import omni.graph.tools.ogn as ogn



class OgnExampleAdjacencyDatabase(og.Database):
    """Helper class providing simplified access to data on nodes of type omni.graph.examples.cpp.Adjacency

    Class Members:
        node: Node being evaluated

    Attribute Value Properties:
        Inputs:
            inputs.computeDistances
            inputs.computeNeighborCounts
            inputs.computeNeighborStarts
            inputs.computeNeighbors
            inputs.mesh
            inputs.nameOfDistancesOutputAttribute
            inputs.nameOfNeighborCountsOutputAttribute
            inputs.nameOfNeighborStartsOutputAttribute
            inputs.nameOfNeighborsOutputAttribute
            inputs.nameOfPositionsInputAttribute
            inputs.nameOfVertexCountsInputAttribute
            inputs.nameOfVertexIndicesInputAttribute
            inputs.pointCount
            inputs.removeDuplicates
            inputs.treatEdgesAsOneWay
            inputs.treatFacesAsCurves
        Outputs:
            outputs.mesh
    """

    # Imprint the generator and target ABI versions in the file for JIT generation
    GENERATOR_VERSION = (1, 41, 3)
    TARGET_VERSION = (2, 139, 12)

    # 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:computeDistances', 'bool', 0, None, "When enabled, the distances from each point to its neighbors is computed and stored in a 'float[]' attribute in 'output' as specified by 'nameOfDistancesOutputAttribute'.", {ogn.MetadataKeys.DEFAULT: 'false'}, True, False, False, ''),
        ('inputs:computeNeighborCounts', 'bool', 0, None, "When enabled, the number of neighbors of each point is computed and all are stored in an 'int[]' attribute in 'output' as specified by 'nameOfNeighborCountsOutputAttribute'.", {ogn.MetadataKeys.DEFAULT: 'false'}, True, False, False, ''),
        ('inputs:computeNeighborStarts', 'bool', 0, None, "When enabled, the beginning index of neighbors of each point within the arrays computed by either 'computeNeighbors' or 'computeDistances' is computed and all, plus an additional integer to indicate the end of the array, are stored in an 'int[]' attribute in 'output' as specified by 'nameOfNeighborStartsOutputAttribute'.  The extra integer at the end allows for easy computing of the number of neighbors of any single point, by subtracting the value in the array corresponding with the point, from the following value in the array.", {ogn.MetadataKeys.DEFAULT: 'true'}, True, True, False, ''),
        ('inputs:computeNeighbors', 'bool', 0, None, "When enabled, the neighbors of each point are computed and stored contiguously in an 'int[]' attribute in 'output' as specified by 'nameOfNeighborsOutputAttribute'.", {ogn.MetadataKeys.DEFAULT: 'true'}, True, True, False, ''),
        ('inputs:mesh', 'bundle', 0, None, 'Bundle containing topology data to be analysed', {}, True, None, False, ''),
        ('inputs:nameOfDistancesOutputAttribute', 'token', 0, None, "Name of the 'float[]' attribute to be created in 'output' to contain the computed distances to each neighbor.  This is only used if 'computeDistances' is true.", {ogn.MetadataKeys.DEFAULT: '"distances"'}, True, "distances", False, ''),
        ('inputs:nameOfNeighborCountsOutputAttribute', 'token', 0, None, "Name of the 'int[]' attribute to be created in 'output' to contain the number of neighbors of each point.  This is only used if 'computeNeighborCounts' is true.  A running sum of this array can be computed using 'computeNeighborStarts'.  The neighbors themselves can be computed using 'computeNeighbors'.", {ogn.MetadataKeys.DEFAULT: '"neighborCounts"'}, True, "neighborCounts", False, ''),
        ('inputs:nameOfNeighborStartsOutputAttribute', 'token', 0, None, "Name of the 'int[]' attribute to be created in 'output' to contain the beginning index of neighbors of each point in the arrays computed by either 'computeNeighbors' or 'computeDistances'.  This is only used if 'computeNeighborStarts' is true.", {ogn.MetadataKeys.DEFAULT: '"neighborStarts"'}, True, "neighborStarts", False, ''),
        ('inputs:nameOfNeighborsOutputAttribute', 'token', 0, None, "Name of the 'int[]' attribute to be created in 'output' to contain the neighbors of all points.  This is only used if 'computeNeighbors' is true.  The beginnings of each point's neighbors within this array can be computed using 'computeNeighborStarts'.  The number of neighbors of each point can be computed using 'computeNeighborCounts'.", {ogn.MetadataKeys.DEFAULT: '"neighbors"'}, True, "neighbors", False, ''),
        ('inputs:nameOfPositionsInputAttribute', 'token', 0, None, "Name of the 'point3f[]' attribute in 'mesh' containing the positions of each point.  This is only used if 'computeDistances' is true.  The element count of this array overrides 'pointCount', when used.", {ogn.MetadataKeys.DEFAULT: '"points"'}, True, "points", False, ''),
        ('inputs:nameOfVertexCountsInputAttribute', 'token', 0, None, "Name of the 'int[]' attribute in 'mesh' containing the vertex counts of each face", {ogn.MetadataKeys.DEFAULT: '"faceVertexCounts"'}, True, "faceVertexCounts", False, ''),
        ('inputs:nameOfVertexIndicesInputAttribute', 'token', 0, None, "Name of the 'int[]' attribute in 'mesh' containing the vertex indices of each face", {ogn.MetadataKeys.DEFAULT: '"faceVertexIndices"'}, True, "faceVertexIndices", False, ''),
        ('inputs:pointCount', 'int', 0, None, "Number of points being referred to in the vertex indices attribute.  This is only used if 'computeDistances' is false, otherwise this is overridden by the element count of the attribute specified by 'nameOfPositionsInputAttribute'.", {}, True, 0, False, ''),
        ('inputs:removeDuplicates', 'bool', 0, None, 'When enabled, each neighbor of a point will be counted only once, instead of once per edge that connects the point to the neighbor.', {ogn.MetadataKeys.DEFAULT: 'true'}, True, True, False, ''),
        ('inputs:treatEdgesAsOneWay', 'bool', 0, None, 'When enabled, if a face has an edge from A to B, B will be considered a neighbor of A, but A will not be considered a neighbor of B.  This can be useful as part of identifying unshared edges or inconsistent face winding order.', {ogn.MetadataKeys.DEFAULT: 'false'}, True, False, False, ''),
        ('inputs:treatFacesAsCurves', 'bool', 0, None, 'When enabled, the input faces will be treated as curves, instead of closed polygons, i.e. no edge from the last vertex of each face to the first vertex of that face will be counted.', {ogn.MetadataKeys.DEFAULT: 'false'}, True, False, False, ''),
        ('outputs:mesh', 'bundle', 0, None, "A copy of the input 'mesh' with the computed attributes added, as specified above.", {}, True, None, False, ''),
    ])

    @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.mesh = og.AttributeRole.BUNDLE
        role_data.outputs.mesh = og.AttributeRole.BUNDLE
        return role_data

    class ValuesForInputs(og.DynamicAttributeAccess):
        LOCAL_PROPERTY_NAMES = { }
        """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.__bundles = og.BundleContainer(context, node, attributes, [], read_only=True, gpu_ptr_kinds={})
            self._batchedReadAttributes = []
            self._batchedReadValues = []

        @property
        def computeDistances(self):
            data_view = og.AttributeValueHelper(self._attributes.computeDistances)
            return data_view.get()

        @computeDistances.setter
        def computeDistances(self, value):
            if self._setting_locked:
                raise og.ReadOnlyError(self._attributes.computeDistances)
            data_view = og.AttributeValueHelper(self._attributes.computeDistances)
            data_view.set(value)

        @property
        def computeNeighborCounts(self):
            data_view = og.AttributeValueHelper(self._attributes.computeNeighborCounts)
            return data_view.get()

        @computeNeighborCounts.setter
        def computeNeighborCounts(self, value):
            if self._setting_locked:
                raise og.ReadOnlyError(self._attributes.computeNeighborCounts)
            data_view = og.AttributeValueHelper(self._attributes.computeNeighborCounts)
            data_view.set(value)

        @property
        def computeNeighborStarts(self):
            data_view = og.AttributeValueHelper(self._attributes.computeNeighborStarts)
            return data_view.get()

        @computeNeighborStarts.setter
        def computeNeighborStarts(self, value):
            if self._setting_locked:
                raise og.ReadOnlyError(self._attributes.computeNeighborStarts)
            data_view = og.AttributeValueHelper(self._attributes.computeNeighborStarts)
            data_view.set(value)

        @property
        def computeNeighbors(self):
            data_view = og.AttributeValueHelper(self._attributes.computeNeighbors)
            return data_view.get()

        @computeNeighbors.setter
        def computeNeighbors(self, value):
            if self._setting_locked:
                raise og.ReadOnlyError(self._attributes.computeNeighbors)
            data_view = og.AttributeValueHelper(self._attributes.computeNeighbors)
            data_view.set(value)

        @property
        def mesh(self) -> og.BundleContents:
            """Get the bundle wrapper class for the attribute inputs.mesh"""
            return self.__bundles.mesh

        @property
        def nameOfDistancesOutputAttribute(self):
            data_view = og.AttributeValueHelper(self._attributes.nameOfDistancesOutputAttribute)
            return data_view.get()

        @nameOfDistancesOutputAttribute.setter
        def nameOfDistancesOutputAttribute(self, value):
            if self._setting_locked:
                raise og.ReadOnlyError(self._attributes.nameOfDistancesOutputAttribute)
            data_view = og.AttributeValueHelper(self._attributes.nameOfDistancesOutputAttribute)
            data_view.set(value)

        @property
        def nameOfNeighborCountsOutputAttribute(self):
            data_view = og.AttributeValueHelper(self._attributes.nameOfNeighborCountsOutputAttribute)
            return data_view.get()

        @nameOfNeighborCountsOutputAttribute.setter
        def nameOfNeighborCountsOutputAttribute(self, value):
            if self._setting_locked:
                raise og.ReadOnlyError(self._attributes.nameOfNeighborCountsOutputAttribute)
            data_view = og.AttributeValueHelper(self._attributes.nameOfNeighborCountsOutputAttribute)
            data_view.set(value)

        @property
        def nameOfNeighborStartsOutputAttribute(self):
            data_view = og.AttributeValueHelper(self._attributes.nameOfNeighborStartsOutputAttribute)
            return data_view.get()

        @nameOfNeighborStartsOutputAttribute.setter
        def nameOfNeighborStartsOutputAttribute(self, value):
            if self._setting_locked:
                raise og.ReadOnlyError(self._attributes.nameOfNeighborStartsOutputAttribute)
            data_view = og.AttributeValueHelper(self._attributes.nameOfNeighborStartsOutputAttribute)
            data_view.set(value)

        @property
        def nameOfNeighborsOutputAttribute(self):
            data_view = og.AttributeValueHelper(self._attributes.nameOfNeighborsOutputAttribute)
            return data_view.get()

        @nameOfNeighborsOutputAttribute.setter
        def nameOfNeighborsOutputAttribute(self, value):
            if self._setting_locked:
                raise og.ReadOnlyError(self._attributes.nameOfNeighborsOutputAttribute)
            data_view = og.AttributeValueHelper(self._attributes.nameOfNeighborsOutputAttribute)
            data_view.set(value)

        @property
        def nameOfPositionsInputAttribute(self):
            data_view = og.AttributeValueHelper(self._attributes.nameOfPositionsInputAttribute)
            return data_view.get()

        @nameOfPositionsInputAttribute.setter
        def nameOfPositionsInputAttribute(self, value):
            if self._setting_locked:
                raise og.ReadOnlyError(self._attributes.nameOfPositionsInputAttribute)
            data_view = og.AttributeValueHelper(self._attributes.nameOfPositionsInputAttribute)
            data_view.set(value)

        @property
        def nameOfVertexCountsInputAttribute(self):
            data_view = og.AttributeValueHelper(self._attributes.nameOfVertexCountsInputAttribute)
            return data_view.get()

        @nameOfVertexCountsInputAttribute.setter
        def nameOfVertexCountsInputAttribute(self, value):
            if self._setting_locked:
                raise og.ReadOnlyError(self._attributes.nameOfVertexCountsInputAttribute)
            data_view = og.AttributeValueHelper(self._attributes.nameOfVertexCountsInputAttribute)
            data_view.set(value)

        @property
        def nameOfVertexIndicesInputAttribute(self):
            data_view = og.AttributeValueHelper(self._attributes.nameOfVertexIndicesInputAttribute)
            return data_view.get()

        @nameOfVertexIndicesInputAttribute.setter
        def nameOfVertexIndicesInputAttribute(self, value):
            if self._setting_locked:
                raise og.ReadOnlyError(self._attributes.nameOfVertexIndicesInputAttribute)
            data_view = og.AttributeValueHelper(self._attributes.nameOfVertexIndicesInputAttribute)
            data_view.set(value)

        @property
        def pointCount(self):
            data_view = og.AttributeValueHelper(self._attributes.pointCount)
            return data_view.get()

        @pointCount.setter
        def pointCount(self, value):
            if self._setting_locked:
                raise og.ReadOnlyError(self._attributes.pointCount)
            data_view = og.AttributeValueHelper(self._attributes.pointCount)
            data_view.set(value)

        @property
        def removeDuplicates(self):
            data_view = og.AttributeValueHelper(self._attributes.removeDuplicates)
            return data_view.get()

        @removeDuplicates.setter
        def removeDuplicates(self, value):
            if self._setting_locked:
                raise og.ReadOnlyError(self._attributes.removeDuplicates)
            data_view = og.AttributeValueHelper(self._attributes.removeDuplicates)
            data_view.set(value)

        @property
        def treatEdgesAsOneWay(self):
            data_view = og.AttributeValueHelper(self._attributes.treatEdgesAsOneWay)
            return data_view.get()

        @treatEdgesAsOneWay.setter
        def treatEdgesAsOneWay(self, value):
            if self._setting_locked:
                raise og.ReadOnlyError(self._attributes.treatEdgesAsOneWay)
            data_view = og.AttributeValueHelper(self._attributes.treatEdgesAsOneWay)
            data_view.set(value)

        @property
        def treatFacesAsCurves(self):
            data_view = og.AttributeValueHelper(self._attributes.treatFacesAsCurves)
            return data_view.get()

        @treatFacesAsCurves.setter
        def treatFacesAsCurves(self, value):
            if self._setting_locked:
                raise og.ReadOnlyError(self._attributes.treatFacesAsCurves)
            data_view = og.AttributeValueHelper(self._attributes.treatFacesAsCurves)
            data_view.set(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 = { }
        """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.__bundles = og.BundleContainer(context, node, attributes, [], read_only=False, gpu_ptr_kinds={})
            self._batchedWriteValues = { }

        @property
        def mesh(self) -> og.BundleContents:
            """Get the bundle wrapper class for the attribute outputs.mesh"""
            return self.__bundles.mesh

        @mesh.setter
        def mesh(self, bundle: og.BundleContents):
            """Overwrite the bundle attribute outputs.mesh with a new bundle"""
            if not isinstance(bundle, og.BundleContents):
                carb.log_error("Only bundle attributes can be assigned to another bundle attribute")
            self.__bundles.mesh.bundle = bundle

        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 = OgnExampleAdjacencyDatabase.ValuesForInputs(node, self.attributes.inputs, dynamic_attributes)
        dynamic_attributes = self.dynamic_attribute_data(node, og.AttributePortType.ATTRIBUTE_PORT_TYPE_OUTPUT)
        self.outputs = OgnExampleAdjacencyDatabase.ValuesForOutputs(node, self.attributes.outputs, dynamic_attributes)
        dynamic_attributes = self.dynamic_attribute_data(node, og.AttributePortType.ATTRIBUTE_PORT_TYPE_STATE)
        self.state = OgnExampleAdjacencyDatabase.ValuesForState(node, self.attributes.state, dynamic_attributes)
