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

void BitNosMain() { BitNosMainCpp(); }
void task_b_main();

// グローバルメモリマネージャ
Memory g_km;

Font* font_hankaku;
Font* font_mini;

Screen* g_screen;
SheetController* g_shtctl;
Sheet* g_sheet_back;
TaskController* g_taskctl;

#ifndef DEBUG_MESSAGE
queue<Message*>* task1_fifo;
#else
queue<Message>* task1_fifo;
#endif
DebugWindow* dbg;

int BitNosMainCpp()
{
	BootInfo binfo(reinterpret_cast<BootInfo*>(ADR_BOOTINFO));

	dword memory_size = g_km.getMemorySize(0x00400000, 0xbfffffff); /* 物理メモリサイズ */
	g_km.init(0x00400000, memory_size); /* メモリマネージャ初期化 */

	char* s = new char[256];

	
	// FDDのモーターを止める
	IO8 fd_motor(0x03f2);
	fd_motor << 0x0c;
	
	// ディスクリプタの初期化
	GDT::init();
	IDT::init();
	
	// 割り込みコントローラの初期化
	PIC::init();
	
	// インターバルタイマの初期化
	PIT::init();
	
	IO8 pic0_imr(PIC::PIC0_IMR);
	IO8 pic1_imr(PIC::PIC1_IMR);
	pic0_imr << 0xf8; // タイマー,キーボード割り込み許可
	pic1_imr << 0xef; // マウス割り込み許可

	Keyboard::init();
	
	// VESAドライバの生成と、スクリーンの設定
	IVideo* vesa_driver = 0;
	if (binfo.scrn_mode == 16) {
		vesa_driver = new Vesa;
	} else if (binfo.scrn_mode == 8) {
		init_palette();
		vesa_driver = new Vesa8;
	} else {
		vesa_driver = new Vesa;
	}
	vesa_driver->init(reinterpret_cast<word*>(binfo.vram), binfo.scrn_x, binfo.scrn_y);
	g_screen = new Screen(vesa_driver, binfo.scrn_x, binfo.scrn_y);
	
	// シートコントローラの生成
	g_shtctl = new SheetController();
	
	// 半角フォント（標準）の設定  xsize = 8, ysize = 16
	font_hankaku = new Font(hankaku, 8, 16);
	// ミニフォント（OSAkkie）の設定  xsize = 6, ysize = 12
	font_mini = new Font(minifnt, 6, 12);
	
	// デバッグ用表示領域の作成
	if (binfo.scrn_y >= 600) {
		dbg = new DebugWindow(10, binfo.scrn_y - 16 * 15 - 40, 8 * 40, 16 * 15);
	} else {
		dbg = new DebugWindow(10, binfo.scrn_y - 16 * 5 - 40, 8 * 40, 16 * 5);
	}
	
	// タイマコントローラの生成
	g_timerctl = new TimerController();
	
	
	// 背景用シートの生成
	Sheet* sheet_back = g_shtctl->alloc();
	g_sheet_back = sheet_back;
	sheet_back->init(binfo.scrn_x, binfo.scrn_y);
	sheet_back->set_fix(true);
	Picture* buffer_back = sheet_back->get_buffer();
	sheet_back->set_invisible_color(0x0001);
	g_shtctl->updown(sheet_back, 0);
	
	
	// 背景描画
	buffer_back->box(0, 0, binfo.scrn_x - 1, binfo.scrn_y - 1, Screen::BACKGROUND_COLOR);
	
	Sheet* sheet_taskbar = g_shtctl->alloc(TASK_TASKBAR);
	sheet_taskbar->init(buffer_back->get_xsize(), 26);
	sheet_taskbar->set_invisible_color(0x0001);
	sheet_taskbar->set_fix(true);
	Picture* buffer_taskbar = sheet_taskbar->get_buffer();
	buffer_taskbar->box(0, 0, buffer_taskbar->get_xsize() - 1, 26 - 1, Screen::TASKBAR_COLOR);
	buffer_taskbar->box(0, 0, buffer_taskbar->get_xsize() - 1, 0, 0xffff);
	g_shtctl->slide(sheet_taskbar, 0, buffer_back->get_ysize() - buffer_taskbar->get_ysize());
	g_shtctl->updown(sheet_taskbar, 1);

	Sheet* sheet_win1 = g_shtctl->alloc(TASK_KERNEL);
	sheet_win1->init(200, 150);
	sheet_win1->set_invisible_color(0x0001);
	Picture* buffer_win1 = sheet_win1->get_buffer();
	buffer_win1->box(3,  29, 200 - 4, 150 - 4, Screen::TASKBAR_COLOR);
	Window::make(sheet_win1);
	buffer_win1->putstr(10, 8, "task_a", 0xffff);
	g_shtctl->updown(sheet_win1, 4);
	g_shtctl->slide(sheet_win1, 100, 10);

	Message* msg = 0;
	
	
	
	g_shtctl->refresh_map(0, 0, binfo.scrn_x, binfo.scrn_y, 0);
	// いったん全て再描画させておく
	g_shtctl->refresh(sheet_back, 0, 0, buffer_back->get_xsize(), buffer_back->get_ysize());
	
	// タスクコントローラの生成
	g_taskctl = new TaskController();
	Task* task_a = g_taskctl->init();
	Task* task_b = g_taskctl->alloc(1, 1);
	task_b->set_tss_esp((dword)malloc(64 * 1024) + 64 * 1024);
	task_b->set_tss_eip( (dword)&system::task_b_main );
	g_taskctl->run(task_b);

	#ifndef DEBUG_MESSAGE
	task1_fifo = new queue<Message*>(512);
	#else
	//task1_fifo = new queue<Message>(256);
	task1_fifo = task_a->fifo();
	#endif
    
	
	*dbg << "debug console";
	
	Timer* tim2 = g_timerctl->alloc();
	tim2->set_task(task_a, 200);
	timer_settime(tim2, 300);
	Timer* tim3 = g_timerctl->alloc();
	tim3->set_task(task_a, 300);
/*
	sheet_dframe = g_shtctl->alloc();
	//sheet_dframe->init(buffer_win1->get_xsize(), buffer_win1->get_ysize());
	sheet_dframe->init(20, 20);
	sheet_dframe->set_invisible_color(0x0000);
	Picture* buffer_dframe = sheet_dframe->get_buffer();
	buffer_dframe->box(0, 0,
		20 - 1, 20 - 1,
		0x0000);
	buffer_dframe->box(8, 0,
		12 - 1, 20 - 1,
		convC(0xC0C0C0));
	buffer_dframe->box(0, 8,
		20 - 1, 12 - 1,
		convC(0xC0C0C0));
*/
	for (;;) {
		io_cli();
		if (task1_fifo->size() == 0) {
			g_taskctl->sleep(task_a);
			io_sti();
			continue;
		}
		#ifndef DEBUG_MESSAGE
		msg = task1_fifo->back();
		#else
		//msg_ = task1_fifo->back();
		//msg = &msg_;
		msg = &task1_fifo->back();
		#endif
		io_sti();
		if (msg->type == MSG::TYPE::TIMER) {
			if (msg->arg1 == 100) {
				// 自分で設定したタイマーがタイムアウトした
				dbg->flush();
			} else if (msg->arg1 == 200) {
				// 自分で設定したタイマーがタイムアウトした
				timer_settime(tim3, 700);
				*dbg << "3 sec";
			} else if (msg->arg1 == 300) {
				// 自分で設定したタイマーがタイムアウトした
				*dbg << "10sec";
			}
		}
		//buffer_back->box(0, 424, 8 * 15 - 1, 424 + 16 - 1, 0xffff);
		//sprintf(s, "free:%dB", g_km.getFreeSize());
		//buffer_back->putstr(0, 424, s, 0x0000);
		//g_shtctl->refresh(sheet_back, 0, 424, 8 * 15, 424 + 16);
		
		#ifndef DEBUG_MESSAGE
		// Message::create()の中で、newを使って生成しているため、ここでdeleteする
		delete msg;
		#endif
		task1_fifo->pop();
	}
	delete[] s;
	return 0;
}

void putstr_sht(Sheet* sht, int x, int y, const char* str, color_16 color,
	color_16 bgcolor, Font* font)
{
	int length = strlen(str);
	Picture* buf = sht->get_buffer();
	buf->box(x, y, x + 8 * length - 1, y + 15, bgcolor);
	buf->putstr(x, y, str, color, font);
	g_shtctl->refresh(sht, x, y, x + 8 * length, y + 16);
}

void box_sht(Sheet* sht, int x0, int y0, int x1, int y1, color_16 color) {
	sht->get_buffer()->box(x0, y0, x1, y1, color);
	g_shtctl->refresh(sht, x0, y0, x1 + 1, y1 + 1);
}

