#include "Random.h"

#include <iostream>

#include "Zeit.h"

using namespace Framework;

RandomGenerator::RandomGenerator()
    : ReferenceCounter()
{
    int tmp[] = {
        3,
        -1726662223,
        379960547,
        1735697613,
        1040273694,
        1313901226,
        1627687941,
        -179304937,
        -2073333483,
        1780058412,
        -1989503057,
        -615974602,
        344556628,
        939512070,
        -1249116260,
        1507946756,
        -812545463,
        154635395,
        1388815473,
        -1926676823,
        525320961,
        -1009028674,
        968117788,
        -123449607,
        1284210865,
        435012392,
        -2017506339,
        -911064859,
        -370259173,
        1132637927,
        1398500161,
        -205601318,
    };
    memcpy(randtbl, tmp, 32 * 4);
    unsafe_state
        = {&randtbl[4], &randtbl[1], &randtbl[1], 3, 31, 3, &randtbl[32]};
    offset = 0;
    srand((int)time(0));
}

// Destruktor
RandomGenerator::~RandomGenerator() {}

void RandomGenerator::srand(int seed)
{
    this->seed = seed;
    int type;
    int* state;
    long int i;
    int word;
    int* dst;
    int kc;

    type = unsafe_state.rand_type;
    if ((unsigned int)type >= 5) return;

    state = unsafe_state.state;
    if (seed == 0) seed = 1;
    state[0] = seed;
    if (type == 0) return;

    dst = state;
    word = seed;
    kc = unsafe_state.rand_deg;
    for (i = 1; i < kc; ++i)
    {
        long int hi = word / 127773;
        long int lo = word % 127773;
        word = (int)(16807 * lo - 2836 * hi);
        if (word < 0) word += 2147483647;
        *++dst = word;
    }

    unsafe_state.fptr = &state[unsafe_state.rand_sep];
    unsafe_state.rptr = &state[0];
    kc *= 10;
    while (--kc >= 0)
        rand();
}

void RandomGenerator::setSeed(__int64 seed)
{
    this->offset = 0;
    int offset = (int)(seed >> 32);
    srand((int)seed);
    offset -= this->offset;
    while (offset-- > 0)
        rand();
}

double RandomGenerator::rand()
{
    offset++;
    int* state;

    state = unsafe_state.state;

    if (unsafe_state.rand_type == 0)
    {
        int val = state[0];
        val = ((state[0] * 1103515245) + 12345) & 0x7fffffff;
        state[0] = val;
        return val / 2147483647.0;
    }
    else
    {
        int* fptr = unsafe_state.fptr;
        int* rptr = unsafe_state.rptr;
        int* end_ptr = unsafe_state.end_ptr;
        int val;

        val = *fptr += *rptr;
        int result = (val >> 1) & 0x7fffffff;
        ++fptr;
        if (fptr >= end_ptr)
        {
            fptr = state;
            ++rptr;
        }
        else
        {
            ++rptr;
            if (rptr >= end_ptr) rptr = state;
        }
        unsafe_state.fptr = fptr;
        unsafe_state.rptr = rptr;
        double res = result / 2147483647.0;
        return res;
    }
    return 0;
}

__int64 RandomGenerator::getSeed() const
{
    __int64 ret = ((__int64)offset << 32) | seed;
    return ret;
}