/**
* @copyright 2015 Tridium, Inc. All Rights Reserved.
* @author Gareth Johnson
*/
/**
* Defines {@link baja.OrderedMap}.
* @module baja/sys/structures/OrderedMap
* @private
*/
define([ "bajaScript/baja/sys/BaseBajaObj",
"bajaScript/baja/sys/bajaUtils",
"bajaScript/baja/sys/inherit",
"bajaScript/baja/sys/structures/FilterCursor" ], function (
BaseBajaObj,
bajaUtils,
inherit,
FilterCursor) {
"use strict";
var subclass = inherit.subclass,
callSuper = inherit.callSuper,
strictArg = bajaUtils.strictArg;
/**
* Maintains an ordered list of key/value pairs.
*
* This object forms the basis of a Complex's Slot Map.
*
* @class
* @alias baja.OrderedMap
* @extends baja.BaseBajaObj
* @private
* @param {object} [obj] initial object literal to populate the map
*/
const OrderedMap = function OrderedMap(obj) {
callSuper(OrderedMap, this, arguments);
let map, array;
if (obj) {
map = Object.assign({}, obj);
array = Object.keys(obj);
} else {
map = {};
array = [];
}
this.$map = map;
this.$array = array;
};
subclass(OrderedMap, BaseBajaObj);
/**
* Assign the value to the Map with the given key.
*
* @param {String} key the key used for the entry in the Map
* @param val the value used to store in the Map
*/
OrderedMap.prototype.put = function (key, val) {
if (!this.$map.hasOwnProperty(key)) {
this.$map[key] = val;
this.$array.push(key);
} else {
this.$map[key] = val;
}
};
/**
* Remove a value from the map and return it.
*
* @param {String} key the key used to remove the value.
* @returns the value removed (return null if nothing is found to be removed).
*/
OrderedMap.prototype.remove = function (key) {
strictArg(key, String);
var v,
i,
map = this.$map,
array = this.$array;
if (!map.hasOwnProperty(key)) {
return null;
}
v = map[key];
// Remove the element from the Map
delete map[key];
// Find and remove the key from the array
for (i = 0; i < array.length; ++i) {
if (array[i] === key) {
array.splice(i, 1);
break;
}
}
return v;
};
/**
* Query the Map to see if it contains the key.
*
* @param {String} key
* @returns {Boolean} a boolean value indicating if the Map contains the key.
*/
OrderedMap.prototype.contains = function (key) {
strictArg(key, String);
return this.$map.hasOwnProperty(key);
};
/**
* Return the value for the key.
*
* @param {String} key
* @returns the value for the key (return null if key is not found in Map).
*/
OrderedMap.prototype.get = function (key) {
var map = this.$map;
return map.hasOwnProperty(key) ? map[key] : null;
};
/**
* Rename an entry.
*
* @param {String} oldName the name of the existing entry to be renamed.
* @param {String} newName the new name of the entry.
* @returns {Boolean} true if the entry was successfully renamed.
*/
OrderedMap.prototype.rename = function (oldName, newName) {
strictArg(oldName, String);
strictArg(newName, String);
if (!this.contains(oldName)) {
return false;
}
if (this.contains(newName)) {
return false;
}
// Get existing entry
var entry = this.$map[oldName];
delete this.$map[oldName];
// Create new entry
this.$map[newName] = entry;
// Update array
var i;
for (i = 0; i < this.$array.length; ++i) {
if (this.$array[i] === oldName) {
this.$array[i] = newName;
break;
}
}
return true;
};
/**
* Return the key's index.
*
* @param {String} key
* @returns {Number} the index for the key (return -1 if key is not found in Map).
*/
OrderedMap.prototype.getIndex = function (key) {
strictArg(key, String);
if (this.$map.hasOwnProperty(key)) {
var i;
for (i = 0; i < this.$array.length; ++i) {
if (this.$array[i] === key) {
return i;
}
}
}
return -1;
};
/**
* Return the value for the index.
*
* @param {Number} index
* @returns the value for the index (return null if index is not found in Map).
*/
OrderedMap.prototype.getFromIndex = function (index) {
strictArg(index, Number);
var key = this.$array[index];
if (typeof key === "string") {
return this.$map[key];
}
return null;
};
/**
* Return an ordered array of keys for iteration.
*
* Please note, a copy of the internal array will be returned.
*
* @returns {Array} an array of keys that can be used for iteration.
*/
OrderedMap.prototype.getKeys = function () {
// Return a copy of the array
return this.$array.slice(0);
};
/**
* Return the size of the Map.
*
* @returns {Number} the size of the Map.
*/
OrderedMap.prototype.getSize = function () {
return this.$array.length;
};
/**
* Sort the Map.
*
* @see Array#sort
*
* @param {Function} sortFunc Function used to sort the map. This definition of the Function
* should be the same as the one passed into a JavaScript Array's
* sort method.
*/
OrderedMap.prototype.sort = function (sortFunc) {
strictArg(sortFunc, Function);
this.$array.sort(sortFunc);
};
/**
* Return a Cursor used for iteration.
*
* @param context used as 'this' in iteration operations
* @param {Function} [Cursor=baja.FilterCursor] the Constructor of the
* `Cursor` to use for the Map.
*
* @returns {baja.Cursor} Cursor used for iteration
*/
OrderedMap.prototype.getCursor = function (context, Cursor) {
Cursor = Cursor || FilterCursor;
return new Cursor(context, this);
};
return OrderedMap;
});