#ifndef VINI_HEADER
#       define  VINI_HEADER

#include <stdio.h>

#define MAXP 18
#define VBFSZ 3000
enum {VINI_NORM=0,VINI_MULTI=1,VINI_REQ=2, VINI_NOCLASS=4, VINI_VDOMAIN=8, VINI_CLASS=16, VINI_GLOBAL=32, VINI_FIELDS=64};
typedef struct INIVAL {int no_edit; int ref; char *val[MAXP]; int vali[MAXP]; struct INIVAL *next; } Inival;
typedef struct INITYPE {char *name; char *dflt; char *desc; int type;  int np; char isop[MAXP]; int ptype[MAXP]; char *pname[MAXP]; int ismulti;  } Initype;
typedef struct INITABLE {
	int id; 
	Inival **table; 
	int nref; 
	void *ref[100];
	char *ref_file[100];
	int ref_line[100];
	int todel; 
	int no_edit;
	struct INITABLE *classes; 
	struct INITABLE *next;
} Initable;
typedef struct INIHANDLE {int domain; int n; Inival *v; Initable *tbl; Initable *cls; } Inihandle;
typedef struct INIPARAM  {struct INIVAL *v; struct INITYPE *t; struct INIHANDLE *h; int x;} Iniparam;

#define vini_lock_all() vini_lock_all_x(__FILE__,__LINE__)
#define vini_lock() vini_lock_x(__FILE__,__LINE__)
#define vini_unlock() vini_unlock_real(__FILE__,__LINE__)
void vini_stats_show(FILE *f);
int vini_kmsg(int (*xkmsg)(const char *s,...));

void vini_unlock_real(char *file, int line);
int vini_get_stats_ref(void);
void vini_gethandle_stack_line(Inihandle *h, char *src, int line);
int vini_set_p(Inihandle *h, int x, char *param, char *val);
int vini_mutex_wait(char *file, int line);
int vini_set_mutex(int (*cb)(int vm, int isget, int seconds, char *file, int line), int m);
void vini_mutex_release(char *file, int line);
int vini_free_domain(Initable *tt);
int vini_free_table(Initable *t);
int vini_domain_delete(int domainid, char *domname);
Inival *vini_which(Inihandle *h, int x, Initype **tt);
int vini_class_delete(int domainid,int classid);
char *vini_get_name_domain(Inihandle *ini, char *name);
#define vini_get_name(x) vini_get_namex(x,__FILE__,__LINE__)
char *vini_get_namex(char *name, char *file, int line);
char *vini_get_vardesc(int x);
char *vini_get_varname(int x);
int vini_get_vartype(int x);
char *vini_get_pname(int x, int i);
int vini_isbool(int x,int i);
int vini_get_np(int x);
int vini_max(void);
int vini_type_global(int x);
int vini_type_domain(int x);
int vini_dom_clear(int domainid, int x);
char *vini_cur(Inihandle *h, int x);
void vini_mutex_state(char *s);
int vini_no_edit(int x);

void vini_free_idle(int nowait);
int vini_geti(Inihandle *h, int x);
char *vini_get_p_raw(Inival *v, int x, char *param);
int vini_showsetting_name(Inihandle *h, int (print)(void *, char *, ...), void *data, char *name);
int vini_showsetting(int (print)(void *, char *, ...), void *data, int i, Inival *r, char *info);
int vini_setting_string(Inihandle *h, char *setting, char *bf, int bfsz);
int vini_showconfig(FILE *f,Initable *b);
int vini_restore_domain(void);
int vini_save_domain(void);
int vini_newval(Inival **v);
int vini_clear_one(Initable *tble, int x);
int vini_dom_clear_with_value(int domainid, int x, char *field, char *val);
int vini_clear(int domainid,int classid, int x);
int vini_blank_domain(void);
int vini_blank_class(int domainid);
int vini_exit(void);
void vini_free_settings(void);
char *vini_cr_decode(char *s, char *tmp);
char *vini_get_decode(Inihandle *h, int x, char *tmp);
char *vini_setting_name(int i);
int vini_find_name(char *s);

void vini_lock_all_x(char *fname, int line);
void vini_unlock_all(void);
Initable *vini_dangle(Initable *t);
Initable *vini_dangle_classes(Initable *tlist);
Initable *vini_duplicate(Initable *t);
void vini_free_dangling(Initable *t, char *file, int line);
void vini_lock_x(char *fname, int line);

int vini_free_current(void);
char * vini_get_crash(int *line);

/*	vini_init() initialises the vini routines to use ini filename 'fname', and
 *	log error messages to 'xemsg'.
 *
 *	vini_init() returns TRUE if 'fname' exists, and FALSE otherwise.
 */
int vini_init(char *fname, int (*xemsg)(const char *s,...) );

int vini_add(int code, char *cmd, char *dflt, int type, char *desc);
int vini_reload(void);
void vini_load(void);
int vini_readone(Initype *t, Inival *v, char *cmd, char *eq, char *val);

void vini_gethandle_stack(Inihandle *h);
void vini_freehandle_stack(Inihandle *h, char *file, int line);

#define vini_gethandle(hhh) vini_gethandle_real(hhh,__FILE__,__LINE__)
void vini_gethandle_real(Inihandle **h,char *file,int line);
void vini_freehandle_real(Inihandle **h, char *file, int line);
#define vini_freehandle(a) vini_freehandle_real(a,__FILE__,__LINE__)
char *vini_get(Inihandle *h, int x);
int vini_global_istrue(int x);
int vini_domains_count(void);
Initable *vini_domains(void);
int vini_true(Inihandle *h, int x);
char *vini_get_p(Inihandle *h, int x, char *param);
int vini_geti_p(Inihandle *h, int x, char *param);
char *vini_cur_p(Inihandle *h, int x, char *param);
int vini_cur_p_true(Inihandle *h, int x, char *param);

int vini_curi_p(Inihandle *h, int x, char *param);
int vini_next(Inihandle *h, int x);
int vini_find(Inihandle *h, int x);
int vini_count(Inihandle *h, int x);

Iniparam *vini_find_ptr(Inihandle *h, int x, Iniparam **output);
Iniparam *vini_next_ptr(Iniparam *inip);
char *vini_cur_ptr(Iniparam *inip, char *param);
int vini_cur_ptr_true(Iniparam *inip, char *param);
int vini_set_encrypt(int gate, int mirror,char *(*xxx)(char *in, char *out) );

int vini_type_fields(int x);
int vini_type_multi(int x);
int vini_type_gmulti(int x);
int vini_token_quote(char *s, char *p[], int tmax);
int vini_set(int domainid,int classid, int mid,char *line);
int vini_global_set(char *line);
char *vini_file(void);
int vini_set_val(Initype *t, Inival *v, char *p[], int np);
int vini_free_val(Inival *v);

/*  Very useful for testing to see if all pointers are being "done" properly
void vini_handle_add_do(Inihandle **h, char*file, int line);
void vini_handle_remove_do(Inihandle **h, char*file, int line);
void vini_handle_imsg_remaining(void);
#define vini_handle_add(x) vini_handle_add_do(x , __FILE__, __LINE__);
#define vini_handle_remove(x) vini_handle_remove_do(x , __FILE__, __LINE__);
*/
#define vini_handle_add(x) ;
#define vini_handle_remove(x) ;

/*---------------------------------------------------------*/

int vini_free_inival(Inival **table);
int vini_save_domain(void);
int vini_restore_class(void);
int vini_save_class(void);
int vini_restore_domain(void);
int vini_add_domain(Initable *t);
Initable *vini_new_domain(void);
int vini_copy_table(Initable *a, Initable *b);
/*---------------------------------------------------------*/
#define vini_free_ref(t,pn,x) vini_free_ref_real(t,pn,x,__FILE__,__LINE__)
#define vini_get_ref(t,n,x) vini_get_ref_real(t,n,x,__FILE__,__LINE__)
Initable *vini_get_ref_real(Initable *t, int *pn, void *x, char *file, int line);
void vini_free_ref_real(Initable *t, int n, void *x, char *file, int line);
void vini_switch_table(Inihandle *ini, Initable *t);
int vini_switch_table_n(Inihandle *ini, int domainid);
int vini_write_log(char *src, int line);
int vini_write_real(char *src, int line, char *altfile);
#define vini_write() vini_write_log(__FILE__,__LINE__)

//Initable *vini_get_ref_real(Initable *t, char *file, int line);
//void vini_free_ref_real(Initable *t, char *file, int line);

void vini_abort(char *reason);
#endif
