import config from 'config';
import recycle from 'recycle';
export default (function () {
/**
* This class defines a set that is populated and then pulled from at random. When pulled from, the set will return copies of the contents
* such that all the contents in the set are used once before there are repeats. Repeats may still occur when the set has been used
* up or when the number of items requested is greater than the size of the set.
*
* @memberof platypus
* @class RandomSet
* @param contents {array} The contents that will populate the set.
* @return {platypus.RandomSet} Returns the new RandomSet object.
*/
const RandomSet = function (contents) {
let x = 0;
if (contents) {
this.contents = [];
for (x = 0; x < contents.length; x++) {
this.contents.push(contents[x]);
}
} else {
this.contents = [];
}
this.availableIndexes = [];
this.refill();
},
proto = RandomSet.prototype;
proto.refill = function () {
let x = 0;
for (x = 0; x < this.contents.length; x++) {
this.availableIndexes.push(x);
}
};
/**
* Add single element to the content set. Includes the new content in the current set, which means it be returned quickly depending on the remaining set size.
*
* @method platypus.RandomSet#add
* @param toAdd {primitive|Object} Content to add to the set.
*/
proto.add = function (toAdd) {
this.contents.push(toAdd);
this.availableIndexes.push(this.contents.length - 1);
};
/**
* Remove from the content set. Use removeAll if you want to remove all instances, otherwise only removes the first instance found.
*
* @method platypus.RandomSet#remove
* @param toRemove {primitive|Object} Content to remove from the set.
* @param removeAll {boolean} Remove all instances of the primitive/object.
*/
proto.remove = function (toRemove, removeAll) {
let index = -1,
indexesIndex = -1;
do {
index = this.contents.indexOf(toRemove);
if (index !== -1) {
this.contents.splice(index, 1);
indexesIndex = this.availableIndexes.indexOf(index);
this.availableIndexes.splice(indexesIndex, 1);
// Now we need to re-index entries above index...
for (let i = 0; i < this.availableIndexes; i++) {
if (this.availableIndexes[i] > index) {
this.availableIndexes[i] -= 1;
}
}
}
} while (index !== -1 && removeAll);
};
/**
* Get a random member of the set.
*
* @method platypus.RandomSet#get
* @return {primitive|Object} A random member of the set
*/
proto.get = function () {
let index = 0;
if (this.availableIndexes.length === 0) {
this.refill();
}
index = this.availableIndexes.splice(Math.floor(Math.random() * this.availableIndexes.length), 1)[0];
return this.contents[index];
};
/**
* Get an array of random set members. There may be multiple of the same member in the set if the quantity requested is greater
* than the set size, or the set is exhausted and replenished while retrieving members.
*
* @method platypus.RandomSet#getMultiple
* @param numberToGet {integer} Number of set members to retrieve
* @return {primitive|Object} A random member of the set
*/
proto.getMultiple = function (numberToGet) {
const toReturn = [];
let x = 0;
for (x = 0; x < numberToGet; x++) {
toReturn.push(this.get());
}
return toReturn;
};
/**
* Returns an RandomSet from cache or creates a new one if none are available.
*
* @method platypus.RandomSet.setUp
* @return {platypus.RandomSet} The instantiated RandomSet.
*/
/**
* Returns a RandomSet back to the cache.
*
* @method platypus.RandomSet.recycle
* @param {platypus.RandomSet} randomSet The RandomSet to be recycled.
*/
/**
* Relinquishes properties of the RandomSet and recycles it.
*
* @method platypus.RandomSet#recycle
*/
recycle.add(RandomSet, 'RandomSet', RandomSet, null, true, config.dev);
return RandomSet;
}());