import DataMap from './DataMap.js';
import {arrayCache} from './utils/array.js';
import config from 'config';
import {greenSplit} from './utils/string.js';
import recycle from 'recycle';
export default (function () {
/**
* This class defines a state object to use for entity states with helper methods. It includes recycle methods to encourage reuse.
*
* @memberof platypus
* @class StateMap
* @extends platypus.DataMap
* @return stateMap {platypus.StateMap} Returns the new StateMap object.
*/
var StateMap = function (first) {
var l = arguments.length;
if (l) {
if ((l === 1) && (typeof first === 'string')) {
DataMap.call(this);
this.updateFromString(first);
} else {
DataMap.apply(this, arguments);
}
} else {
DataMap.call(this);
}
},
parent = DataMap.prototype,
proto = StateMap.prototype = Object.create(parent);
Object.defineProperty(StateMap.prototype, 'constructor', {
configurable: true,
writable: true,
value: StateMap
});
/**
* Sets the state using the provided string value which is a comma-delimited list such that `"blue,red,!green"` sets the following state values:
*
* {
* red: true,
* blue: true,
* green: false
* }
*
* @method platypus.StateMap#updateFromString
* @param states {String} A comma-delimited list of true/false state values.
* @chainable
*/
Object.defineProperty(proto, 'updateFromString', {
value: function (states) {
var arr = greenSplit(states, ','),
i = arr.length,
str = '';
while (i--) {
str = arr[i];
if (str) {
if (str.substr(0, 1) === '!') {
this.set(str.substr(1), false);
} else {
this.set(str, true);
}
}
}
arrayCache.recycle(arr);
return this;
}
});
/**
* Checks whether the provided state matches this state and updates this state to match.
*
* @method platypus.StateMap#update
* @param state {platypus.StateMap} The state that this state should match.
* @return {Boolean} Whether this state already matches the provided state.
*/
Object.defineProperty(proto, 'update', {
value: function (newState) {
var keys = newState.keys,
i = keys.length,
state = '',
changed = false,
value = false;
while (i--) {
state = keys[i];
value = newState.get(state);
if (this.get(state) !== value) {
this.set(state, value);
changed = true;
}
}
return changed;
}
});
/**
* Checks whether the provided state matches all equivalent keys on this state.
*
* @method platypus.StateMap#includes
* @param state {platypus.StateMap} The state that this state should match.
* @return {Boolean} Whether this state matches the provided state.
*/
Object.defineProperty(proto, 'includes', {
value: function (otherState) {
var keys = otherState.keys,
i = keys.length,
state = '';
while (i--) {
state = keys[i];
if (this.get(state) !== otherState.get(state)) {
return false;
}
}
return true;
}
});
/**
* Checks whether the provided state matches any equivalent keys on this state.
*
* @method platypus.StateMap#intersects
* @param state {platypus.StateMap} The state that this state should intersect.
* @return {Boolean} Whether this state intersects the provided state.
*/
Object.defineProperty(proto, 'intersects', {
value: function (otherState) {
var keys = otherState.keys,
i = keys.length,
state = '';
while (i--) {
state = keys[i];
if (this.get(state) === otherState.get(state)) {
return true;
}
}
return false;
}
});
/**
* Returns StateMap from cache or creates a new one if none are available.
*
* @method platypus.StateMap.setUp
* @return {platypus.StateMap} The instantiated StateMap.
*/
/**
* Returns StateMap back to the cache. Prefer the StateMap's recycle method since it recycles property objects as well.
*
* @method platypus.StateMap.recycle
* @param {platypus.StateMap} stateMap The StateMap to be recycled.
*/
/**
* Relinquishes StateMap properties and recycles it.
*
* @method platypus.StateMap#recycle
*/
recycle.add(StateMap, 'StateMap', StateMap, function () {
this.clear();
}, true, config.dev);
return StateMap;
}());