#ifndef __KERNEL_H__
#define __KERNEL_H__

#include "types.h"
#include "intmgr.h"
#include "screen.h"
#include "task.h"

extern Task IdleTask;

class MsgQueue {
public:
    MsgQueue(void) {top = next = num = 0;}
    void  enqueue(uint8 msg) {
        IntMgr::disable();
        data[next] = msg;
        if (++next >= NUM) next = 0;
        ++num;
        IntMgr::enable();
    }
    uint8 dequeue(void) {
        IntMgr::disable();
        uint8 msg = data[top];
        if (++top >= NUM) top = 0;
        --num;
        IntMgr::enable();
        return msg;
    }
    bool isEmpty(void) {return num == 0;}

private:
    enum {NUM=128};
    uint8  data[NUM];
    uint32 top;
    uint32 next;
    uint32 num;
};

class Kernel
{
public:
    static const char version[];

    static void initGlobalObjects(void);
    static void  sendMessage(uint8 msg) {
        message.enqueue(msg);
        SystemScheduler.wakeup(IdleTask);
    }
    static uint8 waitForMsg(void) {
        while (true) {
            if (message.isEmpty()) {
                SystemScheduler.sleep(IdleTask);
            } else {
                return message.dequeue();
            }
        }
    }

    static void panic(const char* format, ...) {
        Console.printf("[Kernel Panic] ");
        Console.printf(format);
        while (true) {
            InterruptManager.disable();
            asm volatile("hlt");
        }
    }

private:
    static MsgQueue message;
};

extern void* stack;

#endif /* __KERNEL_H__ */
