/**
 * Warning: Shufflers will alter the given array
 */
class Shuffler<T> {
    private array : Array<T>;
    private position = 0;

    /**
     * Maybe use seeded random some day
     */
    private rng : () => number;

    public constructor (array : Array<T>, rng? : () => number) {
        this.rng = rng == undefined ? Math.random : rng;
        this.array = array;
    }

    public restart () {
        this.position = 0;
    }

    /**
     * Gets a random element from the Shuffler Array
     * Can be called repeatedly
     * When there are no more elements left, returns undefined
     * @returns {T}
     */
    public getOne () : T {
        // get a random element from this.position to (array.length - 1)
        // store it locally
        // switch it with array[this.position]
        // return it
        if (this.position >= this.array.length) {
            return undefined;
        }
        let randomIndex = Math.floor(this.rng() * (this.array.length - this.position)) + this.position;
        let localCopy = this.array[this.position];
        this.array[this.position] = this.array[randomIndex];
        this.array[randomIndex] = localCopy;
        return this.array[this.position++];
    }

    /**
     * There should be no reason to use this with the "getOne" code above.
     * @returns {T[]}
     */
    public getShuffled () : Array<T> {
        let array = this.array.slice(0);
        var m = array.length, t, i;
        while (m) {
            i = Math.floor(this.rng() * m--);
            t = array[m];
            array[m] = array[i];
            array[i] = t;
        }

        return array;
    }
}