#ifndef TASK_H
#define TASK_H
#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>
#include <stdbool.h>

#include "interface.h"

#define TASK_DATA(t) ((uint8_t *)((t)+1))
#define TASK_RET(t)  ((uint16_t *)TASK_DATA(t))
#define TASK_SDS(t)  (TASK_DATA(t)+(t)->returnwidth*2)
#define TASK_PER(t)  (TASK_SDS(t)+(t)->sdslen)
#define TASK_BC(t)   (TASK_PER(t)+(t)->peripherals*PTRSIZE)

struct task {
	//Task id
	uint8_t taskid;
	//Stability value
	uint8_t stability;
	//Number of 16 bit cells occupied by the return value
	uint8_t returnwidth;
	//Number of bytes occupied by the sdsses
	uint16_t sdslen;
	//Number of peripheral
	uint8_t peripherals;
	//Number of bytes occupied by the bytecode
	uint16_t bclen;
	//Pointer to the task tree
	uint16_t tree;
	//Task value
	//uint16_t returnvalue[returnwidth]
	//The sds bytes
	//uint8_t sdsses[sdslen]
	//The peripherals
	//struct peripheral[peripherals]
	//The program bytes
	//uint8_t bytes[bclen]
};

/*
struct peripheral {
	void *data;
}
*/

/*
struct sds {
	uint8_t sdsid;
	bool itask;
	uint8_t len;
	uint8_t bytes[len];
};
*/

struct tasktree {
	//Type of the task
	uint8_t task_type;
	bool trash;
	//Reverse ptr
	uint16_t ptr;
	union {
// Constant node values {{{
		uint16_t stable[4];
		uint16_t unstable[4];
		struct {
			uint16_t next;
			uint8_t w;
			uint16_t stable[2];
		} stablenode;
		struct {
			uint16_t next;
			uint8_t w;
			uint16_t unstable[2];
		} unstablenode;
//}}}
//Pin IO {{{
		//Read pin
		uint16_t readd;
		uint16_t reada;
		struct {
			uint16_t pin;
			uint8_t pinmode;
		} pinmode;
		struct {
			//Pin to write
			uint16_t pin;
			//Value to write
			bool value;
		} writed;
		struct {
			//Pin to write
			uint16_t pin;
			//Value to write
			uint8_t value;
		} writea;
//}}}
//Repeat, delay and step {{{
		struct {
			//Pointer to the tree
			uint16_t tree;
			//Pointer to the original tree
			uint16_t oldtree;
		} repeat;
		//Waiting time
		uint64_t delay;
		//Milliseconds since boot
		uint64_t until;
		struct {
			//Pointer to lhs
			uint16_t lhs;
			//Pointer to function for the rhs
			uint16_t rhs;
			//Return size of rhs
			uint8_t w;
		} step;
		struct {
			//Pointer to lhs
			uint16_t lhs;
			//Pointer to function for the rhs
			uint16_t rhs;
			//Return size of rhs
			uint8_t w;
		} steps;
		struct {
			//Pointer to lhs
			uint16_t lhs;
			//Pointer to function for the rhs
			uint16_t rhs;
			//Return size of rhs
			uint8_t w;
		} stepu;
		struct {
			//Pointer to lhs
			uint16_t lhs;
			//Pointer to function for the rhs
			uint16_t rhs;
			//Width of the rhs
			uint8_t w;
		} seqs;
		struct {
			//Pointer to lhs
			uint16_t lhs;
			//Pointer to function for the rhs
			uint16_t rhs;
			//Width of the rhs
			uint8_t w;
		} sequ;
//}}}
//Parallel {{{
		struct {
			//Pointer to lhs
			uint16_t lhs;
			//Pointer to rhs
			uint16_t rhs;
			//Return size of lhs
//			uint8_t lw;
			//Return size of rhs
//			uint8_t rw;
		} tand;
		struct {
			//Pointer to lhs
			uint16_t lhs;
			//Pointer to rhs
			uint16_t rhs;
			//Return size of lhs and rhs
//			uint8_t w;
		} tor;
//}}}
//Sds {{{
		//Pointer to the data
		struct {
			//Pointer to the sds data
			uint16_t sds;
			//Id of the sds
			uint8_t sdsid;
		} sdsget;
		struct {
			//Pointer to the data from the sds
			uint16_t sds;
			//Id of the sds
			uint8_t sdsid;
			//Pointer to the data that we write
			uint16_t data;
		} sdsset;
//}}}
//Peripherals {{{
		uint8_t dhttemp;
		uint8_t dhthumid;
		uint8_t ledmatrixclear;
		uint8_t ledmatrixdisplay;
		struct {
			uint8_t id;
			uint8_t intensity;
		} ledmatrixintensity;
		struct {
			uint8_t id;
			uint8_t x;
			uint8_t y;
			bool s;
		} ledmatrixdot;
		uint8_t abutton;
		uint8_t bbutton;
		uint8_t lightsensor;
		struct {
			float humid;
			float temp;
			uint8_t sensor;
		} setenvironment;
		uint8_t airqualitysensor;
//}}}
	} data;
};

struct task *task_head(void);
struct task *task_next(struct task *);
void task_complete(struct task *, uint16_t *);
void task_remove(struct task *, uint16_t *stack);

void *task_peripheral(uint8_t index);

#ifdef DEBUG
void tasktree_print(struct tasktree *, int);
void tasktree_print_node(struct tasktree *);
#else
#define tasktree_print(i, j)
#define tasktree_print_node(i)
#endif

uint16_t tasktree_clone(uint16_t, uint16_t);

uint16_t sds_get_addr(uint8_t);

void task_register(void);
void sds_recv(void);
void task_delete(uint8_t num);

#ifdef __cplusplus
}
#endif
#endif
