#ifndef __RNG_H__
#define __RNG_H__

#include <time.h>
#include <stdlib.h>
#include <vector>

#include "fraction.h"

// Technically, you should ONLY define one rng for the entire program
// IMPORTANT: pass all RNG objects as references
class RNG final {
private:
        const unsigned int init_seed;
        int curr_rand_num;
public:
        RNG(); // use time(0) as the seed
        RNG(const unsigned int seed); // use a seed

        int rand_num(); // returns a random number between 0 and RAND_MAX

        // IMPORTANT: all upper bounds are not included, all lower bounds are
        int rand_between(const int lower_bound, const int upper_bound);
        // returns a random number between 0 and upper_bound
        int rand_under(const int upper_bound);
        unsigned int get_init_seed() const;
        int get_curr_rand_num() const;

        bool trial(const fraction &psuccess);

        bool coin_flip();

        int exclude_middle(const int lower_bound, const int upper_bound,
                           const int excluded);

        template<class T> T rand_exclude(std::vector<T> &vec, T &target) {
                std::size_t idx = 0;

                for (; idx < vec.size(); ++idx)
                        if (vec[idx] == target)
                                break;

                return vec[exclude_middle(0, vec.size(), idx)];
        }

        template<class T> T get_rand_in_vector(std::vector<T> &vec) {
                if (!vec.size())
                        return T{};

                curr_rand_num = rand();

                return vec[curr_rand_num % vec.size()];
        }
};

#endif
