#include "Random.h"
#include "Zeit.h"
#include <iostream>

using namespace Framework;

RandomGenerator::RandomGenerator()
{
    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 );
    ref = 1;
    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-- )
        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;
}

// Erh�ht den Reference Counting Z�hler.
//  return: this.
RandomGenerator *RandomGenerator::getThis()
{
    ref++;
    return this;
}

// Verringert den Reference Counting Z�hler. Wenn der Z�hler 0 erreicht, wird das Objekt automatisch gel�scht.
//  return: 0.
RandomGenerator *RandomGenerator::release()
{
    if( !--ref )
        delete this;
    return 0;
}