#include "rgcache.h"

rgcache_p	V_GLOBAL
rgcReset(rgcache_p rgc,
	vec_t min, vec_t max, /* for uniforms */
	vec_t mean, vec_t stdev /* for gaussians */)
{
	if(!rgc)
		return rgcCreate(0,NULL,min,max,mean,stdev);
	rgc->min = min;
	rgc->max = max;
	rgc->mean = mean;
	rgc->stdev = stdev;
	rgc->g_idx = rgc->u_idx = 0;
	ranNextGaussianVector(rgc->rg,rgc->g_cache,rgc->mean,rgc->stdev);
	ranNextVectorRange(rgc->rg,rgc->u_cache,rgc->min,rgc->max);
	return rgc;
}

s32_t global_rgc_seed = 0;

rgcache_p V_GLOBAL
rgcCreate(u32_t cache_size, /* can be 0 */
	vhandle_t rg, /* can be NULL */
	vec_t min, vec_t max, /* for uniforms */
	vec_t mean, vec_t stdev /* for gaussians */)
{
	rgcache_p rgc = (rgcache_p)memAlloc(sizeof(rgcache_t));
	if(!cache_size)
		cache_size = RGCACHE_SIZE;
	rgc->u_cache = vecAlloc(cache_size);
	rgc->g_cache = vecAlloc(cache_size);
	if(rg == LIBV_INVALID_HANDLE)
	{
		rgc->own_rg = true;
		rgc->rg = ranCreateGenerator(++global_rgc_seed);
	}
	else
	{
		rgc->own_rg = false;
		rgc->rg = rg;
	}
	return rgcReset(rgc, min, max, mean, stdev);
}

void	V_GLOBAL
rgcDestroy(rgcache_p rgc)
{
	if(!rgc)
		return;
	memFree(rgc->u_cache);
	memFree(rgc->g_cache);
	if(rgc->own_rg)
		ranDestroyGenerator(rgc->rg);
	memFree(rgc);
}

vec_t	V_GLOBAL
rgcNext(rgcache_p rgc)
{
	if(rgc->u_idx == rgc->u_cache->size)
	{
		rgc->u_idx = 0;
		ranNextVectorRange(rgc->rg,rgc->u_cache,rgc->min,rgc->max);
	}
	return rgc->u_cache->elements[rgc->u_idx++];
}

vec_t	V_GLOBAL
rgcNextGaussian(rgcache_p rgc)
{
	if(rgc->g_idx == rgc->g_cache->size)
	{
		rgc->g_idx = 0;
		ranNextGaussianVector(rgc->rg,rgc->g_cache,rgc->mean,rgc->stdev);
	}
	return rgc->g_cache->elements[rgc->g_idx++];
}
