#ifndef __INTMGR_H__
#define __INTMGR_H__

#include "ioport.h"
#include "types.h"

class InterruptHandler;

class IntMgr 
{
public:
    enum IrqNum {
        TIMER_IRQ    = 0,
        KEYBOARD_IRQ = 1,
        SLAVE_IRQ    = 2,
        COM2_IRQ     = 3,
        COM1_IRQ     = 4,
        LPT2_IRQ     = 5,
        FDD_IRQ      = 6,
        LPT1_IRQ     = 7,
        RTCLK_IRQ    = 8,
        MOUSE_IRQ    = 12,
        FPU_IRQ      = 13,
        IDE_P_IRQ    = 14,
        IDE_S_IRQ    = 15,
        IRQ_NUM      = 16
    };
    enum IntMask {
        TIMER_MASK    = BIT(TIMER_IRQ),
        KEYBOARD_MASK = BIT(KEYBOARD_IRQ),
        SLAVE_MASK    = BIT(SLAVE_IRQ),
        COM2_MASK     = BIT(COM2_IRQ),
        COM1_MASK     = BIT(COM1_IRQ),
        LPT2_MASK     = BIT(LPT2_IRQ),
        FDD_MASK      = BIT(FDD_IRQ),
        LPT1_MASK     = BIT(LPT1_IRQ),
        RTCLK_MASK    = BIT(RTCLK_IRQ),
        MOUSE_MASK    = BIT(MOUSE_IRQ),
        FPU_MASK      = BIT(FPU_IRQ),
        IDE_P_MASK    = BIT(IDE_P_IRQ),
        IDE_S_MASK    = BIT(IDE_S_IRQ),
        ALL_MASK      = 0xFFFF 
    };
    void    init(void);
    static void    setMask(uint16 mask);
    static void    clearMask(uint16 mask);
    static void    disable(void) {asm("cli");}
    static void    enable(void)  {asm("sti");}
    static void    setEoi(IrqNum n) {
        const IoPortLib::IoPort port = (n < 8) ? 
            IoPortLib::PIC0_OCW2 : IoPortLib::PIC1_OCW2;
        int num = (n < 8) ? int(n) : int(n) - 8;
        IoPortLib::out8(port, 0x60 + num);
    }

    void connect(IrqNum irq, InterruptHandler& handler);
    void dispatchHandler(IrqNum irq);

private:
    InterruptHandler* handler[IRQ_NUM];    
};

class InterruptHandler
{
public:
    virtual void operator()(uint32 intNum) {}
};

extern IntMgr InterruptManager;

#endif /* __INTMGR_H__ */
