/* OSの核 */

#include "bootpack.h"
#include <stdio.h>

struct fifo fifo;		/* システム用 */
struct mdec mdec;		/* マウス */
struct memorys *mem;	/* メモリ管理用 */
unsigned int memtotal;	/* 合計メモリサイズ */
int *fat;				/* FATテーブル */
unsigned char *nihongo;	/* 日本語フォント */
struct sheet *sht_back;

void HariMain(void)
{
	struct bootinfo *binfo = (struct bootinfo *) BOOTINFO_ADDR;
	int fbuf[32];
	static char ktable[0x80] = {
		0,   0,   '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0x08, 0,
		'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0x0a, 0, 'A', 'S',
		'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0,   0,   ']', 'Z', 'X', 'C', 'V',
		'B', 'N', 'M', ',', '.', '/', 0,   '*', 0,   ' ', 0,   0,   0,   0,   0,   0,
		0,   0,   0,   0,   0,   0,   0,   '7', '8', '9', '-', '4', '5', '6', '+', '1',
		'2', '3', '0', '.', 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
		0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
		0,   0,   0,   0x5c, 0,  0,   0,   0,   0,   0,   0,   0,   0,   0x5c, 0,  0
	};
	static char ktable1[0x80] = {
		0,   0,   '!', 0x22, '#', '$', '%', '&', 0x27, '(', ')', '~', '=', '~', 0x08, 0,
		'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '`', '{', 0x0a, 0, 'A', 'S',
		'D', 'F', 'G', 'H', 'J', 'K', 'L', '+', '*', 0,   0,   '}', 'Z', 'X', 'C', 'V',
		'B', 'N', 'M', '<', '>', '?', 0,   '*', 0,   ' ', 0,   0,   0,   0,   0,   0,
		0,   0,   0,   0,   0,   0,   0,   '7', '8', '9', '-', '4', '5', '6', '+', '1',
		'2', '3', '0', '.', 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
		0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
		0,   0,   0,   '_', 0,   0,   0,   0,   0,   0,   0,   0,   0,   '|', 0,   0
	};
	int kshf = 0, kleds = (binfo->leds >> 4) & 7, kcwait = -1;
	struct task *task_sys, *task_fdc, *task_clock;
	struct sheet *sht_tbar, *sht_mouse;
	unsigned char *buf_back, *buf_tbar, *buf_mouse;
	struct sheet *sht = 0, *sht2, *snow = 0;
	int mmx = -1, mmx2 = 0, mmy = -1, x, y;
	int nmx = -1, nmy = 0, nwx = 0x7fffffff, nwy = 0;
	struct file *file;
	int i, j;
	char c;

	/* ハードウェアの初期化 */
	gdtidt_init();
	pic_init();
	pit_init();

	/* メモリの初期化 */
	mem = (struct memorys *) MEMORY_ADDR;
	memtotal = memory_test(0x00400000, 0xbfffffff);
	memory_init(mem);
	memory_free(mem, 0x00001000, 0x0009e000);
	memory_free(mem, 0x00400000, memtotal - 0x00400000);

	/* タイマの初期化 */
	timers_init();

	/* FIFOの初期化 */
	fifo_init(&fifo, 0, fbuf, 32);

	/* タスクの初期化 */
	task_sys = task_init();
	fifo.task = task_sys;

	/* FDC */
	task_fdc = task_alloc();
	fdc_tinit(task_fdc);

	/* I/Oリストの初期化 */
	io_init();

	/* 割り込み許可 */
	outb(PIC0_IMR, 0xb8);	/* 10111000 PITとキーボードとPIC1とFDCを許可 */
	outb(PIC1_IMR, 0xef);	/* 11101111 マウスを許可 */
	sti();

	/* 画面の初期化 */
	palette_init();
	sheets_init(binfo->vram, binfo->scrnx, binfo->scrny);

	/* デスクトップ */
	sht_back = sheet_alloc();
	buf_back = (unsigned char *) memory_alloc(mem, binfo->scrnx * binfo->scrny);
	sheet_set(sht_back, buf_back, binfo->scrnx, binfo->scrny, -1);
	graphic_box(sht_back, COLOR_008484, 0, 0, binfo->scrnx - 1, binfo->scrny - 1);	/* 背景 */

	/* マウスカーソル */
	sht_mouse = sheet_alloc();
	buf_mouse = (unsigned char *) memory_alloc(mem, 10 * 16);
	sheet_set(sht_mouse, buf_mouse, 10, 16, 99);
	mdec.mx = (binfo->scrnx - 10) / 2;	/* 位置は画面中央 */
	mdec.my = (binfo->scrny - 44) / 2;
	mcursor_init(buf_mouse, 99);

	/* 画面の表示 */
	sheet_slide(sht_back, 0, 0);
	sheet_slide(sht_mouse, mdec.mx, mdec.my);
	sheet_updown(sht_back, 0);
	sheet_updown(sht_mouse, 1);

	/* FATテーブルの初期化 */
	fat = (int *) memory_alloc(mem, 11520);
	fat_read(fat, (unsigned char *) FAT_ADDR);

	/* 壁紙を適応する */
	screen_init(sht_back);
	sheet_refresh(sht_back, 0, 0, binfo->scrnx, binfo->scrny);

	/* 日本語フォントの読み込み */
	file = file_search("nihongo.fnt");
	nihongo = 0;
	if(file != 0) {
		i = file->size;
		nihongo = file_read(file->cno, &i);
	}
	if(nihongo == 0) {	/* フォントがないため塗りつぶす */
		nihongo = (unsigned char *) memory_alloc(mem, 16 * 256 + 32 * 94 * 47);
		for(i = 0; i < 16 * 256 + 32 * 94 * 47; i++) {
			nihongo[i] = 0xff;
		}
	}

	/* タスクバー */
	sht_tbar = sheet_alloc();
	buf_tbar = (unsigned char *) memory_alloc(mem, 190 * 22);
	sheet_set(sht_tbar, buf_tbar, 190, 22, -1);
	tbar_init(sht_tbar);

	/* 時計 */
	task_clock = task_alloc();
	clock_tinit(task_clock, sht_tbar);

	sheet_slide(sht_tbar, 0, 0);
	sheet_updown(sht_tbar, 1);

	/* キーボードとマウスの有効化 */
	keyboard_init();
	mouse_enable();

	for(;;) {
		cli();
		if(fifo_stat(&fifo) == 0) {	/* 未描画を済ます */
			if(nmx >= 0) {
				sti();
				sheet_slide(sht_mouse, nmx, nmy);
				nmx = -1;
			} else if(nwx != 0x7fffffff) {
				sti();
				sheet_slide(sht, nwx, nwy);
				nwx = 0x7fffffff;
			} else {
				task_sleep(task_sys);
				sti();
			}
		} else {
			i = fifo_get(&fifo);
			sti();

			if(i == 1 || (snow->flag == SHEET_NONE && snow != 0)) {	/* 入力ウィンドウの切り替え */
				if(shts->top <= 2) {	/* 背景、タスクバー、マウスカーソルのみ */
					snow = 0;
				} else {
					if(snow != 0) {
						window_passive(snow);
					}
					snow = shts->s[shts->top - 2];
					window_active(snow);
				}
			}
			if(256 <= i && i <= 511) {	/* KCへデータを送る */
				kcwait = i - 256;
				kc_rwait();
				outb(PORT_KEYDATA, kcwait);
			} else if(512 <= i && i <= 767) {	/* キーコード */
				if(i - 512 < 0x80) {	/* 文字コードに変換 */
					if(kshf != 0) {
						c = ktable1[i - 512];
					} else {
						c = ktable[i - 512];
					}
				} else {
					c = 0;
				}
				if('A' <= c && c <= 'Z') {	/* アルファベットを小文字へ */
					if(((kleds & 4) == 0 && kshf == 0) || ((kleds & 4) && kshf != 0)) {
						c += 0x20;
					}
				}
				if(c != 0 && snow != 0) {	/* バックスペース、Enter、通常文字 */
					fifo_put(&snow->task->fifo, 256 + (int) c);
				}
				if(i == 512 + 0x2a) {	/* 左シフトON */
					kshf |= 1;
				} else if(i == 512 + 0x36) {	/* 右シフトON */
					kshf |= 2;
				} else if(i == 512 + 0x3a) {	/* CapsLock */
					kleds ^= 4;
					fifo_put(&fifo, 256 + KEYCMD_LED);
					fifo_put(&fifo, 256 + kleds);
				} else if(i == 512 + 0x3b) {	/* F1キー */
					/* 新規コンソールを入力ウィンドウにする */
					if(snow != 0) {
						window_passive(snow);
						i = snow->x + 28;
						j = snow->y + 28;
						if(i > shts->xsize - 28) {
							i = shts->xsize - 28;
						}
						if(j > shts->ysize - 28) {
							j = shts->ysize - 28;
						}
					} else {
						i = 28;
						j = 28;
					}
					snow = cons_open();
					sheet_slide(snow, i, j);
					sheet_updown(snow, shts->top - 1);
					window_active(snow);
				} else if(i == 512 + 0x3e) {	/* F4キー */
					cli();
					snow->task->tss.eax = (int) &(snow->task->tss.esp0);
					snow->task->tss.eip = (int) app_end;
					sti();
					task_run(snow->task, -1, 0);
				} else if(i == 512 + 0x45) {	/* NUMLock */
					kleds ^= 2;
					fifo_put(&fifo, 256 + KEYCMD_LED);
					fifo_put(&fifo, 256 + kleds);
				} else if(i == 512 + 0x46) {	/* ScrollLock */
					kleds ^= 1;
					fifo_put(&fifo, 256 + KEYCMD_LED);
					fifo_put(&fifo, 256 + kleds);
				} else if(i == 512 + 0xaa) {	/* 左シフトOFF */
					kshf &= ~1;
				} else if(i == 512 + 0xb6) {	/* 右シフトOFF */
					kshf &= ~2;
				} else if(i == 512 + 0xfa) {	/* KCがデータを受け取った */
					kcwait = -1;
				} else if(i == 512 + 0xfe) {	/* KCがデータを受け取れなかった */
					kc_rwait();
					outb(PORT_KEYDATA, kcwait);
				}
			} else if(768 <= i && i <= 1023) {	/* マウスデータ */
				if(mouse_decode(i - 768) != 0) {	/* マウスカーソルの移動 */
					mdec.mx += mdec.x;
					mdec.my += mdec.y;
					if(mdec.mx < 0) { mdec.mx = 0; }
					if(mdec.my < 0) { mdec.my = 0; }
					if(mdec.mx > binfo->scrnx - 1) { mdec.mx = binfo->scrnx - 1; }
					if(mmx >= 0) {
						if(mdec.my > binfo->scrny - 28) { mdec.my = binfo->scrny - 28; }
					} else {
						if(mdec.my > binfo->scrny - 1) { mdec.my = binfo->scrny - 1; }
					}
					sheet_slide(sht_mouse, mdec.mx, mdec.my);
					if((mdec.btn & 0x01) != 0) {	/* 左ボタンを押している */
						if(mmx < 0) {	/* 通常モード（ウィンドウを上から探して手前に持ってくる） */
							for(j = shts->top - 2; j > 0; j--) {
								sht = shts->s[j];
								x = mdec.mx - sht->x;
								y = mdec.my - sht->y;
								if(0 <= x && x < sht->sx && 0 <= y && y < sht->sy) {
									if(sht->buf[y * sht->sx + x] != sht->cinv) {
										sheet_updown(sht, shts->top - 2);
										window_passive(snow);
										snow = sht;
										window_active(snow);
										if(0 <= x && x < sht->sx && 0 <= y && y < 20) {	/* ウィンドウ移動モードへ */
											mmx = mdec.mx;
											mmy = mdec.my;
											mmx2 = sht->x;
											nwy = sht->y;
										}
										if(6 <= x && x < 14 && 6 <= y && y < 14) {	/* 「×」ボタンをクリック */
											if((sht->flag & SHEET_FROMAPP) != 0) {	/* アプリ用のウィンドウなら終了 */
												cli();
												snow->task->tss.eax = (int) &(snow->task->tss.esp0);
												snow->task->tss.eip = (int) app_end;
												sti();
												task_run(snow->task, -1, 0);
											} else {	/* コンソール */
												cli();
												fifo_put(&snow->task->fifo, 4);
												sheet_updown(snow, -1);
												window_passive(snow);
												snow = shts->s[shts->top - 2];
												window_active(snow);
												sti();
											}
										}
									}
									break;
								}
							}
						} else {	/* ウインドウ移動モード（移動量を計算して動かす） */
							x = mdec.mx - mmx;
							y = mdec.my - mmy;
							nwx = (mmx2 + x + 2) & ~3;
							nwy = nwy + y;
							if(nwy > binfo->scrny - 28) {
								nwy = binfo->scrny - 28;
								mdec.my = binfo->scrny - 28;
							}
							mmy = mdec.my;
						}
					} else {	/* 左ボタンを押していない */
						mmx = -1;	/* 通常モードへ */
						if(nwx != 0x7fffffff) {
							sheet_slide(sht, nwx, nwy);
							nwx = 0x7fffffff;
						}
					}
				}
			} else if(1024 <= i && i <= 1279) {	/* コンソール終了処理 */
				cons_close(shts->sheet + (i - 1024));
			} else if(1280 <= i && i <= 1535) {	/* コンソールだけを閉じる */
				sht2 = shts->sheet + (i - 1280);
				memory_free(mem, (int) sht2->buf, (CONSOLE_X * 8 + 16) * (CONSOLE_Y * 16 + 36));
				sheet_free(sht2);
			}
		}
	}
}
