/***************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A.  All Rights Reserved.                         *
*                                                                          *
***************************************************************************/

#pragma once

#include "glmSingleton.h"
#include "glmSmartPointer.h"
#include "glmRTTI.h"

namespace glm
{
// implementation of RandomNumberGenerator using the public domain Mersenne Twister by Michael Brundage
// original code from Sean's Tool Box -- public domain -- http://nothings.org/stb.h
class GLM_CORE_API RandomNumberGenerator : public ReferenceCounter
{
    friend class glm::Singleton<glm::RandomNumberGenerator>;

  public:
    GLM_CLASS_STAT_ID( glm::MemoryStatIds::GolaemShared);

	typedef SmartPointer<RandomNumberGenerator> SP;

    RandomNumberGenerator(uint32_t seed = 0);

    uint32_t rand();
    uint32_t rand(uint32_t lowerBound, uint32_t upperBound);
    float frand();
    float frand(float lowerBound, float upperBound);

    uint32_t getSeed() const;
    void setSeed(uint32_t seed);

  private:
    uint32_t _seed;
    static const uint16_t _mtLength = 624;
    int32_t _mtIndex;
    uint32_t _mtBuffer[_mtLength];
};

//-------------------------------------------------------------------------
inline uint32_t RandomNumberGenerator::rand(uint32_t lowerBound, uint32_t upperBound)
{
    return rand() % (upperBound - lowerBound + 1) + lowerBound;
}

//-------------------------------------------------------------------------
inline float RandomNumberGenerator::frand()
{
    return rand() / (static_cast<float>(1 << 16) * (1 << 16));
}

//-------------------------------------------------------------------------
inline float RandomNumberGenerator::frand(float lowerBound, float upperBound)
{
    GLM_DEBUG_ASSERT(lowerBound <= upperBound);
    return frand() * (upperBound - lowerBound) + lowerBound;
}

//-------------------------------------------------------------------------
inline uint32_t RandomNumberGenerator::getSeed() const
{
    return _seed;
}

//-------------------------------------------------------------------------
extern GLM_CORE_API RandomNumberGenerator& getRNGSingleton();

//-----------------------------------------------------------------------------
/// Cross-platform deterministic shuffle using Fisher-Yates algorithm
template <typename Iterator>
void deterministicShuffle(Iterator first, Iterator last, RandomNumberGenerator& rng)
{
    typedef typename std::iterator_traits<Iterator>::difference_type diff_t;
    diff_t n = last - first;
    for (diff_t i = n - 1; i > 0; --i)
    {
        diff_t j = rng.rand() % (i + 1); // Get random index from 0 to i
        std::swap(first[i], first[j]);
    }
}
}
