"use strict";
/**
* @module opcua.miscellaneous
*
*/
/**
* @class Enum
* @constructor
* Represents an Item of an Enum.
* @param {String} key The Enum key.
* @param {Number} value The Enum value.
*/
const EnumItem = function (key, value) {
this.key = key;
this.value = value;
};
/**
* Checks if the EnumItem is the same as the passing object.
* @method is
* @param {EnumItem | String | Number} item The object to check with.
* @return {Boolean} The check result.
*/
EnumItem.prototype.is = function (item) {
if (item instanceof EnumItem) {
return this.value === item.value;
} else if (typeof item === 'string') {
return this.key === item;
} else {
return this.value === item;
}
};
/**
* Checks if the flagged EnumItem has the passing object.
* @method has
* @param {EnumItem | String |Number} value The object to check with.
* @return {Boolean} The check result.
*/
EnumItem.prototype.has = function (value) {
if (value instanceof EnumItem) {
return (value.value & this.value) !== 0;
} else if (typeof value === 'string') {
return this.key.indexOf(value) >= 0;
} else {
return (value & this.value) !== 0;
}
};
/**
* Returns String representation of this EnumItem.
* @method toString
* @return {String} String representation of this EnumItem.
*/
EnumItem.prototype.toString = function toString() {
return this.key;
};
/**
* Returns JSON object representation of this EnumItem.
* @method toJSON
* @return {String} JSON object representation of this EnumItem.
*/
EnumItem.prototype.toJSON = function toJSON() {
return this.key;
};
/**
* Returns the value to compare with.
* @method valueOf
* @return {String} The value to compare with.
*/
EnumItem.prototype.valueOf = function valueOf() {
return this.value;
};
// check if enum is flaggable
const check_is_flaggable = function (enums) {
for (const i in enums) {
const e = enums[i];
if (!(e.value !== 0 && !(e.value & e.value - 1))) {
return false;
}
}
return true;
};
/**
* @class Enum
* @constructor
* Represents an Enum with enum items.
* @param {Array || Object} map This are the enum items.
*/
const Enum = function (map) {
const self = this;
self.enums = [];
let mm = null;
let is_flaggable = null;
if (Array.isArray(map)) {
// create map as flaggable enum
mm = {};
for (let i = 0; i < map.length; i++) {
mm[map[i]] = 1 << i;
}
is_flaggable = true;
} else {
mm = map;
}
for (const key in mm) {
const val = mm[key];
if (undefined === val) { continue; }
const kv = new EnumItem(key, val);
self[key] = kv;
self[val] = kv;
self.enums.push(kv);
}
if (!is_flaggable) {
is_flaggable = check_is_flaggable(self.enums);
}
this._is_flaggable = is_flaggable;
};
/**
* Returns the appropriate EnumItem.
* @method get
* @param {EnumItem || String || Number} key The object to get with.
* @return {EnumItem} The get result.
*/
Enum.prototype.get = function (key) {
if (key instanceof EnumItem) {
//xx console.log("sssss");
if (!this[key.key]){ throw new Error("Invalid key"); }
return key;
}
if (key === null || key === undefined) {
return null;
}
const prop = this[key];
if (prop) {
return prop;
} else if (this._is_flaggable) {
if (typeof key === "string") {
return this._get_by_str(key);
} else if (typeof key === "number") {
return this._get_by_num(key);
}
}
};
Enum.prototype._get_by_str = function (key) {
const parts = key.split(' | ');
let val = 0;
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
const item = this[part];
if (undefined === item) {
return undefined;
}
val |= item.value;
}
const kv = new EnumItem(key, val);
// add in cache for later
let prop = this[val];
if (prop === undefined) {
this[val] = kv;
}
prop = this[key];
if (prop === undefined) {
this[key] = kv;
}
return kv;
};
Enum.prototype._get_by_num = function (key) {
if (key === 0) { return undefined; }
let name;
let c = 1, item;
for (let i = 0; c < key; i++) {
if ((c & key) === c) {
item = this[c];
if (undefined === item) {
return undefined;
}
if (name) {
name = name + " | " + item.key;
} else {
name = item.key;
}
}
c *= 2;
}
const kv = new EnumItem(name, key);
// add in cache for later
this[name] = kv;
this[key] = kv;
return kv;
};
module.exports = Enum;