APIs

Show:
"use strict";

/**
 * @module opcua.address_space
 */

var assert = require("node-opcua-assert");
var util = require("util");

var BaseNode = require("./base_node").BaseNode;
var NodeClass = require("node-opcua-data-model").NodeClass;
var AttributeIds = require("node-opcua-data-model").AttributeIds;
var DataValue =  require("node-opcua-data-value").DataValue;
var DataType = require("node-opcua-variant").DataType;
var StatusCodes = require("node-opcua-status-code").StatusCodes;

var SessionContext = require("./session_context").SessionContext;

var coerceLocalizedText = require("node-opcua-data-model").coerceLocalizedText;

var ReferenceTypeCounter=0;

/**
 * @class ReferenceType
 * @extends  BaseNode
 * @param options
 * @constructor
 */
function ReferenceType(options) {
    BaseNode.apply(this, arguments);
    this.isAbstract = (options.isAbstract === null) ? false : options.isAbstract;
    this.symmetric = (options.symmetric === null) ? false : options.symmetric;
    this.inverseName = coerceLocalizedText(options.inverseName);

    ReferenceTypeCounter +=1;
    
}
util.inherits(ReferenceType, BaseNode);
ReferenceType.prototype.nodeClass = NodeClass.ReferenceType;

/**
 *
 * @method readAttribute
 * @param attributeId {AttributeIds}
 * @param [indexRange {NumericalRange}]
 * @param [dataEncoding {String}]
 * @return {DataValue}
 */
ReferenceType.prototype.readAttribute = function (context, attributeId, indexRange, dataEncoding) {

    assert(context instanceof SessionContext);

    var options = {};
    switch (attributeId) {
        case AttributeIds.IsAbstract:
            options.value = {dataType: DataType.Boolean, value: this.isAbstract ? true : false};
            options.statusCode = StatusCodes.Good;
            break;
        case AttributeIds.Symmetric:
            options.value = {dataType: DataType.Boolean, value: this.symmetric ? true : false};
            options.statusCode = StatusCodes.Good;
            break;
        case AttributeIds.InverseName: // LocalizedText
            options.value = {dataType: DataType.LocalizedText, value: this.inverseName};
            options.statusCode = StatusCodes.Good;
            break;
        default:
            return BaseNode.prototype.readAttribute.call(this, context, attributeId);
    }
    return new DataValue(options);
};
exports.ReferenceType = ReferenceType;


var tools = require("./tool_isSupertypeOf");
/**
 * returns true if self is  a super type of baseType
 * @method isSupertypeOf
 * @param baseType {ReferenceType}
 * @return {Boolean}  true if self is a Subtype of baseType
 *
 *
 * @example
 *
 *
 */
ReferenceType.prototype.isSupertypeOf = tools.construct_isSupertypeOf(ReferenceType);

ReferenceType.prototype._slow_isSupertypeOf = tools.construct_slow_isSupertypeOf(ReferenceType);

ReferenceType.prototype.toString = function () {
    var str = "";
    str += this.isAbstract ? "A" : " ";
    str += this.symmetric ? "S" : " ";
    str += " " + this.browseName.toString() + "/" + this.inverseName.text + " ";
    str += this.nodeId.toString();
    return str;
};


function findAllSubTypes(referenceType) {

    var addressSpace = referenceType.addressSpace;
    var possibleReferenceTypes = [];

    function _findAllSubType(referenceType) {
        possibleReferenceTypes.push(referenceType);
        assert(referenceType.nodeClass === NodeClass.ReferenceType);
        var references = referenceType.findReferences("HasSubtype", true);
        references.forEach(function (_r) {
            var subType = addressSpace.findNode(_r.nodeId);
            _findAllSubType(subType);
        });
    }
    _findAllSubType(referenceType);

    return possibleReferenceTypes;
}

/**
 * returns a array of all ReferenceTypes in the addressSpace that are self or a subType of self
 * @method getAllSubtypes
 * @return {ReferenceType[]}
 */
ReferenceType.prototype.getAllSubtypes = function() {

    if (!this._cache._allSubTypesVersion || this._cache._allSubTypesVersion < ReferenceTypeCounter) {

        this._cache._allSubTypes = null;
    }
    if (!this._cache._allSubTypes) {
        this._cache._allSubTypes = findAllSubTypes(this);
        this._cache._allSubTypesVersion = ReferenceTypeCounter;
    }
    return this._cache._allSubTypes;
};
function _get_idx(referenceType)  {

    var possibleReferenceTypes = referenceType.getAllSubtypes();
    // create a index of reference type with browseName as key for faster search
    var keys = {};
    possibleReferenceTypes.forEach(function(refType){
        keys[refType.browseName.toString()]= refType;
    });

    return keys;
}
ReferenceType.prototype.getSubtypeIndex = function() {
    if (this._cache._subtype_idxVersion < ReferenceTypeCounter) {
        this._cache._subtype_idx = null;
    } else {
    }
    if (!this._cache._subtype_idx) {
        this._cache._subtype_idx = _get_idx(this);
        this._cache._subtype_idxVersion = ReferenceTypeCounter;
    }
    return this._cache._subtype_idx;

};

ReferenceType.prototype.is = function(referenceTypeString) {
    return this.getSubtypeIndex().hasOwnProperty(referenceTypeString);
};

ReferenceType.prototype.install_extra_properties = function () {
    //
};

exports.ReferenceType = ReferenceType;