#ifndef	UTIL_H
#define	UTIL_H

#include <v_lib.h>

#define	PTR2FUNC(func,ptr)	*((void_p*)(&(func))) = (ptr)
#define	FUNC2PTR(ptr,func)	(ptr) = *((void_p*)&(func))

extern	vhandle_t rhandle;

extern int seed;

int		util_init(void);
void	util_shutdown(void);

#ifdef	__cplusplus
extern "C" {
#endif	/* __cplusplus */
	/* Writes "val" to "idx" position of *srcdst, reallocates *srcdst if necessary */
	vboolean	V_GLOBAL	vecStoreVec(vector_p *srcdst,vec_t val,u32_t idx);
	/* Copies elements from src to row "row" of dst. dst->cols must be equal to src->size. */
	void		V_GLOBAL	matCopyToRow(matrix_t *dst, vector_t *src,u32_t row);
	/* Copies elements from src to col "col" of dst. dst->rows must be equal to src->size. */
	void		V_GLOBAL	matCopyToCol(matrix_t *dst,vector_t *src,u32_t col);
	/* Allocates "row" X "col" matrix and fills it with values from "src" row by row. */
	matrix_p	V_GLOBAL	matRowMatrixFromVecs(u32_t rows,u32_t cols,vec_p src);
	/*
	 * Parses vector with MATLAB syntax (e.g. [1.2 2.3 3.4] or [1.2,2.3,3.4]).
	 * Chars '[', ']' and ',' and ';' must be in delimiter string of "lex".
	 */
	vector_p	V_GLOBAL	vecParse(vhandle_t lex);
	/*
	 * Parses matrix with MATLAB syntax (e.g. [1.2 2.3 3.4; 4 5 6] or [1.2,2.3,3.4;4,5,6]).
	 * Chars '[', ']', ',' and ';' must be in delimiter string of "lex".
	 */
	matrix_p	V_GLOBAL	matParse(vhandle_t lex);
	/* Outputs matrix to "out" in MATLAB syntax */
	/* Writes FP number "val" to "out" using "dotchar" as decimal separator */
	void		V_GLOBAL	writeVec(vhandle_t out,vec_t val,char dotchar);
	/* Outputs matrix to "out" in MATLAB syntax */
	void		V_GLOBAL	matWrite(vhandle_t out, matrix_p m);
	/* Outputs vector to "out" in MATLAB syntax */
	void		V_GLOBAL	vecWrite(vhandle_t out, vector_p m);
	/* Prints X[i] and Y[i] in two tab-separated columns */
	void		V_GLOBAL	vecsWriteXY(char *outname,vec_p X,vec_p Y,u32_t num_elems);
	/*
	 * Stores X[i] and Y[i] in SVG graphics.
	 * View is A4 (210 by 297 mm), units are millimeters.
	 * Origin is top-left, thus "y_scale" should be negative and
	 * (for the 1st quadrant) y_ofs should be positive.
	 */
	void	V_GLOBAL		vecsWriteXYsvgEx(char *outname,vec_p X,vec_p Y,u32_t num_elems,
		vec_t x_ofs,vec_t x_scale,vec_t y_ofs,vec_t y_scale,
		char *stroke_color, char *stroke_width,vboolean draw_box,vboolean draw_axes);
	/*
	 * Same as above, "stroke_color" == "000000", "stroke_width" == "0.1pt", draw_box == draw_axes == true.
	 */
	void	V_GLOBAL	vecsWriteXYsvg(char *outname,vec_p X,vec_p Y,u32_t num_elems);
	/* Stepwise interpolation */
	vec_t	V_GLOBAL	vecsStepwise(vec_p X,vec_p Y,u32_t num_points,vec_t x);
	/* Piecewise linear interpolation */
	vec_t	V_GLOBAL	vecsLerp(vec_p X,vec_p Y,u32_t num_points,vec_t x);
	/*
	 * Returns 2 x (n+1) matrix of values that can be used for estimation of stepwise inverse
	 * cumilative probability distribution function in case of target probability density function is
	 * f(x) = \sum\limits_{i=1}^{n} \alpha_i \delta(x-x_i),
	 * where \delta is Dirac delta, \sum\limits_{i=1}^{n} \alpha_i = 1.
	 * Both x_i and \alpha_i are get from "PDF" 2 x n matix, \alpha's can be non-normalized,
	 * but should be positive.
	 * All x_i must be specified in ascending order.
	 * The result if suitable for later vecsStepwise(m->cell[0], m->cell[1], m->cols, prob).
	 */
	matrix_p	V_GLOBAL	stepwiseICP(matrix_p PDF);
	/*
	 * Reads x_i and \alpha_i from lexer "lex" as 2 x n matix and returns
	 * stepwiseICP() of the result.
	 */
	matrix_p	V_GLOBAL	parseStepwiseICP(vhandle_t lex);
	/*
	 * Calls parseStepwiseICP() and than generates "numvals" random numbers.
	 * Uses global "rhandle".
	 */
	vboolean	V_GLOBAL	vecsDirac(vhandle_t lex,vec_p dst,u32_t numvals);
	/*
	 * Returns 2 x n matrix of values that can be used for estimation of piecewise linear
	 * inverse cumilative probability distribution function in case of target probability
	 * density function is
	 * f(x) = 
	\begin{cases}
		0, x < x_1 \\
		p_i, x_i \leq x < x_{i+1}, i = \overline{1,n - 1} \\
		0, p_n \leq x
	\end{cases}
	 * Last probability value p_n is ignored (assumed to be zero).
	 * Both x_i and p_i are get from "PDF" 2 x n matix, p_n's can be non-normalized,
	 * p_1 must be positive and adjacent p_i must be different (thus, p_{n-1} must be
	 * positive).
	 * The result if suitable for later vecsLerp(m->cell[0], m->cell[1], m->cols, prob).
	 */
	matrix_p	V_GLOBAL	linearICP(matrix_p PDF);
	/*
	 * Reads x_i and p_i from lexer "lex" as 2 x n matix and returns
	 * linearICP() of the result.
	 */
	matrix_p	V_GLOBAL	parseLinearICP(vhandle_t lex);
	/*
	 * Calls parseLinearICP() and than generates "numvals" random numbers.
	 * Uses global "rhandle".
	 */
	vboolean	V_GLOBAL	vecsHeaviside(vhandle_t lex,vec_p dst,u32_t numvals);
	/*
	 * Generates samples that are uniformly distributed in (min;max).
	 * Fast version of vecsHeaviside() for [min,max;1,0].
	 * Uses global "rhandle".
	 */
	void		V_GLOBAL	vecsUniform(vec_p dst,u32_t numvals,vec_t min,vec_t max);
#ifdef	__cplusplus
}
#endif	/* __cplusplus */

#endif	/* !UTIL_H */
