#include "rewrite.h"

#include "interpret.h"
#include "mem.h"
#include "events.h"

extern struct MTask *current_task;
extern uint32_t now;

//TODO make non-recursive
uint16_t *rewrite(struct TaskTree *t, uint8_t *program, uint16_t *stack)
{
	msg_debug(SC("rewriting code stack: %p\n"), stack);
	uint16_t *oldstack;
	uint16_t width, t16;
	float tfloat;

//	for (uint16_t j = 0; j<sp+2; j++)
//		msg_debug(SC("stack[%u]: %u\n"), j, stack[j]);

	switch (t->task_type) {
//Constant node values {{{
	case BCStableNode_c:
		*stack++ = MTStable_c;
		*stack++ = t->data.stablenode.stable[0];
		*stack++ = t->data.stablenode.stable[1];
		oldstack = stack;
		stack = rewrite(t->data.stablenode.next, program, stack);
		if (stack == NULL)
			return NULL;

		for ( ; oldstack < stack; oldstack++)
			oldstack[0] = oldstack[1];
		stack--;
		break;
	case BCStable0_c:
		msg_debug(SC("Rewrite:Stable0\n"));
		*stack++ = MTStable_c;
		break;
	case BCStable1_c:
		msg_debug(SC("Rewrite:Stable1\n"));
		*stack++ = MTStable_c;
		*stack++ = t->data.stable[0];
		break;
	case BCStable2_c:
		msg_debug(SC("Rewrite:Stable2\n"));
		*stack++ = MTStable_c;
		*stack++ = t->data.stable[0];
		*stack++ = t->data.stable[1];
		break;
	case BCStable3_c:
		msg_debug(SC("Rewrite:Stable3\n"));
		*stack++ = MTStable_c;
		*stack++ = t->data.stable[0];
		*stack++ = t->data.stable[1];
		*stack++ = t->data.stable[2];
		break;
	case BCStable4_c:
		msg_debug(SC("Rewrite:Stable4\n"));
		*stack++ = MTStable_c;
		*stack++ = t->data.stable[0];
		*stack++ = t->data.stable[1];
		*stack++ = t->data.stable[2];
		*stack++ = t->data.stable[3];
		break;
	case BCUnstableNode_c:
		msg_debug(SC("Rewrite:Unstablenode\n"));
		*stack++ = MTUnstable_c;
		*stack++ = t->data.unstablenode.unstable[0];
		*stack++ = t->data.unstablenode.unstable[1];
		oldstack = stack;
		stack = rewrite(t->data.unstablenode.next, program, stack);
		if (stack == NULL)
			return NULL;

		for ( ; oldstack < stack; oldstack++)
			oldstack[0] = oldstack[1];
		stack--;
		break;
	case BCUnstable0_c:
		msg_debug(SC("Rewrite:Unstable0\n"));
		*stack++ = MTUnstable_c;
		break;
	case BCUnstable1_c:
		msg_debug(SC("Rewrite:Unstable1\n"));
		*stack++ = MTUnstable_c;
		*stack++ = t->data.unstable[0];
		break;
	case BCUnstable2_c:
		msg_debug(SC("Rewrite:Unstable2\n"));
		*stack++ = MTUnstable_c;
		*stack++ = t->data.unstable[0];
		*stack++ = t->data.unstable[1];
		break;
	case BCUnstable3_c:
		msg_debug(SC("Rewrite:Unstable3\n"));
		*stack++ = MTUnstable_c;
		*stack++ = t->data.unstable[0];
		*stack++ = t->data.unstable[1];
		*stack++ = t->data.unstable[2];
		break;
	case BCUnstable4_c:
		msg_debug(SC("Rewrite:Unstable4\n"));
		*stack++ = MTUnstable_c;
		*stack++ = t->data.unstable[0];
		*stack++ = t->data.unstable[1];
		*stack++ = t->data.unstable[2];
		*stack++ = t->data.unstable[3];
		break;
//}}}
//Pin IO {{{
	case BCReadD_c:
		msg_debug(SC("Rewrite:ReadD\n"));
		*stack++ = MTUnstable_c;
		*stack++ = read_dpin(t->data.readd);
		break;
	case BCWriteD_c:
		msg_debug(SC("Rewrite:WriteD\n"));
		write_dpin(t->data.writed.pin, t->data.writed.value);

		*stack++ = MTStable_c;
		*stack++ = t->data.writed.value;

		t->task_type = BCStable1_c;
		t->data.stable[0] = t->data.writed.value;

		if (current_task->status != MTUnevaluated_c)
			current_task->status = MTPurged_c;
		break;
	case BCReadA_c:
		msg_debug(SC("Rewrite:ReadA\n"));
		*stack++ = MTUnstable_c;
		*stack++ = read_apin(t->data.reada);
		break;
	case BCWriteA_c:
		msg_debug(SC("Rewrite:WriteA\n"));
		write_apin(t->data.writea.pin, t->data.writea.value);

		*stack++ = MTStable_c;
		*stack++ = t->data.writea.value;

		t->task_type = BCStable1_c;
		t->data.stable[0] = t->data.writea.value;

		if (current_task->status != MTUnevaluated_c)
			current_task->status = MTPurged_c;
		break;
	case BCPinMode_c:
		msg_debug(SC("Rewrite:pinmode\n"));
		set_pinmode(t->data.pinmode.pin, t->data.pinmode.pinmode);
		t->task_type = BCStable0_c;
		*stack++ = MTStable_c;

		if (current_task->status != MTUnevaluated_c)
			current_task->status = MTPurged_c;
		break;
	case BCInterrupt_c:
		msg_debug(SC("Rewrite:interrupt\n"));

		if (!t->data.interrupt.initialized) {
			register_events(current_task, t);
			t->data.interrupt.initialized = true;
		}

		if (!t->data.interrupt.triggered) {
			*stack++ = MTNoValue_c;
			stack++;
			break;
		}

		t->task_type = BCStable1_c;
		t->data.stable[0] = t->data.interrupt.status;

		*stack++ = MTStable_c;
		*stack++ = t->data.interrupt.status;
		break;
//}}}
// Steps {{{
	case BCStep_c:
		msg_debug(SC("Rewrite:Step (%u)\n"), t->data.step.w);
		tasktree_print(t, 0);
		msg_debug(SC("\n"));
		//Save the stack pointer
		oldstack = stack;
		//Prepare the stack for interpretation
		width = 0;
		INITSTACKMAIN(stack, width);
		//Rewrite
		stack = rewrite(t->data.step.lhs, program, stack+width);
		if (stack == NULL)
			return NULL;
		for (uint16_t *sp = oldstack; sp != stack; sp++) {
			msg_debug("sp: %lu\n", *sp);
		}
		//Interpret
		if (!interpret(program, t->data.step.rhs,
				stack-oldstack, oldstack))
			return NULL;
		for (uint16_t *sp = oldstack; sp != stack; sp++) {
			msg_debug("sp: %lu\n", *sp);
		}
		//Save the width, it might be destroyed if we had a match
		width = t->data.step.w;
		//There was no match...
		if (*oldstack == MT_NULL) {
			msg_debug(SC("Step nomatch\n"));
		} else {
			msg_debug(SC("Step match: %u\n"), *oldstack);
			tasktree_print(t, 0);
			msg_debug(SC("\nmatch\n"));
			tasktree_print(mem_cast_tree(*oldstack), 0);
			msg_debug(SC("\n"));

			//Clean up lhs
			mem_mark_trash_and_destroy(t->data.step.lhs, current_task, stack);

			//Move the node to t
			mem_node_move(t, mem_cast_tree(*oldstack));

			msg_debug(SC("After move: %u\n"), *oldstack);
			tasktree_print(t, 0);

			// Mark as changed
			current_task->status = MTUnevaluated_c;
		}
		//Set the stack back to the old stack
		stack = oldstack;
		//Step never returns
		*stack++ = MTNoValue_c;
		//pad with the rhs width
		stack += width;
		break;
	case BCStepStable_c:
		msg_debug(SC("Rewrite:Stepstable (%u, %u)\n"),
			t->data.steps.w, t->data.steps.rhs);
		//Save the stack pointer
		oldstack = stack;
		//Prepare the stack for interpretation
		width = 0;
		INITSTACKMAIN(stack, width);
		//Rewrite
		stack = rewrite(t->data.steps.lhs, program, stack+width);
		if (stack == NULL)
			return NULL;
		width = t->data.steps.w;
		//Width might be lost if we need to rewrite
		if (*(oldstack + STACKMETA) == MTStable_c) {
			//Interpret the rhs
			if (!interpret(program, t->data.steps.rhs,
					stack-oldstack, oldstack))
				return NULL;

			//Clean up lhs
			mem_mark_trash_and_destroy(t->data.steps.lhs, current_task, stack);

			//Move the node to t
			mem_node_move(t, mem_cast_tree(*oldstack));

			// Mark as changed
			current_task->status = MTUnevaluated_c;
		}
		//Set the stack back to the old stack
		stack = oldstack;
		//Step never returns
		*stack++ = MTNoValue_c;
		//pad with the rhs width
		stack += width;
		break;
	case BCStepUnstable_c:
		msg_debug(SC("Rewrite:Stepunstable (%u)\n"), t->data.stepu.w);
		oldstack = stack;
		width = 0;
		INITSTACKMAIN(stack, width);
		stack = rewrite(t->data.stepu.lhs, program, stack+width);
		if (stack == NULL)
			return NULL;
		width = t->data.stepu.w;
		if (*(oldstack + STACKMETA) != MTNoValue_c) {
			if (!interpret(program, t->data.stepu.rhs,
				stack-oldstack, oldstack))
				return NULL;
			mem_mark_trash_and_destroy(t->data.stepu.lhs, current_task, stack);
			mem_node_move(t, mem_cast_tree(*oldstack));

			// Mark as changed
			current_task->status = MTUnevaluated_c;
		}
		stack = oldstack;
		*stack++ = MTNoValue_c;
		stack += width;
		break;
	case BCSeqStable_c:
		msg_debug(SC("Rewrite:seqs (%u)\n"), t->data.seqs.w);
		//Rewrite lhs
		if (rewrite(t->data.seqs.lhs, program, stack) == NULL)
			return NULL;

		//Save the width, it might be destroyed if we had a match
		width = t->data.seqs.w;
		//There was no match...
		if (*stack != MTStable_c) {
			msg_debug(SC("Step nomatch\n"));
		} else {
			msg_debug(SC("Step match\n"));

			//Clean up lhs
			mem_mark_trash_and_destroy(t->data.seqs.lhs, current_task, stack);

			//Move the node to t
			mem_node_move(t, t->data.seqs.rhs);

			// Mark as changed
			current_task->status = MTUnevaluated_c;
		}

		//Step never returns
		*stack++ = MTNoValue_c;
		//pad with the rhs width
		stack += width;
		break;
	case BCSeqUnstable_c:
		msg_debug(SC("Rewrite:sequ (%u)\n"), t->data.sequ.w);
		//Rewrite lhs
		if (rewrite(t->data.sequ.lhs, program, stack) == NULL)
			return NULL;

		//Save the width, it might be destroyed if we had a match
		width = t->data.sequ.w;
		//There was no match...
		if (*stack == MTNoValue_c) {
			msg_debug(SC("Step nomatch\n"));
		} else {
			msg_debug(SC("Step match\n"));

			//Clean up lhs
			mem_mark_trash_and_destroy(t->data.sequ.lhs, current_task, stack);

			//Move the node to t
			mem_node_move(t, t->data.sequ.rhs);

			// Mark as changed
			current_task->status = MTUnevaluated_c;
		}

		//Step never returns
		*stack++ = MTNoValue_c;
		//pad with the rhs width
		stack += width;
		break;
//}}}
//Repeat, delay {{{
	case BCRepeat_c:
		msg_debug(SC("Rewrite:Repeat\n"));
		if (t->data.repeat.tree == NULL) {
			msg_debug(SC("Clone repeat tree\n"));
			t->data.repeat.done = false;
			if (t->data.repeat.start == 0)
				t->data.repeat.start = current_task->lastrun;
			t->data.repeat.tree =
				tasktree_clone(t->data.repeat.oldtree, t);
			if (t->data.repeat.tree == NULL)
				return NULL;
			tasktree_print(t->data.repeat.tree, 0);
			msg_debug(SC("\n"));

			current_task->status = MTUnevaluated_c;
		}
		oldstack = stack;
		stack = rewrite(t->data.repeat.tree, program, stack);
		if (stack == NULL)
			return NULL;

		//Stable
		if (*oldstack == MTStable_c) {
			t->data.repeat.done = true;
			*oldstack = MTUnstable_c;
		}

		// Reinitialize
		if (t->data.repeat.done &&
				current_task->lastrun - t->data.repeat.start >=
				t->refresh_min * (t->seconds ? 1000u : 1u)) {
			//Clean up lhs
			mem_mark_trash_and_destroy(t->data.repeat.tree, current_task, stack);
			t->data.repeat.tree = NULL;
			// Set the next start time to the current time
			// Or the maximum run time + last start time if the task was overdue
			if (current_task->lastrun - t->data.repeat.start >=
					t->refresh_max * (t->seconds ? 1000u : 1u)) {
				t->data.repeat.start =
					t->data.repeat.start +
					t->refresh_max *
						(t->seconds ? 1000u : 1u);
			} else {
				t->data.repeat.start = current_task->lastrun;
			}
		}

		if (current_task->status != MTUnevaluated_c &&
			t->data.repeat.done)
			current_task->status = MTPurged_c;
		break;
	case BCDelay_c:
		t->data.until = now + t->data.delay;
		t->task_type = BCDelayUntil_c;
		/*-fallthrough*/
	case BCDelayUntil_c:
		msg_debug(SC("Rewrite:DelayUntil\n"));
		msg_debug(SC("now: %lu\n"), now);
		msg_debug(SC("until: %lu\n"), t->data.until);
		//Overshot time
		*PALIGN(int32_t, stack+3) = now-t->data.until;
		stack[0] = MTUnstable_c;
		stack[1] = (*PALIGN(int32_t, stack+3) >> 16) & 0xffff;
		stack[2] = *PALIGN(int32_t, stack+3) & 0xffff;
		if (*PALIGN(int32_t, stack+3) >= 0) {
			stack[0] = MTStable_c;
			t->task_type = BCStable1_c;
			t->data.until = *PALIGN(int32_t, stack+3);
			t->data.stable[0] = stack[1];
			t->data.stable[1] = stack[2];
		}
		stack+=3;

		if (current_task->status != MTUnevaluated_c)
			current_task->status = MTPurged_c;
		break;
//}}}
//Parallel {{{
	case BCTOr_c:
		oldstack = stack;
		stack = rewrite(t->data.tor.lhs, program, stack);
		if (stack == NULL)
			return NULL;
		//msg_debug(SC("rewrite: sp: %u\n"), sp);
		//msg_debug(SC("After rewriting lhs\n"));
		//for (uint16_t j = 0; j<sp+2; j++)
		//	msg_debug(SC("stack[%u]: %u\n"), j, stack[j]);

		//lhs is stable, done
		if (*oldstack == MTStable_c) {
			msg_debug(SC("lhs is stable, done\n"));
			//Clean up rhs
			mem_mark_trash_and_destroy(t->data.tor.rhs, current_task, stack);
			//Move the lhs to t
			mem_node_move(t, t->data.tor.lhs);

			if (current_task->status != MTUnevaluated_c)
				current_task->status = MTPurged_c;
			break;
		//lhs has no value, use rhs
		} else if (*oldstack == MTNoValue_c) {
			msg_debug(SC("lhs has no value, just eval rhs\n"));
			stack = oldstack;
			if (rewrite(t->data.tor.rhs, program, stack) == NULL)
				return NULL;
		//lhs is unstable, eval rhs and see if it is more stable
		} else {
			/*
			 * oldstack-width : lhs stability
			 *                : lhs
			 * oldstack       : rhs stability
			 *                : rhs
			 * stack
			 */
			width = stack-oldstack;
			oldstack = stack;
			stack = rewrite(t->data.tor.rhs, program, stack);
			if (stack == NULL)
				return NULL;
			if (*oldstack == MTStable_c) {
				oldstack -= width;
				stack -= width;
				for (uint8_t i = 0; i<width; i++)
					oldstack[i] = stack[i];
				//Clean up lhs
				mem_mark_trash_and_destroy(t->data.tor.lhs, current_task, stack);
				//Move the rhs to t
				mem_node_move(t, t->data.tor.rhs);

				if (current_task->status != MTUnevaluated_c)
					current_task->status = MTPurged_c;
			}
		}
		break;
	case BCTAnd_c:
		msg_debug(SC("Rewrite .&&.\n"));

		//Rewrite the lhs and the rhs
		oldstack = stack;
		stack = rewrite(t->data.tand.lhs, program, stack);
		if (stack == NULL)
			return NULL;
		msg_debug(SC("Rewritten lhs\n"));
		width = stack-oldstack;
		//rhs starts just right of lhs compensating for the stability
		oldstack = stack;
		stack = rewrite(t->data.tand.rhs, program, stack);
		if (stack == NULL)
			return NULL;
		msg_debug(SC("Rewritten rhs\n"));

		/*
		 * oldstack-width : lhs stability
		 *                : lhs
		 * oldstack       : rhs stability
		 *                : rhs
		 * stack
		 */

		//The stability is the minimum of the both values
		msg_debug(SC("lhs stability: %u, rhs: %u\n"),
			*(oldstack-width), *oldstack);
		*(oldstack-width)
			= *(oldstack-width) < *oldstack
			? *(oldstack-width)
			: *oldstack;
		//Compress the taskvalue
		for (uint8_t i = 0; i<stack-oldstack; i++)
			oldstack[i] = oldstack[i+1];
		stack--;
		break;
//}}}
//Sds {{{
	case BCSdsGet_c:
		*stack++ = MTUnstable_c;
		msg_debug(SC("Get sds at %p\n"), t->data.sdsget);
		stack = sds_get_mtask(t->data.sdsget, stack);
		break;
	case BCSdsSet_c:
		msg_debug(SC("Set sds at %p\n"), t->data.sdsset.sds);

		tasktree_print(t->data.sdsset.data, 0);
		msg_debug(SC("\n"));
		oldstack = stack;
		stack = rewrite(t->data.sdsset.data, program, stack);
		if (stack == NULL)
			return NULL;
		//Jump over the stability
		oldstack++;

		//Write to the actual share and update server if necessary
		sds_set_mtask(t->data.sdsset.sds, oldstack);

		//Set this node to be the data
		mem_node_move(t, t->data.sdsset.data);

		if (current_task->status != MTUnevaluated_c) {
			current_task->status = MTPurged_c;
		}

		break;
	case BCSdsUpd_c:
		msg_debug(SC("Get sds at %lu\n"), t->data.sdsupd.sds);

		oldstack = stack;

		//Prepare the stack for interpretation
		width = 0;
		INITSTACKMAIN(stack, width);
		stack += width; // we saved the old stack anyway

		msg_debug("stack initialised for interpretation\n");
		for (uint16_t *sp = oldstack; sp < stack; sp++) {
			msg_debug("sp: %lu\n", *sp);
		}

		//Get the old value of the share
		stack = sds_get_mtask(t->data.sdsupd.sds, stack);
		width = stack-oldstack;

		//Rewrite the context
		msg_debug("rewrite context\n");
		for (uint16_t *sp = oldstack; sp < stack; sp++) {
			msg_debug("sp: %lu\n", *sp);
		}

		//Context is a task tree so we strip the stability and put it
		//back
		t16 = oldstack[width-1];
		stack = rewrite(t->data.sdsupd.ctx, program, stack-1);
		if (stack == NULL)
			return NULL;
		oldstack[width-1] = t16;
		for (uint16_t *sp = oldstack; sp < stack; sp++) {
			msg_debug("sp: %lu\n", *sp);
		}

		//Interpret the function
		msg_debug("interpret function\n");
		if (!interpret(program, t->data.sdsupd.fun, stack-oldstack,
			       oldstack))
			return NULL;
		for (uint16_t *sp = oldstack; sp < stack+width; sp++) {
			msg_debug("sp: %lu\n", *sp);
		}
		msg_debug("done with interpretting function: p\n");

		//Save the tasktree and rewrite the result
		t16 = oldstack[0];
		stack = oldstack;
		stack = rewrite(mem_ptr(t16), program, oldstack);

		//Write to the actual share and update server if necessary
		// oldstack+1 to jump over the stability
		sds_set_mtask(t->data.sdsupd.sds, oldstack+1);

		//Clean up ctx
		mem_mark_trash_and_destroy(t->data.sdsupd.ctx, current_task, stack);

		//Set this node to be the data
		mem_node_move(t, mem_cast_tree(t16));

		if (current_task->status != MTUnevaluated_c)
			current_task->status = MTPurged_c;

		break;
//}}}
//Rate limit {{{
	case BCRateLimit_c:
		msg_debug(SC("Rewrite RateLimit\n"));

		if (t->data.ratelimit.storage == NULL ||
			current_task->lastrun - t->data.ratelimit.last_execution >=
				t->refresh_min * (t->seconds ? 1000u : 1u)) {
			msg_debug(SC("Execute child task at: %p\n"),
				t->data.ratelimit.task);
			tasktree_print(t->data.ratelimit.task, 0);
			msg_debug(SC("\n"));

			oldstack = stack;
			stack = rewrite(t->data.ratelimit.task, program, stack);

			t->data.ratelimit.last_execution =
				current_task->lastrun;

			// Store this value for future reevaluations
			mem_mark_trash_and_destroy(t->data.ratelimit.storage, current_task, stack);
			struct TaskTree *s = create_result_task(
				oldstack + 1, stack);
			t->data.ratelimit.storage = s;
			s->ptr = t;
		} else {
			msg_debug(
				SC("Return stored result, %u ms until new result\n"),
				(t->data.ratelimit.last_execution +
				 t->refresh_min  * (t->seconds ? 1000u : 1u)) -
					current_task->lastrun);

			stack = rewrite(t->data.ratelimit.storage,
				program, stack);
		}

		if (current_task->status != MTUnevaluated_c)
			current_task->status = MTPurged_c;

		break;
//}}}
//Peripherals {{{
//DHT {{{
#ifdef HAVE_DHT
	case BCDHTTemp_c:
		msg_debug(SC("dht read temp: %u\n"), t->data.dhttemp);
		*stack++ = MTUnstable_c;
		tfloat = get_dht_temp(t->data.dhttemp);
		*stack++ = float2uint32_t(tfloat) >> 16;
		*stack++ = float2uint32_t(tfloat) & 0xffff;
		break;
	case BCDHTHumid_c:
		msg_debug(SC("dht read humid: %u\n"), t->data.dhthumid);
		*stack++ = MTUnstable_c;
		tfloat = get_dht_humidity(t->data.dhthumid);
		*stack++ = float2uint32_t(tfloat) >> 16;
		*stack++ = float2uint32_t(tfloat) & 0xffff;
		break;
#endif /* HAVE_DHT */
//}}}
//I2CButton {{{
#ifdef HAVE_I2CBUTTON
	case BCAButton_c:
		msg_debug(SC("abutton: %u\n"), t->data.abutton);
		*stack++ = MTUnstable_c;
		*stack++ = i2c_abutton(t->data.abutton);
		break;
	case BCBButton_c:
		msg_debug(SC("bbutton: %u\n"), t->data.bbutton);
		*stack++ = MTUnstable_c;
		*stack++ = i2c_bbutton(t->data.bbutton);
		break;
#endif /* HAVE_I2CBUTTON */
//}}}
//LIGHTSENSOR {{{
#ifdef HAVE_LIGHTSENSOR
	case BCGetLight_c:
		msg_debug(SC("light read: %u\n"), t->data.lightsensor);
		*stack++ = MTUnstable_c;
		tfloat = get_light(t->data.lightsensor);
		*stack++ = float2uint32_t(tfloat) >> 16;
		*stack++ = float2uint32_t(tfloat) & 0xffff;
		break;
#endif /* HAVE_LIGHTSENSOR */
//}}}
//AIRQUALITYSENSOR {{{
#ifdef HAVE_AIRQUALITYSENSOR
	case BCSetEnvironmentalData_c:
		msg_debug(SC("set environmental data: %u\n"),
				t->data.setenvironment.sensor);
		set_environmental_data(t->data.setenvironment.sensor,
				t->data.setenvironment.humid,
				t->data.setenvironment.temp);
		t->task_type = BCStable0_c;
		*stack++ = MTStable_c;

		if (current_task->status != MTUnevaluated_c)
			current_task->status = MTPurged_c;

		break;
	case BCTVOC_c:
		msg_debug(SC("tvoc: %u\n"), t->data.airqualitysensor);
		*stack++ = MTUnstable_c;
		*stack++ = get_tvoc(t->data.airqualitysensor);
		break;
	case BCCO2_c:
		msg_debug(SC("co2: %u\n"), t->data.airqualitysensor);
		*stack++ = MTUnstable_c;
		*stack++ = get_co2(t->data.airqualitysensor);
		break;
#endif /* HAVE_AIRQUALITYSENSOR */
//}}}
//GESTURESENSOR {{{
#ifdef HAVE_GESTURESENSOR
	case BCGesture_c:
		msg_debug(SC("gesture: %u\n"), t->data.gesturesensor);
		*stack++ = MTUnstable_c;
		*stack++ = get_gesture(t->data.gesturesensor);
		break;
#endif /* HAVE_GESTURESENSOR */
//}}}
//LEDMatrix {{{
#ifdef HAVE_LEDMATRIX
	case BCLEDMatrixDisplay_c:
		msg_debug(SC("ledmatrixdisplay: %u\n"),
			t->data.ledmatrixdisplay);
		ledmatrix_display(t->data.ledmatrixdisplay);
		*stack++ = MTStable_c;
		break;
	case BCLEDMatrixIntensity_c:
		msg_debug(SC("ledmatrixintensity: %u\n"),
			t->data.ledmatrixintensity.intensity);
		ledmatrix_intensity(t->data.ledmatrixintensity.id,
			t->data.ledmatrixintensity.intensity);
		*stack++ = MTStable_c;
		break;
	case BCLEDMatrixDot_c:
		msg_debug(SC("ledmatrixdot: %u %u %u\n"),
			t->data.ledmatrixdot.x, t->data.ledmatrixdot.y,
			t->data.ledmatrixdot.s);
		ledmatrix_dot(t->data.ledmatrixdot.id, t->data.ledmatrixdot.x,
			t->data.ledmatrixdot.y, t->data.ledmatrixdot.s);
		*stack++ = MTStable_c;
		break;
	case BCLEDMatrixClear_c:
		msg_debug(SC("ledmatrixclear: %u\n"), t->data.ledmatrixclear);
		ledmatrix_clear(t->data.ledmatrixclear);
		*stack++ = MTStable_c;
		break;
#endif /* HAVE_LEDMATRIX */
//}}}
//}}}
	}
	return stack;
	(void)tfloat;
}
