/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */

#ifndef UA_SERVER_NODES_H_
#define UA_SERVER_NODES_H_

/* !!! Warning !!!
 *
 * If you are not developing a nodestore plugin, then you should not work with
 * the definitions from this file directly. The underlying node structures are
 * not meant to be used directly by end users. Please use the public server API
 * / OPC UA services to interact with the information model. */

#include <open62541/server.h>
#include "ziptree.h"

_UA_BEGIN_DECLS

/* Forward declaration */
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
struct UA_MonitoredItem;
#endif

/**
 * .. _information-modelling:
 *
 * Information Modelling
 * =====================
 *
 * Information modelling in OPC UA combines concepts from object-orientation and
 * semantic modelling. At the core, an OPC UA information model is a graph made
 * up of
 *
 * - Nodes: There are eight possible Node types (variable, object, method, ...)
 * - References: Typed and directed relations between two nodes
 *
 * Every node is identified by a unique (within the server) :ref:`nodeid`.
 * Reference are triples of the form ``(source-nodeid, referencetype-nodeid,
 * target-nodeid)``. An example reference between nodes is a
 * ``hasTypeDefinition`` reference between a Variable and its VariableType. Some
 * ReferenceTypes are *hierarchic* and must not form *directed loops*. See the
 * section on :ref:`ReferenceTypes <referencetypenode>` for more details on
 * possible references and their semantics.
 *
 * **Warning!!** The structures defined in this section are only relevant for
 * the developers of custom Nodestores. The interaction with the information
 * model is possible only via the OPC UA :ref:`services`. So the following
 * sections are purely informational so that users may have a clear mental
 * model of the underlying representation.
 *
 * Base Node Attributes
 * --------------------
 *
 * Nodes contain attributes according to their node type. The base node
 * attributes are common to all node types. In the OPC UA :ref:`services`,
 * attributes are referred to via the :ref:`nodeid` of the containing node and
 * an integer :ref:`attribute-id`.
 *
 * Internally, open62541 uses ``UA_Node`` in places where the exact node type is
 * not known or not important. The ``nodeClass`` attribute is used to ensure the
 * correctness of casting from ``UA_Node`` to a specific node type. */

/* Ordered tree structure for fast member check */
typedef struct UA_ReferenceTarget {
    ZIP_ENTRY(UA_ReferenceTarget) idTreeFields;
    ZIP_ENTRY(UA_ReferenceTarget) nameTreeFields;
    UA_UInt32 targetIdHash;   /* Hash of the target's NodeId */
    UA_UInt32 targetNameHash; /* Hash of the target's BrowseName */
    UA_ExpandedNodeId targetId;
} UA_ReferenceTarget;

ZIP_HEAD(UA_ReferenceTargetIdTree, UA_ReferenceTarget);
typedef struct UA_ReferenceTargetIdTree UA_ReferenceTargetIdTree;
ZIP_PROTTYPE(UA_ReferenceTargetIdTree, UA_ReferenceTarget, UA_ReferenceTarget)

ZIP_HEAD(UA_ReferenceTargetNameTree, UA_ReferenceTarget);
typedef struct UA_ReferenceTargetNameTree UA_ReferenceTargetNameTree;
ZIP_PROTTYPE(UA_ReferenceTargetNameTree, UA_ReferenceTarget, UA_UInt32)

/* List of reference targets with the same reference type and direction */
typedef struct {
    UA_NodeId referenceTypeId;
    UA_Boolean isInverse;
    size_t refTargetsSize;
    UA_ReferenceTarget *refTargets;
    UA_ReferenceTargetIdTree refTargetsIdTree;
    UA_ReferenceTargetNameTree refTargetsNameTree;
} UA_NodeReferenceKind;

#define UA_NODE_BASEATTRIBUTES                  \
    UA_NodeId nodeId;                           \
    UA_NodeClass nodeClass;                     \
    UA_QualifiedName browseName;                \
    UA_LocalizedText displayName;               \
    UA_LocalizedText description;               \
    UA_UInt32 writeMask;                        \
    size_t referencesSize;                      \
    UA_NodeReferenceKind *references;           \
                                                \
    /* Members specific to open62541 */         \
    void *context;                              \
    UA_Boolean constructed; /* Constructors were called */

typedef struct {
    UA_NODE_BASEATTRIBUTES
} UA_Node;

/**
 * VariableNode
 * ------------
 *
 * Variables store values in a :ref:`datavalue` together with
 * metadata for introspection. Most notably, the attributes data type, value
 * rank and array dimensions constrain the possible values the variable can take
 * on.
 *
 * Variables come in two flavours: properties and datavariables. Properties are
 * related to a parent with a ``hasProperty`` reference and may not have child
 * nodes themselves. Datavariables may contain properties (``hasProperty``) and
 * also datavariables (``hasComponents``).
 *
 * All variables are instances of some :ref:`variabletypenode` in return
 * constraining the possible data type, value rank and array dimensions
 * attributes.
 *
 * Data Type
 * ^^^^^^^^^
 *
 * The (scalar) data type of the variable is constrained to be of a specific
 * type or one of its children in the type hierarchy. The data type is given as
 * a NodeId pointing to a :ref:`datatypenode` in the type hierarchy. See the
 * Section :ref:`datatypenode` for more details.
 *
 * If the data type attribute points to ``UInt32``, then the value attribute
 * must be of that exact type since ``UInt32`` does not have children in the
 * type hierarchy. If the data type attribute points ``Number``, then the type
 * of the value attribute may still be ``UInt32``, but also ``Float`` or
 * ``Byte``.
 *
 * Consistency between the data type attribute in the variable and its
 * :ref:`VariableTypeNode` is ensured.
 *
 * Value Rank
 * ^^^^^^^^^^
 *
 * This attribute indicates whether the value attribute of the variable is an
 * array and how many dimensions the array has. It may have the following
 * values:
 *
 * - ``n >= 1``: the value is an array with the specified number of dimensions
 * - ``n =  0``: the value is an array with one or more dimensions
 * - ``n = -1``: the value is a scalar
 * - ``n = -2``: the value can be a scalar or an array with any number of dimensions
 * - ``n = -3``: the value can be a scalar or a one dimensional array
 *
 * Consistency between the value rank attribute in the variable and its
 * :ref:`variabletypenode` is ensured.
 *
 * Array Dimensions
 * ^^^^^^^^^^^^^^^^
 *
 * If the value rank permits the value to be a (multi-dimensional) array, the
 * exact length in each dimensions can be further constrained with this
 * attribute.
 *
 * - For positive lengths, the variable value is guaranteed to be of the same
 *   length in this dimension.
 * - The dimension length zero is a wildcard and the actual value may have any
 *   length in this dimension.
 *
 * Consistency between the array dimensions attribute in the variable and its
 * :ref:`variabletypenode` is ensured. */

/* Indicates whether a variable contains data inline or whether it points to an
 * external data source */
typedef enum {
    UA_VALUESOURCE_DATA,
    UA_VALUESOURCE_DATASOURCE
} UA_ValueSource;

#define UA_NODE_VARIABLEATTRIBUTES                                      \
    /* Constraints on possible values */                                \
    UA_NodeId dataType;                                                 \
    UA_Int32 valueRank;                                                 \
    size_t arrayDimensionsSize;                                         \
    UA_UInt32 *arrayDimensions;                                         \
                                                                        \
    /* The current value */                                             \
    UA_ValueSource valueSource;                                         \
    union {                                                             \
        struct {                                                        \
            UA_DataValue value;                                         \
            UA_ValueCallback callback;                                  \
        } data;                                                         \
        UA_DataSource dataSource;                                       \
    } value;

typedef struct {
    UA_NODE_BASEATTRIBUTES
    UA_NODE_VARIABLEATTRIBUTES
    UA_Byte accessLevel;
    UA_Double minimumSamplingInterval;
    UA_Boolean historizing;

    /* Members specific to open62541 */
    UA_Boolean isDynamic; /* Some variables are "static" in the sense that they
                           * are not attached to a dynamic process in the
                           * background. Only dynamic variables conserve source
                           * and server timestamp for the value attribute.
                           * Static variables have timestamps of "now". */
} UA_VariableNode;

/**
 * .. _variabletypenode:
 *
 * VariableTypeNode
 * ----------------
 *
 * VariableTypes are used to provide type definitions for variables.
 * VariableTypes constrain the data type, value rank and array dimensions
 * attributes of variable instances. Furthermore, instantiating from a specific
 * variable type may provide semantic information. For example, an instance from
 * ``MotorTemperatureVariableType`` is more meaningful than a float variable
 * instantiated from ``BaseDataVariable``. */

typedef struct {
    UA_NODE_BASEATTRIBUTES
    UA_NODE_VARIABLEATTRIBUTES
    UA_Boolean isAbstract;

    /* Members specific to open62541 */
    UA_NodeTypeLifecycle lifecycle;
} UA_VariableTypeNode;

/**
 * .. _methodnode:
 *
 * MethodNode
 * ----------
 *
 * Methods define callable functions and are invoked using the :ref:`Call
 * <method-services>` service. MethodNodes may have special properties (variable
 * childen with a ``hasProperty`` reference) with the :ref:`qualifiedname` ``(0,
 * "InputArguments")`` and ``(0, "OutputArguments")``. The input and output
 * arguments are both described via an array of ``UA_Argument``. While the Call
 * service uses a generic array of :ref:`variant` for input and output, the
 * actual argument values are checked to match the signature of the MethodNode.
 *
 * Note that the same MethodNode may be referenced from several objects (and
 * object types). For this, the NodeId of the method *and of the object
 * providing context* is part of a Call request message. */

typedef struct {
    UA_NODE_BASEATTRIBUTES
    UA_Boolean executable;

    /* Members specific to open62541 */
    UA_MethodCallback method;
#if UA_MULTITHREADING >= 100
    UA_Boolean async; /* Indicates an async method call */
#endif
} UA_MethodNode;

/**
 * ObjectNode
 * ----------
 *
 * Objects are used to represent systems, system components, real-world objects
 * and software objects. Objects are instances of an :ref:`object
 * type<objecttypenode>` and may contain variables, methods and further
 * objects. */

typedef struct {
    UA_NODE_BASEATTRIBUTES
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    struct UA_MonitoredItem *monitoredItemQueue;
#endif
    UA_Byte eventNotifier;
} UA_ObjectNode;

/**
 * .. _objecttypenode:
 *
 * ObjectTypeNode
 * --------------
 *
 * ObjectTypes provide definitions for Objects. Abstract objects cannot be
 * instantiated. See :ref:`node-lifecycle` for the use of constructor and
 * destructor callbacks. */

typedef struct {
    UA_NODE_BASEATTRIBUTES
    UA_Boolean isAbstract;

    /* Members specific to open62541 */
    UA_NodeTypeLifecycle lifecycle;
} UA_ObjectTypeNode;

/**
 * .. _referencetypenode:
 *
 * ReferenceTypeNode
 * -----------------
 *
 * Each reference between two nodes is typed with a ReferenceType that gives
 * meaning to the relation. The OPC UA standard defines a set of ReferenceTypes
 * as a mandatory part of OPC UA information models.
 *
 * - Abstract ReferenceTypes cannot be used in actual references and are only
 *   used to structure the ReferenceTypes hierarchy
 * - Symmetric references have the same meaning from the perspective of the
 *   source and target node
 *
 * The figure below shows the hierarchy of the standard ReferenceTypes (arrows
 * indicate a ``hasSubType`` relation). Refer to Part 3 of the OPC UA
 * specification for the full semantics of each ReferenceType.
 *
 * .. graphviz::
 *
 *    digraph tree {
 *
 *    node [height=0, shape=box, fillcolor="#E5E5E5", concentrate=true]
 *
 *    references [label="References\n(Abstract, Symmetric)"]
 *    hierarchical_references [label="HierarchicalReferences\n(Abstract)"]
 *    references -> hierarchical_references
 *
 *    nonhierarchical_references [label="NonHierarchicalReferences\n(Abstract, Symmetric)"]
 *    references -> nonhierarchical_references
 *
 *    haschild [label="HasChild\n(Abstract)"]
 *    hierarchical_references -> haschild
 *
 *    aggregates [label="Aggregates\n(Abstract)"]
 *    haschild -> aggregates
 *
 *    organizes [label="Organizes"]
 *    hierarchical_references -> organizes
 *
 *    hascomponent [label="HasComponent"]
 *    aggregates -> hascomponent
 *
 *    hasorderedcomponent [label="HasOrderedComponent"]
 *    hascomponent -> hasorderedcomponent
 *
 *    hasproperty [label="HasProperty"]
 *    aggregates -> hasproperty
 *
 *    hassubtype [label="HasSubtype"]
 *    haschild -> hassubtype
 *
 *    hasmodellingrule [label="HasModellingRule"]
 *    nonhierarchical_references -> hasmodellingrule
 *
 *    hastypedefinition [label="HasTypeDefinition"]
 *    nonhierarchical_references -> hastypedefinition
 *
 *    hasencoding [label="HasEncoding"]
 *    nonhierarchical_references -> hasencoding
 *
 *    hasdescription [label="HasDescription"]
 *    nonhierarchical_references -> hasdescription
 *
 *    haseventsource [label="HasEventSource"]
 *    hierarchical_references -> haseventsource
 *
 *    hasnotifier [label="HasNotifier"]
 *    hierarchical_references -> hasnotifier
 *
 *    generatesevent [label="GeneratesEvent"]
 *    nonhierarchical_references -> generatesevent
 *
 *    alwaysgeneratesevent [label="AlwaysGeneratesEvent"]
 *    generatesevent -> alwaysgeneratesevent
 *
 *    {rank=same hierarchical_references nonhierarchical_references}
 *    {rank=same generatesevent haseventsource hasmodellingrule
 *               hasencoding hassubtype}
 *    {rank=same alwaysgeneratesevent hasproperty}
 *
 *    }
 *
 * The ReferenceType hierarchy can be extended with user-defined ReferenceTypes.
 * Many Companion Specifications for OPC UA define new ReferenceTypes to be used
 * in their domain of interest.
 *
 * For the following example of custom ReferenceTypes, we attempt to model the
 * structure of a technical system. For this, we introduce two custom
 * ReferenceTypes. First, the hierarchical ``contains`` ReferenceType indicates
 * that a system (represented by an OPC UA object) contains a component (or
 * subsystem). This gives rise to a tree-structure of containment relations. For
 * example, the motor (object) is contained in the car and the crankshaft is
 * contained in the motor. Second, the symmetric ``connectedTo`` ReferenceType
 * indicates that two components are connected. For example, the motor's
 * crankshaft is connected to the gear box. Connections are independent of the
 * containment hierarchy and can induce a general graph-structure. Further
 * subtypes of ``connectedTo`` could be used to differentiate between physical,
 * electrical and information related connections. A client can then learn the
 * layout of a (physical) system represented in an OPC UA information model
 * based on a common understanding of just two custom reference types. */

typedef struct {
    UA_NODE_BASEATTRIBUTES
    UA_Boolean isAbstract;
    UA_Boolean symmetric;
    UA_LocalizedText inverseName;
} UA_ReferenceTypeNode;

/**
 * .. _datatypenode:
 *
 * DataTypeNode
 * ------------
 *
 * DataTypes represent simple and structured data types. DataTypes may contain
 * arrays. But they always describe the structure of a single instance. In
 * open62541, DataTypeNodes in the information model hierarchy are matched to
 * ``UA_DataType`` type descriptions for :ref:`generic-types` via their NodeId.
 *
 * Abstract DataTypes (e.g. ``Number``) cannot be the type of actual values.
 * They are used to constrain values to possible child DataTypes (e.g.
 * ``UInt32``). */

typedef struct {
    UA_NODE_BASEATTRIBUTES
    UA_Boolean isAbstract;
} UA_DataTypeNode;

/**
 * ViewNode
 * --------
 *
 * Each View defines a subset of the Nodes in the AddressSpace. Views can be
 * used when browsing an information model to focus on a subset of nodes and
 * references only. ViewNodes can be created and be interacted with. But their
 * use in the :ref:`Browse<view-services>` service is currently unsupported in
 * open62541. */

typedef struct {
    UA_NODE_BASEATTRIBUTES
    UA_Byte eventNotifier;
    UA_Boolean containsNoLoops;
} UA_ViewNode;

/**
 * Nodestore Plugin API
 * --------------------
 *
 * The following definitions are used for implementing custom node storage
 * backends. **Most users will want to use the default nodestore and don't need
 * to work with the nodestore API**.
 *
 * Outside of custom nodestore implementations, users should not manually edit
 * nodes. Please use the OPC UA services for that. Otherwise, all consistency
 * checks are omitted. This can crash the application eventually. */

typedef void (*UA_NodestoreVisitor)(void *visitorCtx, const UA_Node *node);

typedef struct {
    /* Nodestore context and lifecycle */
    void *context;
    void (*clear)(void *nsCtx);

    /* The following definitions are used to create empty nodes of the different
     * node types. The memory is managed by the nodestore. Therefore, the node
     * has to be removed via a special deleteNode function. (If the new node is
     * not added to the nodestore.) */
    UA_Node * (*newNode)(void *nsCtx, UA_NodeClass nodeClass);

    void (*deleteNode)(void *nsCtx, UA_Node *node);

    /* ``Get`` returns a pointer to an immutable node. ``Release`` indicates
     * that the pointer is no longer accessed afterwards. */
    const UA_Node * (*getNode)(void *nsCtx, const UA_NodeId *nodeId);

    void (*releaseNode)(void *nsCtx, const UA_Node *node);

    /* Returns an editable copy of a node (needs to be deleted with the
     * deleteNode function or inserted / replaced into the nodestore). */
    UA_StatusCode (*getNodeCopy)(void *nsCtx, const UA_NodeId *nodeId,
                                 UA_Node **outNode);

    /* Inserts a new node into the nodestore. If the NodeId is zero, then a
     * fresh numeric NodeId is assigned. If insertion fails, the node is
     * deleted. */
    UA_StatusCode (*insertNode)(void *nsCtx, UA_Node *node,
                                UA_NodeId *addedNodeId);

    /* To replace a node, get an editable copy of the node, edit and replace
     * with this function. If the node was already replaced since the copy was
     * made, UA_STATUSCODE_BADINTERNALERROR is returned. If the NodeId is not
     * found, UA_STATUSCODE_BADNODEIDUNKNOWN is returned. In both error cases,
     * the editable node is deleted. */
    UA_StatusCode (*replaceNode)(void *nsCtx, UA_Node *node);

    /* Removes a node from the nodestore. */
    UA_StatusCode (*removeNode)(void *nsCtx, const UA_NodeId *nodeId);

    /* Execute a callback for every node in the nodestore. */
    void (*iterate)(void *nsCtx, UA_NodestoreVisitor visitor,
                    void *visitorCtx);
} UA_Nodestore;

/* Attributes must be of a matching type (VariableAttributes, ObjectAttributes,
 * and so on). The attributes are copied. Note that the attributes structs do
 * not contain NodeId, NodeClass and BrowseName. The NodeClass of the node needs
 * to be correctly set before calling this method. UA_Node_clear is called on
 * the node when an error occurs internally. */
UA_StatusCode UA_EXPORT
UA_Node_setAttributes(UA_Node *node, const void *attributes,
                      const UA_DataType *attributeType);

/* Reset the destination node and copy the content of the source */
UA_StatusCode UA_EXPORT
UA_Node_copy(const UA_Node *src, UA_Node *dst);

/* Allocate new node and copy the values from src */
UA_EXPORT UA_Node *
UA_Node_copy_alloc(const UA_Node *src);

/* Add a single reference to the node */
UA_StatusCode UA_EXPORT
UA_Node_addReference(UA_Node *node, const UA_AddReferencesItem *item,
                     UA_UInt32 targetBrowseNameHash);

/* Delete a single reference from the node */
UA_StatusCode UA_EXPORT
UA_Node_deleteReference(UA_Node *node, const UA_DeleteReferencesItem *item);

/* Delete all references of the node */
void UA_EXPORT
UA_Node_deleteReferences(UA_Node *node);

/* Remove all malloc'ed members of the node and reset */
void UA_EXPORT
UA_Node_clear(UA_Node *node);

_UA_END_DECLS

#endif /* UA_SERVER_NODES_H_ */
