#define SUBSYSTEM APPLICATION_EXEC "_dep: "

#define DEP_TOKEN_SIZE CONFIG_LINE_LENGTH					/* Token size in bytes including terminating zero */

enum dep_node_types {								/* Node types */
	NODE_TYPE_NUMBER,
	NODE_TYPE_STRING,
	NODE_TYPE_ANOVAR,
	NODE_TYPE_SYMBOL,
	NODE_TYPE_CAST,
	NODE_TYPE_LIST
};

struct dep_node {
	int c;									/* Node type, one of dep_node_types */
	int d;									/* Node type cast */

	ssize_t offs;								/* Node symbol offset in eval table or variable type */

	union {
		D_NUMBER num;

		char *str;
		char sym[DEP_TOKEN_SIZE];

		struct {
			size_t c;						/* Node count for children */

			struct dep_node **child;
		} list;
	} value;
};

struct dep_env_it {
	char name[DEP_TOKEN_SIZE];

	struct dep_node *value;
	struct dep_env_it *next;
};

struct dep_env {
	struct dep_env_it *head;
};

struct t_dep_eval {
	const char *s;								/* Operator name */

	size_t t;								/* Operator name length in bytes */

	int e;									/* Operator extra flag */

	struct dep_node *(*fn)(struct dep_node *, struct dep_env *, int);
};

struct dep_hnd {
	D_HANDLE hnd;								/* Expression handle */

	struct dep_env *env;							/* Expression environment */
	struct dep_node *ret;							/* Expression result */
};

static struct dep_node *dep_eval_define(struct dep_node *, struct dep_env *, int);
static struct dep_node *dep_eval_if(struct dep_node *, struct dep_env *, int);
static struct dep_node *dep_eval_cmp(struct dep_node *, struct dep_env *, int);
static struct dep_node *dep_eval_and(struct dep_node *, struct dep_env *, int);
static struct dep_node *dep_eval_or(struct dep_node *, struct dep_env *, int);
static struct dep_node *dep_eval_not(struct dep_node *, struct dep_env *, int);
static struct dep_node *dep_eval_abs(struct dep_node *, struct dep_env *, int);
static struct dep_node *dep_eval_add(struct dep_node *, struct dep_env *, int);
static struct dep_node *dep_eval_sub(struct dep_node *, struct dep_env *, int);
static struct dep_node *dep_eval_mul(struct dep_node *, struct dep_env *, int);
static struct dep_node *dep_eval_div(struct dep_node *, struct dep_env *, int);

static const struct t_dep_eval t_dep_eval_t[] = {
	{ "define", 6, 0, dep_eval_define },

	{ "if", 2, 0, dep_eval_if },

	{ "=", 1, 1, dep_eval_cmp },
	{ "/=", 2, 2, dep_eval_cmp },
	{ "<", 1, 3, dep_eval_cmp },
	{ ">", 1, 4, dep_eval_cmp },
	{ "<=", 2, 5, dep_eval_cmp },
	{ ">=", 2, 6, dep_eval_cmp },

	{ "eq", 2, 1, dep_eval_cmp },
	{ "ne", 2, 2, dep_eval_cmp },
	{ "lt", 2, 3, dep_eval_cmp },
	{ "gt", 2, 4, dep_eval_cmp },
	{ "le", 2, 5, dep_eval_cmp },
	{ "ge", 2, 6, dep_eval_cmp },

	{ "&", 1, 0, dep_eval_and },
	{ "|", 1, 0, dep_eval_or },
	{ "!", 1, 0, dep_eval_not },

	{ "and", 3, 0, dep_eval_and },
	{ "or", 2, 0, dep_eval_or },
	{ "not", 3, 0, dep_eval_not },

	{ "abs", 3, 0, dep_eval_abs },

	{ "+", 1, 0, dep_eval_add },
	{ "-", 1, 0, dep_eval_sub },
	{ "*", 1, 0, dep_eval_mul },
	{ "/", 1, 1, dep_eval_div },
	{ "%", 1, 2, dep_eval_div },

	{ "add", 3, 0, dep_eval_add },
	{ "sub", 3, 0, dep_eval_sub },
	{ "mul", 3, 0, dep_eval_mul },
	{ "div", 3, 1, dep_eval_div },
	{ "mod", 3, 2, dep_eval_div },

	{ NULL, 0, 0, NULL }
};

static unsigned int c_env = 0;							/* Environment count created */

static struct dep_hnd **a_env = NULL;						/* Environment contexts */

static D_LOCK t_sem_p = D_LOCK_INIT;						/* Semaphores for reader and writer */

void dep_free(D_HANDLE);

static struct dep_env *dep_run_op(D_HANDLE, D_HANDLE *);
static void dep_run_at(D_HANDLE, struct dep_node *);

static unsigned int dep_ret_op(struct dep_node *, void **);

static struct dep_node *dep_parse(const char **);
static struct dep_node *dep_parse_list(const char **);
static struct dep_node *dep_parse_str(const char **);
static size_t dep_parse_str_op(const char **);
static void dep_parse_str_at(char *);
static struct dep_node *dep_parse_var(const char **);
static int dep_parse_num_op(char *);
static int dep_parse_num_at(D_NUMBER *, char *, size_t);

static struct dep_node *dep_eval(struct dep_node *, struct dep_env *, int);
static struct dep_node *dep_eval_list(struct dep_node *, struct dep_env *, int);
static struct dep_node *dep_eval_func(struct dep_node *, struct dep_env *, char *, int);
static struct dep_node *dep_eval_func_rt(int);
static void dep_eval_func_et(struct dep_node *, struct d_par *);
static int dep_eval_func_num(struct dep_node *, struct d_par_t *, int);
static int dep_eval_func_str(struct dep_node *, struct d_par_t *);
static int dep_eval_var(struct dep_node *);
static int dep_eval_cmp_op(struct dep_node *, D_NUMBER *);
static int dep_eval_cmp_at(D_NUMBER, D_NUMBER, int);
static struct dep_node *dep_eval_bool(int);
static int dep_eval_true(struct dep_node *);

static int dep_node_add(struct dep_node *, struct dep_node *);
static struct dep_node *dep_node_cpy(struct dep_node *);
static struct dep_node *dep_node_new(int);

static struct dep_env *dep_env_new(void);
static struct dep_node *dep_env_get(struct dep_env *, char *);
static int dep_env_set(struct dep_env *, char *, struct dep_node *);

static void dep_free_tree(struct dep_node *);
static void dep_free_envs(struct dep_env *);

/* dsl.c */
int dsl_get_num_by_name(char *, size_t, unsigned int *);
struct dsl_ctx *dsl_get_main_ctx(void);
struct dsl_str *dsl_get_rc_var(void);
int dsl_get_remote(const char *);
