#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/times.h>
#include <sys/time.h>

#define	CPU_FREQ_HZ	100000000
#include "libsys.h"
#include "irq.h"
#include "mips_gfx.h"
#include "mips_ps2.h"

char buffer[16384];
char * volatile pPtr_r;
char * volatile pPtr_w;
static volatile INT32 mouse_x;
static volatile INT32 mouse_y;
static box_t box;
static gfx_t gfx;
static volatile int _g_posx, _g_posy;
static volatile g_btn_l, g_btn_r;
static volatile UINT32 g_color;

// -------------------------------------------------------------
void handler0(void)
{
	printf("Interrupt 0\n");
	interrupt_clr(0);
}

void handler1(void)
{
	printf("Interrupt 1\n");
	interrupt_clr(1);
}

void handler2(void)
{
	printf("Interrupt 2\n");
}

void handler3(void)
{
	volatile UINT32 *pUART0_stat = (UINT32*)SYS_UART0_STAT;
	volatile UINT32 *pUART0_data = (UINT32*)SYS_UART0_DATA;
	volatile UINT32 *pUART1_stat = (UINT32*)SYS_UART1_STAT;
	volatile UINT32 *pUART1_data = (UINT32*)SYS_UART1_DATA;

	while(0x200 & *pUART0_stat)
	{
//		sputs("w: "); print_word((int)pPtr_w); sputs("\n");
		if (pPtr_w == &buffer[16383])
			pPtr_w = buffer;
		*(pPtr_w++) = *pUART0_data;
	}

	while(0x200 & *pUART1_stat)
	{
//		sputs("w: "); print_word((int)pPtr_w); sputs("\n");
		if (pPtr_w == &buffer[16383])
			pPtr_w = buffer;
		*(pPtr_w++) = *pUART1_data;
	}

}

void handler4(void)
{
	printf("Interrupt 4\n");
}

void handler5(void)
{
	UINT32 volatile *pVGA_ctrl = (UINT32*)SYS_VGA_CTRL;

	// Ack
	*pVGA_ctrl |= SYS_VGA_BIT_BUFCHG_FLAG;

}

void handler6(void)
{
	int p, i;
	ps2_if_t *pIF;
	UINT8 mouse_rsp[3];
	UINT32 timeout_count, key;

	INT32 dx, dy;

	for (p=0; p < PS2_get_num_if(); p++)
	{
		pIF = PS2_get_if(p);
		if (SYS_PS2_BIT_RX_ERR_FLAG & *pIF->pCTRL)
			fprintf(stderr, "PS2[%d]: Status = 0x%08X\n", p, *pIF->pCTRL);

		if (pIF->type == ps2_type_keyb)
		{
			while(SYS_PS2_BIT_RX_IRQ & *pIF->pCTRL)
			{
				key = *pIF->pDATA;
				printf("Keyboard scan code = 0x%02X\n", key);
			}
		}
		if (pIF->type == ps2_type_mouse)
		{
			if(!(SYS_PS2_BIT_RX_IRQ & *pIF->pCTRL))
				continue;

			for (i=0; i < 3; i++)
			{
				timeout_count = 100;
				while(!(SYS_PS2_BIT_RX_IRQ & *pIF->pCTRL))
				{
					timeout_count--;
					if (!timeout_count)
					{
						break;
					}
					sleep(1);
				}
				if (!timeout_count)
				{
					break;
				}
				mouse_rsp[i] = (UINT8)*pIF->pDATA;
			}
			if (!timeout_count)
			{
				continue;
			}
			dx = mouse_rsp[1];
			if (mouse_rsp[0] &  0x10)
				dx |= 0xFFFFFF00;
			dy = mouse_rsp[2];
			if (mouse_rsp[0] &  0x20)
				dy |= 0xFFFFFF00;

//			printf("dx = %5d, dy = %5d\n", dx, dy);

			mouse_x += dx;
			mouse_y -= dy;
			g_btn_l = 0;
			if (mouse_rsp[0] & 0x01)
				g_btn_l = 1;

			if (mouse_rsp[0] & 0x02)
			{
				if (g_btn_r == 0)
				{
					g_color  = (UINT32)rand();
				}
				g_btn_r = 1;
			}
			else
				g_btn_r = 0;


			if (mouse_x < 0)
				mouse_x = 0;
			if (mouse_y < 0)
				mouse_y = 0;
			if (mouse_x > (gfx.w-1))
				mouse_x = gfx.w-1;
			if (mouse_y >= (gfx.h-1))
				mouse_y = gfx.h-1;

//			Screen_csr_set_x(mouse_x);
//			Screen_csr_set_y(mouse_y);

//			printf("x = %5d, y = %5d\n", mouse_x, mouse_y);

		}
	}
}

void handler7(void)
{
	printf("Interrupt 7\n");
}

int main(void)
{

	int i;
	volatile UINT32 *pUART0_stat = (UINT32*)SYS_UART0_STAT;
	volatile UINT32 *pUART1_stat = (UINT32*)SYS_UART1_STAT;
	volatile UINT32 *pUART0_baud = (UINT32*)SYS_UART0_BAUD;
	volatile UINT32 *pUART1_baud = (UINT32*)SYS_UART1_BAUD;
	UINT32 volatile *pVGA_ctrl = (UINT32*)SYS_VGA_CTRL;
	UINT32 volatile *pVGA_moffs_0 = (UINT32*)SYS_VGA_FB_FRONT;
	UINT32 volatile *pVGA_moffs_1 = (UINT32*)SYS_VGA_FB_BACK;
	UINT32 volatile *pVGA_cgcol = (UINT32*)SYS_VGA_CGCOL;
	UINT32 volatile *pFlashPicture = (UINT32*)(SYS_FLASH_MEM + 0x00600000);
	UINT32 framecount;
	UINT32 start, end;
	char string[65];

	interrupt_register(0, (void*)handler0);
	interrupt_register(1, (void*)handler1);
//	interrupt_register(2, (void*)handler2);
	interrupt_register(3, (void*)handler3);
//	interrupt_register(4, (void*)handler4);
//	interrupt_register(5, (void*)handler5);
	interrupt_register(6, (void*)handler6);
	interrupt_register(7, (void*)handler7);

	srand(clock());
	UART1_setbaud(460800);
	printf("Hello\n");
	memset(buffer, 0, sizeof(buffer));

	*pVGA_cgcol = 0x00FFFFFF;
	_g_posx = _g_posy = 0;
	g_color = 0xFFFFFFFF;
	GFX_init(&gfx);

	GFX_set_background(&gfx, pFlashPicture, 800, 600, 1, 1);
	box_create(&box, 256, 256);
	GFX_box_draw(&gfx, &box, _g_posx, _g_posy, g_color);
	GFX_show(&gfx);
	printf("VGA status = %08X\n", *pVGA_ctrl);

	pPtr_r = buffer;
	pPtr_w = buffer;

	printf("UART0 Status = 0x%8.8X\n", *pUART0_stat);
	printf("UART0 Baud   = 0x%8.8X\n", *pUART0_baud);
	printf("UART1 Status = 0x%8.8X\n", *pUART1_stat);
	printf("UART1 Baud   = 0x%8.8X\n", *pUART1_baud);

	// UART: enable RX interrupt
	*pUART0_stat |= (1 << 6);
	*pUART1_stat |= (1 << 6);
	printf("UART0 Status = 0x%8.8X\n", *pUART0_stat);
	printf("UART1 Status = 0x%8.8X\n", *pUART1_stat);

	PS2_init(0);
	PS2_init(1);

	sputs("r: "); print_word((int)pPtr_r); sputs("\n");
	sputs("w: "); print_word((int)pPtr_w); sputs("\n");

	// Print Status register
	sputs("Status  : ");
	print_word(CP0_SR_read());
	sputs("\n");
	sputs("\n");

	interrupt_disable(6);
	printf("Bitte gebe ein: ");
	scanf("%s", string);
	printf("Du schriebst: %s\n", string);

	// Flush buffer
	PS2_flush(0);
	PS2_flush(1);

	printf("Start:\n");

	interrupt_enable(0);
	interrupt_enable(1);
//	interrupt_enable(2);
	interrupt_enable(3);
//	interrupt_enable(4);
//	interrupt_enable(5);
	interrupt_enable(6);
	interrupt_enable(7);

	interrupt_set(0);
	interrupt_set(1);
	interrupt_set(2);
	interrupt_set(3);
	interrupt_set(4);
	interrupt_set(5);
	interrupt_set(6);
	interrupt_set(7);

//	while(1)
//	{
//		printf("PS2-Status : 0x%08X\n", *(ps2_if[0].pCTRL));
//		printf("PS2-Data   : 0x%08X\n", *(ps2_if[0].pDATA));
//		sleep(1000);
//	}

	interrupt_enable(6);
	framecount = Screen_get_fps();
	start = clock();

	while(1)
	{
		if (!framecount)
		{
			end = clock();
			framecount = Screen_get_fps();
			printf("%f FPS\n", (float)framecount/((float)(end-start)/CLOCKS_PER_SEC));
			start = clock();
		}

		GFX_frame(&gfx, GFX_FRAME_SYNC);
		framecount--;

		while ((_g_posx != (UINT32)mouse_x) || (_g_posy != (UINT32)mouse_y) || g_btn_r || g_btn_l)
		{

			GFX_restore(&gfx, &box, _g_posx, _g_posy);

			_g_posx = (UINT32)mouse_x;
			_g_posy = (UINT32)mouse_y;

			if (g_btn_l && !g_btn_r)
			{
				GFX_box_draw_bg(&gfx, &box, _g_posx, _g_posy, g_color);
			}

			if (g_btn_l && g_btn_r)
			{
				GFX_set_background(&gfx, pFlashPicture, 800, 600, 1, 1);
			}

			GFX_box_draw(&gfx, &box, _g_posx, _g_posy, g_color);
			break;
		}
		GFX_show(&gfx);

		if(pPtr_w != pPtr_r)
		{
//			sputs("r: "); print_word((int)pPtr_r); sputs("\n");
			if (pPtr_r == &buffer[16383])
				pPtr_r = buffer;
			writechar(0, *(pPtr_r++));
		}
	}
	return 0;
}
