/*
 * Copyright (c) 2020, Andreas Kling <andreas@ladybird.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/Platform.h>
#include <AK/Span.h>
#include <AK/StdLibExtras.h>
#include <AK/Types.h>
#include <stdlib.h>

#if defined(__unix__)
#    include <unistd.h>
#endif

namespace AK {

void fill_with_random([[maybe_unused]] Bytes bytes);

template<typename T>
inline T get_random()
{
    T t;
    fill_with_random({ &t, sizeof(T) });
    return t;
}

u32 get_random_uniform(u32 max_bounds);
u64 get_random_uniform_64(u64 max_bounds);

String generate_random_uuid();

// http://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf
class XorShift128PlusRNG {
public:
    XorShift128PlusRNG();
    double get();

private:
    u64 splitmix64(u64& state);
    u64 advance();
    u64 m_low { 0 };
    u64 m_high { 0 };
};

template<typename Collection>
inline void shuffle(Collection& collection)
{
    // Fisher-Yates shuffle
    for (size_t i = collection.size() - 1; i >= 1; --i) {
        size_t j = get_random_uniform(i + 1);
        AK::swap(collection[i], collection[j]);
    }
}

}

#if USING_AK_GLOBALLY
using AK::fill_with_random;
using AK::generate_random_uuid;
using AK::get_random;
using AK::get_random_uniform;
using AK::shuffle;
using AK::XorShift128PlusRNG;
#endif
