#include <sysinit.h>

#include "basic/basic.h"
#include "lcd/print.h"

QUEUE the_queue;
#ifdef __arm__
volatile uint32_t _timectr=0;
#else
extern uint32_t simTimeCounter();
#define _timectr (simTimeCounter())
#endif

/**************************************************************************/


uint8_t work_queue_minimal(void){
	int start;

	if (the_queue.qstart == the_queue.qend){
		return 0;
	};

	start=the_queue.qstart;
	start=(start+1)%MAXQENTRIES;
    if(the_queue.queue[start].type == QT_NORMAL){
        void (*elem)(void);
        elem=the_queue.queue[start].u.callback;
        the_queue.qstart=start;
        elem();
        return 0;
    }else if(the_queue.queue[start].type == QT_PLUS){
        uint8_t (*elem)(uint8_t);
        uint8_t state=the_queue.queue[start].state;
        elem=the_queue.queue[start].u.callbackplus;
        state=elem(state);
        if(state==QS_END){
            the_queue.qstart=start;
            return 0;
        }else{
            the_queue.queue[start].state=state;
            return 1;
        };
    };
    /* NOTREACHED */
    return 0;
};

void work_queue(void){

	if (the_queue.qstart == the_queue.qend){
        WFI;
        return;
	};

    while(work_queue_minimal());
};


uint8_t delayms_queue_plus(uint32_t ms, uint8_t final){
    int ret=0;
    int end=_timectr+ms/SYSTICKSPEED;
    do {
        if (the_queue.qstart == the_queue.qend){
            WFI;
        }else{
            ret=work_queue_minimal();
        };
    } while (end >_timectr);
    if(ret && final){
        while(work_queue_minimal());
    };
    return ret;
};

void delayms_queue(uint32_t ms){
	int end=_timectr+ms/SYSTICKSPEED;
	do {
		if (the_queue.qstart == the_queue.qend){
            WFI;
		}else{
			work_queue();
		};
	} while (end >_timectr);
};

void delayms_power(uint32_t ms){
    ms/=SYSTICKSPEED;
    ms+=_timectr;
	do {
        WFI;
	} while (ms >_timectr);
};

int push_queue(void (*new)(void)){
	int end;

	end=the_queue.qend;
	end=(end+1)%MAXQENTRIES;

	if(end == the_queue.qstart) // Queue full
		return -1;

	the_queue.queue[end].u.callback=new;
	the_queue.queue[end].type=QT_NORMAL;
	the_queue.qend=end;

	return 0;
};

int push_queue_plus(uint8_t (*new)(uint8_t)){
	int end;

	end=the_queue.qend;
	end=(end+1)%MAXQENTRIES;

	if(end == the_queue.qstart) // Queue full
		return -1;

	the_queue.queue[end].u.callbackplus=new;
	the_queue.queue[end].type=QT_PLUS;
	the_queue.queue[end].state=QS_START;
	the_queue.qend=end;

	return 0;
};
