/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef STDLIB_RANDOM_BASE_H
#define STDLIB_RANDOM_BASE_H

#include <stdlib.h>
#include <stdint.h>

/*
* If C++, prevent name mangling so that the compiler emits a binary file having undecorated names, thus mirroring the behavior of a C compiler.
*/
#ifdef __cplusplus
extern "C" {
#endif

// Forward declaration.
struct BasePRNGObject;

/**
* Base PRNG structure.
*/
struct BasePRNG {
	// Define the generator name:
	const char *name;

	// Define the minimum possible generated integer value:
	const uint64_t min;

	// Define the maximum possible generated integer value:
	const uint64_t max;

	// Define the minimum possible generated double-precision floating-point number:
	const double normalized_min;

	// Define the maximum possible generated double-precision floating-point number:
	const double normalized_max;

	// Define the size of the PRNG state:
	const size_t state_size;

	// Define a pointer to a function for returning the next generated value:
	int8_t (* const next)( struct BasePRNGObject *obj, uint64_t *out );

	// Define a pointer to a function for returning the next generated value on the interval `[0,1)`:
	int8_t (* const normalized)( struct BasePRNGObject *obj, double *out );

	// Define a pointer to a function for freeing a PRNG's allocated memory:
	void (* const free)( struct BasePRNGObject *obj );
};

/**
* Base PRNG wrapper.
*/
struct BasePRNGObject {
	// Define a pointer to the underlying pseudorandom number generator:
	const struct BasePRNG *prng;

	// Define a pointer to the generator state:
	void *state;
};

/**
* Frees a PRNG's allocated memory.
*/
void stdlib_base_prng_free( struct BasePRNGObject *obj );

/**
* Returns a pseudorandom integer.
*/
uint64_t stdlib_base_prng_next( struct BasePRNGObject *obj );

/**
* Returns a pseudorandom double-precision floating-point number on the interval `[0,1)`.
*/
double stdlib_base_prng_normalized( struct BasePRNGObject *obj );

/**
* Returns a PRNG name.
*/
const char * stdlib_base_prng_name( const struct BasePRNGObject *obj );

/**
* Returns the minimum possible integer value generated by a provided PRNG.
*/
uint64_t stdlib_base_prng_min( const struct BasePRNGObject *obj );

/**
* Returns the maximum possible integer value generated by a provided PRNG.
*/
uint64_t stdlib_base_prng_max( const struct BasePRNGObject *obj );

/**
* Returns the minimum possible double-precision floating-point number generated by a provided PRNG.
*/
double stdlib_base_prng_normalized_min( const struct BasePRNGObject *obj );

/**
* Returns the maximum possible double-precision floating-point number generated by a provided PRNG.
*/
double stdlib_base_prng_normalized_max( const struct BasePRNGObject *obj );

/**
* Returns the size of a provided PRNG's internal state.
*/
size_t stdlib_base_prng_state_size( const struct BasePRNGObject *obj );

/**
* Returns a copy of a PRNG's internal state.
*/
void * stdlib_base_prng_state( const struct BasePRNGObject *obj );

/**
* Sets a PRNG's state.
*/
int8_t stdlib_base_prng_set( struct BasePRNGObject *obj, const void *vstate );

/**
* Copies a PRNG.
*/
struct BasePRNGObject * stdlib_base_prng_copy( const struct BasePRNGObject *src );

/**
* Copies a PRNG state from a source PRNG to a destination PRNG of the same kind.
*/
int8_t stdlib_base_prng_copy_state( struct BasePRNGObject *dest, const struct BasePRNGObject *src );

#ifdef __cplusplus
}
#endif

#endif // !STDLIB_RANDOM_BASE_H
