#ifndef ACTIONS_CSCH_H
#define ACTIONS_CSCH_H

#include <libfungw/fungw.h>

typedef enum {
	FGW_COBJ_ = FGW_CUSTOM + 20,
	FGW_AOBJ_,
	FGW_PROJECT_,
	FGW_SHEET_,
	FGW_ATTRIB_
} csch_fgw_types_e;
#define fgw_cobj(arg)    ((arg)->val.ptr_void)
#define fgw_aobj(arg)    ((arg)->val.ptr_void)
#define fgw_project(arg) ((arg)->val.ptr_void)
#define fgw_sheet(arg)   ((arg)->val.ptr_void)
#define fgw_attrib(arg)  ((arg)->val.ptr_void)
#define FGW_COBJ         ((fgw_type_t)FGW_COBJ_)
#define FGW_AOBJ         ((fgw_type_t)FGW_AOBJ_)
#define FGW_PROJECT      ((fgw_type_t)FGW_PROJECT_)
#define FGW_SHEET        ((fgw_type_t)FGW_SHEET_)
#define FGW_ATTRIB       ((fgw_type_t)FGW_ATTRIB_)

extern const char *CSCH_PTR_DOMAIN_COBJ;
extern const char *CSCH_PTR_DOMAIN_AOBJ;
extern const char *CSCH_PTR_DOMAIN_PROJECT;
extern const char *CSCH_PTR_DOMAIN_SHEET;
extern const char *CSCH_PTR_DOMAIN_ATTRIB;
extern const char *CSCH_PTR_DOMAIN_COBJ_ARR;

void csch_actions_init(fgw_ctx_t *ctx);

#define CSCH_HOOK_FAIL(idx, type, aname) \
	rnd_message(RND_MSG_ERROR, "Internal error: unexpected hook argument %d in %s (expected %s)\n", idx, #aname, #type)

/* Require argument idx to exist and convert it to type; on success, also execute stmt */
#define CSCH_HOOK_CONVARG(idx, type, aname, stmt) \
do { \
	if (argc <= idx) { \
		CSCH_HOOK_FAIL(idx, type, aname); \
		return FGW_ERR_ARGC; \
	} \
	if (fgw_arg_conv(&rnd_fgw, &argv[idx], type) != 0) { \
		CSCH_HOOK_FAIL(idx, type, aname); \
		return FGW_ERR_ARG_CONV; \
	} \
	{ stmt; } \
} while(0)

/* If argument idx exists, convert it to type; on success, also execute stmt */
#define CSCH_HOOK_MAY_CONVARG(idx, type, aname, stmt) \
do { \
	if (argc > idx) { \
		if (fgw_arg_conv(&rnd_fgw, &argv[idx], type) != 0) { \
			CSCH_HOOK_FAIL(idx, type, aname); \
			return FGW_ERR_ARG_CONV; \
		} \
		{ stmt; } \
	} \
} while(0)


/* Convert argv[argid] into keyword cmd. If it's F_Object, accept optional
   =oidpath or :oidpath suffix and require that to point to an existing object,
   which is loaded into obj. obj is NULL if suffix is missing */
#define CSCH_ACT_CONVARG_OBJ(argid, ACTNAME, cmd, obj) \
	do { \
		const char *__tmp__; \
		RND_ACT_CONVARG(argid, FGW_STR, ACTNAME, __tmp__ = argv[argid].val.str); \
		if ((strncmp(__tmp__, "object", 6) == 0) && ((__tmp__[6] == ':') || (__tmp__[6] == '='))) {  \
			csch_oidpath_t __oidp__ = {0}; \
			if (csch_oidpath_parse(&__oidp__, __tmp__+7) != 0) { \
				rnd_message(RND_MSG_ERROR, #ACTNAME ": Invalid oidpath: %s\n", __tmp__+7); \
				return FGW_ERR_ARG_CONV; \
			} \
			obj = csch_oidpath_resolve(sheet, &__oidp__); \
			csch_oidpath_free(&__oidp__); \
			if (obj == NULL) { \
				rnd_message(RND_MSG_ERROR, #ACTNAME ": No such object: %s\n", __tmp__+7); \
				return FGW_ERR_ARG_CONV; \
			} \
			cmd = F_Object; \
		} \
		else { \
			obj = NULL; \
			fgw_arg_conv(&rnd_fgw, &argv[1], FGW_KEYWORD); \
			cmd = fgw_keyword(&argv[1]); \
		} \
	} while(0);

#endif
