#ifndef RETRO_CRANDOM16_HPP
#define RETRO_CRANDOM16_HPP

#include "GCNTypes.hpp"

namespace urde
{


class CRandom16
{
    u32 m_seed;
    static CRandom16* g_randomNumber;
public:
    CRandom16() = default;
    CRandom16(u32 p) : m_seed(p) {}

    inline u32 Next()
    {
        m_seed = (m_seed * 0x41c64e6d) + 0x00003039;
        return m_seed >> 16;
    }

    inline u32 GetSeed() const
    {
        return m_seed;
    }

    inline void SetSeed(u32 p)
    {
        m_seed = p;
    }

    inline float Float()
    {
        return Next() * 0.000015259022;
    }

    inline float Range(float min, float max)
    {
        return min + Float() * (max - min);
    }

    inline s32 Range(s32 min, s32 max)
    {
        s32 diff = max - min;
        s32 rand = -1;
        while (rand < 0)
            rand = s32((Next() << 16) | Next());
        return rand % diff + min;
    }

    static CRandom16* GetRandomNumber() {return g_randomNumber;}
    static void SetRandomNumber(CRandom16* rnd) {g_randomNumber = rnd;}
};

class CGlobalRandom
{
    CRandom16& m_random;
    CGlobalRandom* m_prev;
    static CGlobalRandom* g_currentGlobalRandom;
public:
    CGlobalRandom(CRandom16& rand)
        : m_random(rand), m_prev(g_currentGlobalRandom)
    {
        g_currentGlobalRandom = this;
        CRandom16::SetRandomNumber(&m_random);
    }
    ~CGlobalRandom()
    {
        g_currentGlobalRandom = m_prev;
        if (m_prev)
            CRandom16::SetRandomNumber(&m_prev->m_random);
        else
            CRandom16::SetRandomNumber(nullptr);
    }
};

}

#endif // RETRO_CRANDOM16_HPP