/*
 *  Copyright 1994-2022 Olivier Girondel
 *
 *  This file is part of lebiniou.
 *
 *  lebiniou is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  lebiniou is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with lebiniou. If not, see <http://www.gnu.org/licenses/>.
 */

#include <inttypes.h>

#include "brandom.h"


// #define DEBUG_RANDOM

static GRand *brand = NULL;
#ifdef DEBUG_RANDOM
static FILE *debug_random_fd = NULL;
#endif


void
b_rand_init(void)
{
  uint32_t seed;
  char *seedstr;

  if (NULL != (seedstr = getenv("LEBINIOU_SEED"))) {
    seed = xstrtol(seedstr);
    VERBOSE(printf("[i] Random seed set to %"PRIu32"\n", seed));
  } else {
    struct timeval t;

    gettimeofday(&t, NULL);
    seed = t.tv_sec;
    VERBOSE(printf("[i] No random seed, using %"PRIu32"\n", seed));
  }
  brand = g_rand_new_with_seed(seed);
#ifdef DEBUG_RANDOM
  gchar *filename = g_strdup_printf("%s-prng.log", getenv("LEBINIOU_MP4_FILENAME"));
  debug_random_fd = fopen(filename, "w");
  g_free(filename);
  fprintf(debug_random_fd, "Using seed: %"PRIu32"\n", seed);
#endif
}


void
b_rand_free(void)
{
  if (NULL != brand) {
    g_rand_free(brand);
  }
#ifdef DEBUG_RANDOM
  fclose(debug_random_fd);
#endif
}


uint32_t
b_rand_int(void)
{
#ifdef DEBUG_RANDOM
  uint32_t rnd = g_rand_int(brand);
  fprintf(debug_random_fd, "%s: %"PRIu32"\n", __func__, rnd);

  return rnd;
#else
  return g_rand_int(brand);
#endif
}


int32_t
b_rand_int32_range(const int32_t begin, const int32_t end)
{
#ifdef DEBUG_RANDOM
  int32_t rnd = (begin == end) ? end : g_rand_int_range(brand, begin, end);
  fprintf(debug_random_fd, "%s: %"PRId32"\n", __func__, rnd);

  return rnd;
#else
  return (begin == end) ? end : g_rand_int_range(brand, begin, end);
#endif
}


uint32_t
b_rand_uint32_range(const uint32_t begin, const uint32_t end)
{
#ifdef DEBUG_RANDOM
  uint32_t rnd = (begin == end) ? end : (uint32_t)g_rand_int_range(brand, begin, end);
  fprintf(debug_random_fd, "%s: %"PRIu32"\n", __func__, rnd);

  return rnd;
#else
  return (begin == end) ? end : (uint32_t)g_rand_int_range(brand, begin, end);
#endif
}


double
b_rand_double_range(const double begin, const double end)
{
#ifdef DEBUG_RANDOM
  double rnd = g_rand_double_range(brand, begin, end);
  fprintf(debug_random_fd, "%s: %lf\n", __func__, rnd);

  return rnd;
#else
  return g_rand_double_range(brand, begin, end);
#endif
}


uint8_t
b_rand_boolean(void)
{
#ifdef DEBUG_RANDOM
  int rnd = g_rand_boolean(brand);
  fprintf(debug_random_fd, "%s: %d\n", __func__, rnd);

  return rnd;
#else
  return g_rand_boolean(brand);
#endif
}


void
b_rand_set_seed(const uint32_t seed)
{
  g_rand_set_seed(brand, seed);
}
