/**
* Creates a new SoupPermutations object
*
* @constructor
* @param {array} set The set to permute
*/
function SoupPermutations(set) {
// Always working reference to this
var self = this;
// Verify that the set is an array
if (!(set instanceof Array))
throw "Given set is not an array";
if (set.length < 1)
throw "Need at least one item to permute. " + set.length + " given";
// Copy the set
var set = (function() {
var copy = [];
for (var i = 0; i < set.length; i++) {
copy.push(set[i]);
}
return copy;
})();
var setItems = set.length;
// Place to hold the current order of the objects
var currentPermutation = 0;
var possiblePermutations = (function() {
var product = 1;
for (var i = 1; i <= set.length; i++) {
product *= i;
}
return product;
})();
Object.defineProperties(this, {
/**
* Number of the current permutation
*
* @return {number}
* @memberof SoupPermutations
* @instance
*/
currentPermutationNumber: {get: function() {return currentPermutation;}},
/**
* Number of possible permutations of this set
*
* @return {number}
* @memberof SoupPermutations
* @instance
*/
possiblePermutations: {get: function() {return possiblePermutations;}}
});
var currentPermutationArray = [];
for (var i = setItems-1; i >= 0; i--) {
currentPermutationArray.push(i);
}
/**
* Checks if more permutations can be made from the set
*
* @return {boolean} True if more permutations can be made, false otherwise
*/
this.hasNext = function() {
var hasNext = self.currentPermutationNumber != self.possiblePermutations;
if (!hasNext) {
self.next = function() {
throw "All possible permutations have been generated";
};
}
return hasNext;
};
/**
* Calculate and return the next permutation. Will throw an exception if called when {@SoupPermutations#hasNext} returns false
*
* @return {Array} An array with the next permutation of the set
*/
this.next = function() {
currentPermutation++;
// Find first item from the right which is greater than the one on it's left
var i;
for (i = setItems-2; i >= 0; i--) {
if (currentPermutationArray[i] < currentPermutationArray[i+1]) {
break;
}
}
// Find first item from the right which is greater than the one on position i
var j;
for (j = setItems-1; j >= 0; j--) {
if (currentPermutationArray[j] > currentPermutationArray[i]) {
// Swap the items on i and j
var tmp = currentPermutationArray[j];
currentPermutationArray[j] = currentPermutationArray[i];
currentPermutationArray[i] = tmp;
break;
}
}
// Reverse the items from i+1 to the end
i = i+1;
j = setItems-1;
while (i < j) {
var tmp = currentPermutationArray[i];
currentPermutationArray[i] = currentPermutationArray[j];
currentPermutationArray[j] = tmp;
i++;
j--;
}
return self.current();
};
/**
* Gets a copy of the current permutation
*
* @return {Array} An array with the current permutation of the set
*/
this.current = function() {
var perm = [];
for (var i = 0; i < currentPermutationArray.length; i++) {
perm.push(set[currentPermutationArray[i]]);
}
return perm;
};
}