File: src/components/map/core/MapDataManipulator.js
(function mapDataManipulatorCreator() {
/*-----------------------
------- VARIABLES -------
-----------------------*/
const mapLayers = window.flatworld.mapLayers;
const objects = window.flatworld.objects;
const utils = window.flatworld.utils;
/*---------------------
--------- API ---------
----------------------*/
class MapDataManipulator {
/**
* Class to get a consistent standard for the engine to be able to filter objects, when
* etrieving or sorting them. This is used
* when some method uses filters.
*
* You must provide an object that defines how the given objects should be filtered, when
* constructing. The module will filter with every rule and object given and everything that
* doesn't pass one of the given filters, will be dropped out.
*
* Given filters look something like this:
* {
* type: 'filter',
* object: 'layer',
* property: 'selectable', // THIS can also be an array, like: ['data', 'a'] => data.a
* value: true,
* }
* For more information, please check the mapDataManipulatorSpec.js (test) for now.
*
* @namespace flatworld
* @class MapDataManipulator
* @constructor
* @param {Array|Object} rules REQUIRED. The rules that apply for this instance.
* Multiple rules in Array or one as Object.
**/
constructor(rules = utils.general.requireParameter('MapDataManipulator', 'rules')) {
this.rules = Array.isArray(rules) ? rules : [rules];
this.classes = {
layer: Object.keys(mapLayers).map((k) => mapLayers[k]),
object: Object.keys(objects).map((k) => objects[k]),
};
}
/**
* This has exceptional query, since it actually queries it's parent. Subcontainers have
* really no useful values and they are dumb
* containers of objects, every data is on their parent container
*
* @method filter
* @param {Array | Object} objects The objects that are being filtered
* @return {Array} The found objects in an Array
*/
filter(objects) {
var found;
if (!Array.isArray(objects)) {
found = this._runRule(objects) ? [objects] : [];
} else {
found = objects.filter((object) => {
return this._runRule(object);
});
}
return found;
}
/**
* adds a filter rule
*
* @method addRule
* @param {} rules Rules to add
*/
addRule(rules) {
this.rules.concat(rules);
}
/** @todo I think this should be implemented. But it's a small optimization so don't bother yet. Basically the idea is to ONLY use the filters that each situation requires. Not iterate through the unneeded filters */
getOnlyFiltersOf(/*type*/) { }
/**
* Checks if this filter instance is set to filter the given type.
*
* @param {string} type Type of the filter we want to check
* @return {Boolean}
*/
doesItFilter(type) {
return this.rules.some(o => o.object === type);
}
/**
* This is the actual method that runs through the rules and arranges the data
*
* @method _runRule
* @private
* @param {Array} [varname] [description]
**/
_runRule(object) {
var ruleMatches = true;
var matchedType;
Object.keys(this.classes).forEach((type) => {
var filtered = this.classes[type].filter((thisClass) => {
return object instanceof thisClass;
});
matchedType = filtered.length ? type : matchedType;
});
this.rules.forEach((rule) => {
if (rule.type === 'filter') {
if (rule.object !== matchedType) {
return;
}
if (matchedType === 'layer') {
ruleMatches = this._getObject(object, rule);
} else if (matchedType === 'object') {
ruleMatches = this._getObject(object, rule);
}
}
});
return ruleMatches;
}
/**
* This is the actual method that runs through the rules and arranges the data
*
* @method _getObject
* @private
* @return {[type]} [description]
**/
_getObject(object, rule) {
let result = false;
if (Array.isArray(rule.property)) {
try {
result = ''+MapDataManipulator.getPropertyWithArray(object, rule.property, 0) === ''+rule.value;
} catch(e) {
return false;
}
} else {
result = object[rule.property] === rule.value;
}
return result;
}
static getPropertyWithArray(obj, array, index) {
const currentProperty = array[index];
const thisLevel = obj[currentProperty];
if (array[index + 1]) {
return MapDataManipulator.getPropertyWithArray(thisLevel, array, ++index);
} else {
return thisLevel;
}
}
}
MapDataManipulator.OBJECT_LAYER = 'layer';
MapDataManipulator.OBJECT_OBJECT = 'object';
window.flatworld.MapDataManipulator = MapDataManipulator;
}());