#include <stddef.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdbool.h>
#include "../../Terminal/Terminal.h"
#include "../../Scheduler/Scheduler.h"

unsigned char kbdmap[] = {
	0x1B, 0x1B, 0x1B, 0x1B,	/*      esc     (0x01)  */
	'1', '!', '1', '1',
	'2', '@', '2', '2',
	'3', '#', '3', '3',
	'4', '$', '4', '4',
	'5', '%', '5', '5',
	'6', '^', '6', '6',
	'7', '&', '7', '7',
	'8', '*', '8', '8',
	'9', '(', '9', '9',
	'0', ')', '0', '0',
	'-', '_', '-', '-',
	'=', '+', '=', '=',
	0x08, 0x08, 0x7F, 0x08,	/*      backspace       */
	0x09, 0x09, 0x09, 0x09,	/*      tab     */
	'q', 'Q', 'q', 'q',
	'w', 'W', 'w', 'w',
	'e', 'E', 'e', 'e',
	'r', 'R', 'r', 'r',
	't', 'T', 't', 't',
	'y', 'Y', 'y', 'y',
	'u', 'U', 'u', 'u',
	'i', 'I', 'i', 'i',
	'o', 'O', 'o', 'o',
	'p', 'P', 'p', 'p',
	'[', '{', '[', '[',
	']', '}', ']', ']',
	0x0A, 0x0A, 0x0A, 0x0A,	/*      enter   */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      ctrl    */
	'a', 'A', 'a', 'a',
	's', 'S', 's', 's',
	'd', 'D', 'd', 'd',
	'f', 'F', 'f', 'f',
	'g', 'G', 'g', 'g',
	'h', 'H', 'h', 'h',
	'j', 'J', 'j', 'j',
	'k', 'K', 'k', 'k',
	'l', 'L', 'l', 'l',
	';', ':', ';', ';',
	0x27, 0x22, 0x27, 0x27,	/*      '"      */
	'`', '~', '`', '`',	/*      `~      */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      Lshift  (0x2a)  */
	'\\', '|', '\\', '\\',
	'z', 'Z', 'z', 'z',
	'x', 'X', 'x', 'x',
	'c', 'C', 'c', 'c',
	'v', 'V', 'v', 'v',
	'b', 'B', 'b', 'b',
	'n', 'N', 'n', 'n',
	'm', 'M', 'm', 'm',
	0x2C, 0x3C, 0x2C, 0x2C,	/*      ,<      */
	0x2E, 0x3E, 0x2E, 0x2E,	/*      .>      */
	0x2F, 0x3F, 0x2F, 0x2F,	/*      /?      */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      Rshift  (0x36)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x37)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x38)  */
	' ', ' ', ' ', ' ',	/*      space   */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x3a)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x3b)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x3c)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x3d)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x3e)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x3f)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x40)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x41)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x42)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x43)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x44)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x45)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x46)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x47)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x48)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x49)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x4a)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x4b)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x4c)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x4d)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x4e)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x4f)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x50)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x51)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x52)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x53)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x54)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x55)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x56)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x57)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x58)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x59)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x5a)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x5b)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x5c)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x5d)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x5e)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x5f)  */
	0xFF, 0xFF, 0xFF, 0xFF,	/*      (0x60)  */
	0xFF, 0xFF, 0xFF, 0xFF	/*      (0x61)  */
};

void IsrDefaultInt(void)
{
	TerminalPrint("Interrupt\n");
}

void IsrGpExc(void)
{
	TerminalPrint("GP fault\n");
	while (1);
}

void IsrExcFp(void)
{
	uint32_t faulting_addr;
	uint32_t eip;

 	asm(" 	movl 60(%%ebp), %%eax; \
    		mov %%eax, %0;         \
		mov %%cr2, %%eax;      \
		mov %%eax, %1": "=m"(eip), "=m"(faulting_addr): );

	TerminalPrint("Fault");
	TerminalPrint(eip);
	TerminalPrint(faulting_addr);

	asm("hlt");
}

void IsrClockInt(void)
{
	static int tic = 0;
	static int sec = 0;
	tic++;
	if (tic % 255 == 0) {
		sec++;
		tic = 0;
		TerminalPutc('.');
		if(sec == 15){
			TerminalPrint("$");
			return;
		}
	}
	Schedule();
}

void IsrKeyboardInt(void)
{
	unsigned char i;
        static int lshift_enable;
        static int rshift_enable;
        static int alt_enable;
        static int ctrl_enable;

        do {
                i = inb(0x64);
        } while ((i & 0x01) == 0);

        i = inb(0x60);
        i--;

        //// putcar('\n'); dump(&i, 1); putcar(' ');

        if (i < 0x80) {         /* touche enfoncée */
                switch (i) {
                case 0x29:
                        lshift_enable = 1;
                        break;
                case 0x35:
                        rshift_enable = 1;
                        break;
                case 0x1C:
                        ctrl_enable = 1;
                        break;
                case 0x37:
                        alt_enable = 1;
                        break;
                default:
                        TerminalPutc(kbdmap
                               [i * 4 + (lshift_enable || rshift_enable)]);
                }
        } else {                /* touche relâchée */
                i -= 0x80;
                switch (i) {
                case 0x29:
                        lshift_enable = 0;
                        break;
                case 0x35:
                        rshift_enable = 0;
                        break;
                case 0x1C:
                        ctrl_enable = 0;
                        break;
                case 0x37:
                        alt_enable = 0;
                        break;
                }
        }
	// TerminalPrint("Keyboard");
}
