/* Admin Interface Internal Data Structures */

#define _ARISA_ADMIN_INTERFACE_H

enum menu_type_t {
	ADMIN_MENU,
	ADMIN_COMMAND
};

/*** Structures ***/

typedef struct cmd_t		cmd_t;
typedef struct instance_t	instance_t;
typedef struct menu_t		menu_t;

/** cmd_t 
 *	Legacy, used only for loading builtin commands.
 * 	Structure describing a command in the menu system.
 *	Menus consist of NULL terminated arrays of cmd_t pointers.
 */
struct cmd_t {
	// name of the command
	char		*name;
	// function which actually executes the command.
	int		(*func)(instance_t *,acontext_t *,menu_t*,char **,int);
	// minimum number of arguments to accept before executing the command.
	int		min_args;
	// maximum number of arguments to accept, -1 for unlimited
	// -2 to have arguments after min_args maintained as is in the last arg
	int		max_args;
	// if !0 executions of this command are logged
	int		log;
	// if !0 this command is not shown on '?' queries
	int		hide;
	// privilege mask, user must possess ALL of the privileges set 
	uint32_t	privs;
	// helper function is called when a '?' is found in the parameters
	void 		(*helper)(instance_t *,acontext_t *,char **,int);
};

/** menu_t
 *	Struct describing an entry in a menu struct, might be another menu or
 *	a command.
 */
struct menu_t {
	lock_t		lock;
	int		ref_count;

	// Type of menu entry, MENU or COMMAND
	enum menu_type_t	type;
	// name, which appears in listings
	char			*name;

	// func, used to execute the a menu command, or used to verify entry
	int 		(*func)(instance_t *,acontext_t *,menu_t*,char **,int);
	// minimum number of arguments to accept before executing the command.
	int		min_args;
	// maximum number of arguments to accept, -1 for unlimited
	// -2 to have arguments after min_args maintained as is in the last arg
	int		max_args;
	// if !0 executions of this command are logged
	int		log;
	// if !0 this command is not shown on '?' queries
	int		hide;
	// privilege mask, user must possess ALL of the privileges set 
	uint32_t	privs;

	// helper function is called when a '?' is found in the parameters
	void 		(*helper)(instance_t *,acontext_t *,char **,int);

	// help associated with this command, *must* take lock to access these
	char		**help;
	int		no_help;
	
	// menu specific data, *must* take lock to access these
	menu_t		**ents;
	int		no_ents;
};

/** instance_t
 *	Structure describing an instance of a level of the menu system.
 *	These are dynamically created and freed as the admin moves menus.
 */
struct instance_t {
	// text to appear in the prompt bar for this level of the menu
	char 		*prompt;
	// if !0 the pointer *prompt is xfree'd when the instance is
	int		free_prompt;
	// pointer to the global menu, generally always the same
	menu_t		*gmenu;
	// pointer to the local menu, the menu for this level
	menu_t		*lmenu;
	// previous instance, or 1 level down in the menu system, NULL at root
	instance_t	*prev;
	// data specific to this level of the menu
	void		*data;
	// periodic check, called every 30s, returns -1 if no longer valid
	int		(*check)(instance_t *,acontext_t *,time_t);
	// if set then data is free'd with this function when the instance is
	void		(*free)(void *);
};

/**
 * Menu Macros
 */

/*** Macros used to simplify menu definition ***/
#define MENU_CMD_NS(x) int x(instance_t *ins, acontext_t *ac, \
		menu_t *menu_cmd, char **args, int no_args)
#define MENU_CMD(x) static MENU_CMD_NS(x)
#define MENU_HELPER_NS(x) void x(instance_t *ins, acontext_t *ac, \
		char **args, int no_args)
#define MENU_HELPER(x) static MENU_HELPER_NS(x)
#define MENU_CHECK_NS(x) int x(instance_t *ins, acontext_t *ac, time_t now)
#define MENU_CHECK(x) static MENU_CHECK_NS(x)

#define CHAIN_CMD(func) func(ins,ac,menu_cmd,args,no_args)
#define CHAIN_CMD_ARGS(func,args,no_args) func(ins,ac,menu_cmd,args,no_args)

/*** return values ***/
#define RET_VAL(x) 	// legacy 
#define RET_INV_ARG 	-1		/* Invalid Arugment(s) */
#define RET_ISF_ARG 	-2		/* Insufficient Arguments */
#define RET_EXS_ARG	-3 		/* Excess Arguments */
#define RET_INV_CMD	-4		/* Invalid Command */
#define RET_EXE_ERR	-5		/* Execution Error in Command */
#define RET_OK		0		/* All Okay */
#define RET_UP		1		/* Leave this menu level */
#define RET_RTN		2		/* Return to the root menu level */
#define RET_QIT		3		/* Quit */
#define RET_REJ		-1		/* Reject a menu entry */

/**
 * Global and Local Menu variables.
 */
extern menu_t 	*global_menu_root;
extern menu_t 	*main_menu_root;

/**
 * Menu functions.
 */
void	free_menu(menu_t *m);
menu_t	*alloc_menu(enum menu_type_t type);
void	menu_ref(menu_t *m);
void	menu_deref(menu_t *m);
void	menu_add(menu_t *m, menu_t *ent);
void	menu_del(menu_t *m, menu_t *ent);
menu_t	*menu_resolv(const char *path);
menu_t	*menu_from_cmds(const char *name,
		int min_args, int max_args, int log, int hide,
		uint32_t privs,
		int (*func)(instance_t *,acontext_t *,menu_t*,char **,int),
		void (*helper)(instance_t *,acontext_t *,char **,int),
		cmd_t *cmds);
