#include "kernel.h"
#include "ioport.h"
#include "intmgr.h"

#include "screen.h"

IntMgr InterruptManager;

void IntMgr::init(void) {
    for (int i = 0; i < IRQ_NUM; i++) {
        handler[i] = 0;
    }

    IoPortLib::out8(IoPortLib::PIC0_ICW1, 0x11);
    IoPortLib::out8(IoPortLib::PIC0_ICW2, 0x20);
    IoPortLib::out8(IoPortLib::PIC0_ICW3, 0x04);
    IoPortLib::out8(IoPortLib::PIC0_ICW4, 0x01);

    IoPortLib::out8(IoPortLib::PIC1_ICW1, 0x11);
    IoPortLib::out8(IoPortLib::PIC1_ICW2, 0x28);
    IoPortLib::out8(IoPortLib::PIC1_ICW3, 0x02);
    IoPortLib::out8(IoPortLib::PIC1_ICW4, 0x01);

    setMask(ALL_MASK);
    clearMask(SLAVE_MASK);

    enable();
}

void IntMgr::setMask(uint16 mask) {
    const uint8 mask0 = uint8(mask & 0xFF);
    const uint8 mask1 = uint8((mask >> 8) & 0xFF);

    IoPortLib::out8(IoPortLib::PIC0_IMR, 
                    IoPortLib::in8(IoPortLib::PIC0_IMR) | mask0);
    IoPortLib::out8(IoPortLib::PIC1_IMR, 
                    IoPortLib::in8(IoPortLib::PIC1_IMR) | mask1);
}

void IntMgr::clearMask(uint16 mask) {
    const uint8 mask0 = uint8(mask & 0xFF);
    const uint8 mask1 = uint8((mask >> 8) & 0xFF);

    IoPortLib::out8(IoPortLib::PIC0_IMR, 
                    IoPortLib::in8(IoPortLib::PIC0_IMR) & ~(mask0));
    IoPortLib::out8(IoPortLib::PIC1_IMR, 
                    IoPortLib::in8(IoPortLib::PIC1_IMR) & ~(mask1));
}

void IntMgr::connect(IrqNum irq, InterruptHandler& handler) {
    this->handler[irq] = &handler;
}

void IntMgr::dispatchHandler(IrqNum irq) {
    InterruptHandler* functor = handler[irq];
    if (functor != 0) {
        (*functor)(irq);
    } else {
        Kernel::panic("[IntMgr] Null Pointer Exception\n");
    }
}
