// Reimplementation of https://source.dot.net/#System.Private.CoreLib/Random.cs,bb77e610694e64ca
const MamiRNG = function(seed) {
    const MBIG = 0x7FFFFFFF;
    const MSEED = 161803398;

    if((typeof seed).toLowerCase() !== 'number')
        seed = Math.round(Date.now() / 1000);

    const seedArray = new Int32Array(56);

    const vars = new Int32Array(2);
    const mjVal = 0, mkVal = 1;
    let ii = 0;

    vars[mjVal] = seed;
    vars[mjVal] = (vars[mjVal] === -0x80000000) ? 0x7FFFFFFF : Math.abs(vars[mjVal]);
    vars[mjVal] = MSEED - vars[mjVal];
    seedArray[55] = vars[mjVal];
    vars[mkVal] = 1;

    for(let i = 1; i < 55; i++) {
        if((ii += 21) >= 55)
            ii -= 55;

        seedArray[ii] = vars[mkVal];
        vars[mkVal] = vars[mjVal] - vars[mkVal];

        if(vars[mkVal] < 0)
            vars[mkVal] += MBIG;

        vars[mjVal] = seedArray[ii];
    }

    for(let k = 1; k < 5; k++) {
        for(let i = 0; i < 56; i++) {
            let n = i + 30;

            if(n >= 55)
                n -= 55;

            seedArray[i] -= seedArray[1 + n];

            if(seedArray[i] < 0)
                seedArray[i] += MBIG;
        }
    }

    let inext = 0,
        inextp = 21;

    const internalSample = function() {
        const retVal = new Int32Array(1);
        let locINext = inext,
            locINextp = inextp;

        if(++locINext >= 56)
            locINext = 1;
        if(++locINextp >= 56)
            locINextp = 1;

        retVal[0] = seedArray[locINext];
        retVal[0] -= seedArray[locINextp];

        if(retVal[0] == MBIG)
            retVal[0]--;
        if(retVal[0] < 0)
            retVal[0] += MBIG;

        seedArray[locINext] = retVal[0];
        inext = locINext;
        inextp = locINextp;

        return retVal[0];
    };

    const sample = function() {
        return internalSample() * (1.0 / MBIG);
    };

    return {
        sample: sample,
        next: function(minValue, maxValue) {
            let hasMinVal = (typeof minValue).toLowerCase() === 'number',
                hasMaxVal = (typeof maxValue).toLowerCase() === 'number';
            const vars = new Int32Array(3),
                minVal = 0, maxVal = 1, retVal = 2;

            if(hasMinVal) {
                if(!hasMaxVal) {
                    hasMinVal = false;
                    hasMaxVal = true;
                    vars[maxVal] = minValue;
                } else {
                    vars[minVal] = minValue;
                    vars[maxVal] = maxValue;
                }
            }

            if(hasMaxVal) {
                if(hasMinVal) {
                    if(vars[minVal] > vars[maxVal])
                        throw 'Argument out of range.';

                    const range = vars[maxVal] - vars[minVal];

                    vars[retVal] = sample() * range;
                    vars[retVal] += vars[minVal];

                    return vars[retVal];
                }

                vars[retVal] = sample() * vars[maxVal];
                return vars[retVal];
            }

            return internalSample();
        },
    };
};
