/**
 *
 *  RandomIterator.js
 *
 *  copyright 2013, Kevin Lindsey
 *
 */

var defineSubclass = require('kld-class-utils').defineSubclass,
    Iterator = require('./Iterator');

defineSubclass(Iterator, RandomIterator, { shuffle: shuffle });

/**
 *  RandomIterator
 *
 *  @param {Object} items...
 *  @returns {RandomIterator}
 */
function RandomIterator() {
    Iterator.apply(this, arguments);
    this.shuffle();
}

/**
 *  shuffle
 */
function shuffle() {
    var length = this.items.length;

    // shuffle
/**
 *
 *  PermutationIterator.js
 *
 *  copyright 2013, Kevin Lindsey
 *
 *  based on an algorithm described by Joren on Stackoveflow
 *  http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
 *
 */

var defineSubclass = require('kld-class-utils').defineSubclass,
    Iterator = require('./Iterator'),
    CrossProductIterator = require('./CrossProductIterator');

defineSubclass(Iterator, PermutationIterator);

/**
 *  PermutationIterator
 *
 *  @param {Object} items...
 *  @returns {PermutationIterator}
 */
function PermutationIterator() {
    function fact(n) {
        var result = 1;

        for (var i = 2; i <= n; i++) {
            result *= i;
        }
/**
 *
 *  SubsetIterator.js
 *
 *  copyright 2013, Kevin Lindsey
 *
 */

var defineSubclass = require('kld-class-utils').defineSubclass,
    Iterator = require('./Iterator'),
    CrossProductIterator = require('./CrossProductIterator');

defineSubclass(Iterator, SubsetIterator);

/**
 *  SubsetIterator
 *
 *  @param {Object} items...
 *  @returns {CombinatationIterator}
 */
function SubsetIterator() {
    var items = Array.prototype.slice.call(arguments, 0);

    this.items = (items.length == 1 && Array.isArray(items[0])) ? items[0] : items;

    // since we're using a bit mask, we can't have more than 32 elements. That's 2^32-1
    // subsets so that should be reasonable

    if (this.items.length > 32) {
        throw new Error("SubsetIterators cannot work with more than 32 elements");
    }
/**
 *
 *  RepeatIterator.js
 *
 *  copyright 2013, Kevin Lindsey
 *
 */

var defineSubclass = require('kld-class-utils').defineSubclass,
    Iterator = require('./Iterator'),
    CrossProductIterator = require('./CrossProductIterator');

defineSubclass(Iterator, RepeatIterator);

/**
 *  RepeatIterator
 *
 *  @param {Iterator} iterator
 *  @param {Number} minimum
 *  @param {Number} maximum
 *  @returns {RepeatIterator}
 */
function RepeatIterator(iterator, minimum, maximum) {
    if (minimum > maximum) throw new Error("minimum must be <= maximum");

    this.iterator = iterator;
    this.minimum = minimum;
    this.maximum = (maximum !== undefined) ? maximum : Math.pow(2,32);

    this.reset();
}
/**
 *
 *  Range.js
 *
 *  copyright 2013, Kevin Lindsey
 *
 */

var defineSubclass = require('kld-class-utils').defineSubclass,
    Iterator = require('./Iterator');

defineSubclass(Iterator, RangeIterator);

/**
 *  RangeIterator
 *
 *  @param {Number} start
 *  @param {Number} end?
 *  @param {Number} step?
 *  @returns {Range}
 */
function RangeIterator(start, end, step) {
    this.start = start;
    this.end = (end !== undefined) ? end : Math.pow(2,32);    // or should this be Number.MAX_VALUE
    this.step = (step !== undefined)
        ? step
        : (this.end >= this.start)
            ? 1
            : -1;
    this.reset();
}