#ifndef KIcli
#define KIcli

#include <k/core.h>
#include <k/io.h>
#include <k/type.h>
#include <k/internal.egroup.h>

/* input types */

typedef struct kcli_opt {
	rune id;
	const char* name;
	enum kcli_opt_kind {
		kcli_opt_none /* flag is disabled and hidden */,
		kcli_opt_string /* flag takes a string argument */,
		kcli_opt_flag /* on if present, off if absent */,
		kcli_opt_toggle /* off by default, value toggles
		                 * for each occurrence */,
		kcli_opt_accumulate /* u8, value increases for each
		                     * occurrence, saturates at 255 */,
		kcli_opt_enum /* matched against a table of string
		               * values to retrieve the corresponding
					   * integer ID */,

		kcli_opt_int = 0x40,
		/* kcli_opt_int takes a default base parameter.
		 * for instance, to take a decimal number, you
		 * might write `kcli_opt_int | 10.` if the
		 * argument takes a base prefix, the default
		 * base will be disregarded. */
			kcli_opt_oct = kcli_opt_int | 8,
			kcli_opt_dec = kcli_opt_int | 10,
			kcli_opt_hex = kcli_opt_int | 16,
	} kind;
	void* val;
	const char* desc;
} kcli_opt;

typedef struct kcli_param {
	const char* name;
	enum kcli_param_kind {
		kcli_param_none,
		kcli_param_string,
		kcli_param_enum,
		kcli_param_int = 0x40,
			kcli_param_oct = kcli_param_int | 8,
			kcli_param_dec = kcli_param_int | 10,
			kcli_param_hex = kcli_param_int | 16,
	} kind;
	enum kcli_rule {
		kcli_rule_forbidden,
		kcli_rule_required,
		kcli_rule_optional,
		kcli_rule_overflow,
	} rule;
	void* val;
	const char* desc;
} kcli_param;

typedef struct kcli_set {
	const char*       name;
	const char*       version;
	const char**      args;   sz argc;
	const char*       desc;
	const kcli_param* params; sz paramc;
	const kcli_opt*   opts;   sz optc;
} kcli_set;

/* output types */

typedef enum kcli_cond {
	kcli_cond_ok = kcli_cond_id,
	kcli_cond_extra /* parse succeded, but arguments or
	                   flags were left over */,
	kcli_cond_fail /* unspecified error */,
	kcli_cond_parse /* bad syntax, parse failed */,
	kcli_cond_overlong /* a string in the configuration structures is longer than allowed */,
} kcli_cond;

typedef enum kcli_flag {
	kcli_flag_off = 0,
	kcli_flag_on = 1,
} kcli_flag;

/* functions */

kcond kcli_usage(kcli_set, kiochan);
kcli_cond kcli_parse(kcli_set);

/* macros */

#define Kcli_param(field,kind,rule,description) \
	{#field, kcli_param_##kind, kcli_rule_##rule, &field, description}
#define Kcli_opt(long,short,kind,description) \
	{short, #long, kcli_opt_##kind, &long, description}

#endif
