#include "../../bootpack.h"

/*
 * staticメンバ
 */
bool Mouse::scroll_ = false;
MouseDecode Mouse::mdec;

void Mouse::init_cursor(system::Picture& cursor) {
	static const char mcursor1[YSIZE][XSIZE + 1] = {
		"*___________",
		"**__________",
		"*.*_________",
		"*..*________",
		"*...*_______",
		"*....*______",
		"*.....*_____",
		"*......*____",
		"*.......*___",
		"*........*__",
		"*.........*_",
		"*......*****",
		"*...*..*____",
		"*..**..*____",
		"*.*__*..*___",
		"**___*..*___",
		"*_____*..*__",
		"______*..*__",
		"_______*..*_",
		"_______*..*_",
		"________***_",
	};
	int y, x;
	for (y = 0; y < YSIZE; y++) {
		for (x = 0; x < XSIZE; x++) {
			if (mcursor1[y][x] == '*') {
				cursor.point(x, y, 0x0000);
			} else if (mcursor1[y][x] == '.') {
				cursor.point(x, y, 0xffff);
			} else {
				cursor.point(x, y, 0x0001);
			}
		}
	}
}

void Mouse::enable() {
	#ifndef DEBUG_MESSAGE
	Message* msg;
	#else
	Message* msg;
	Message msg_;
	#endif
	int i = 0;
	int errors = 0; // エラーの回数
	bool send = false; // マウスへ送信したらtrue
	
	// マウスホイール有効化
	for (;;) {
		/*
		 * まずマウスへ制御信号送信
		 */
		if (i == 0 && send == false) {
			out(0xf3);
			send = true;
		} else if (i == 1 && send == false) {
			out(200);
			send = true;
		} else if (i == 2 && send == false) {
			out(0xf3);
			send = true;
		} else if (i == 3 && send == false) {
			out(100);
			send = true;
		} else if (i == 4 && send == false) {
			out(0xf3);
			send = true;
		} else if (i == 5 && send == false) {
			out(80);
			send = true;
		} else if (i == 6 && send == false) {
			out(0xf2);
			send = true;
		}
		io_cli();
		if (task1_fifo->size() == 0) {
			io_stihlt();
			continue;
		}
		#ifndef DEBUG_MESSAGE
		msg = task1_fifo->back();
		#else
		msg_ = task1_fifo->back();
		msg = &msg_;
		#endif
		task1_fifo->pop();
		io_sti();
		
		if (msg->type == MSG::TYPE::MOUSE) {
		
			if (0 <= i && i <= 6 && msg->arg1 == 0xfa) {
				// エラー無し
			} else if (i == 7 && msg->arg1 == 0) {
				// ホイール無し
				scroll_ = false;
			} else if (i == 7 && msg->arg1 == 3) {
				// ホイール有り
				scroll_ = true;
			}
			
			if (i == 7 || errors > 10) {
				/*
				 * ループを抜ける
				 */
				#ifndef DEBUG_MESSAGE
				delete msg;
				#endif
				break;
			}
			
			if (msg->arg1 != 0xfe) {
				// 再送要求では無かった
				i++;
				send = false;
			} else {
				errors++;
			}
		}
		
		#ifndef DEBUG_MESSAGE
		delete msg;
		#endif
	}
	
	// マウス初期化
	for (i = 0, send = false;;) {
		/*
		 * マウスの初期化
		 */
		if (i == 0 && send == false) {
			out(0xe8); // set resolution
			send = true;
		} else if (i == 1 && send == false) {
			out(0x03); // 8 count/mm
			send = true;
		} else if (i == 2 && send == false) {
			out(0xe6); // set scaling 1:1
			send = true;
		} else if (i == 3 && send == false) {
			out(0xf3); // set sample rate
			send = true;
		} else if (i == 4 && send == false) {
			out(40);
			send = true;
		}
		io_cli();
		if (task1_fifo->size() == 0) {
			io_stihlt();
			continue;
		}
		#ifndef DEBUG_MESSAGE
		msg = task1_fifo->back();
		#else
		msg_ = task1_fifo->back();
		msg = &msg_;
		#endif
		task1_fifo->pop();
		io_sti();
		
		if (msg->type == MSG::TYPE::MOUSE) {
		
			if (0 <= i && i <= 4 && msg->arg1 == 0xfa) {
				// エラー無し
			}
			
			if (i == 4 || errors > 10) {
				/*
				 * マウス初期化が終わったのでループを抜ける
				 */
				#ifndef DEBUG_MESSAGE
				delete msg;
				#endif
				break;
			}
			
			if (msg->arg1 != 0xfe) {
				// 再送要求では無かった
				i++;
				send = false;
			} else {
				errors++;
			}
		}
		
		#ifndef DEBUG_MESSAGE
		delete msg;
		#endif
	}

	// 以下を実行すると、マウスからの座標情報が届くようになる
	out(MOUSECMD_ENABLE);
	
	// マウスから0xfaが来るのを待つ段階
	mdec.phase = 0;
}

bool Mouse::decode(byte data) {
	bool finished = false; // 解析が終了したらtrue
	if (mdec.phase == 0) {
		if (data == 0xfa) {
			mdec.phase = 1;
		}
	} else if (mdec.phase == 1) {
		if ((data & 0xc8) == 0x08) {
			// 正しい1バイト目だった
			mdec.buf[0] = data;
			mdec.phase++;
		}
	} else if (mdec.phase == 2) {
		mdec.buf[1] = data;
		mdec.phase++;
	} else if (mdec.phase == 3) {
		mdec.buf[2] = data;
		if (scroll_ == true) {
			// マウスはホイール有り
			mdec.phase++;
		} else {
			// マウスはホイール無し
			mdec.phase = 1;
			
			// ホイール無しなので、以下の解析が終わればOK
			finished = true;
		}
		
		// これからマウスデータの解析をする
		// この解析は、ホイール有り、無しで共通である
		mdec.button = mdec.buf[0] & 0x07;
		mdec.x = mdec.buf[1];
		mdec.y = mdec.buf[2];
		
		if (mdec.buf[0] & 0x10) {
			// X sign bit == 1
			mdec.x |= 0xffffff00;
		}
		
		if (mdec.buf[0] & 0x20) {
			// Y sign bit == 1
			mdec.y |= 0xffffff00;
		}
		mdec.y = -mdec.y;
	} else if (mdec.phase == 4) {
		mdec.buf[3] = data;
		mdec.phase = 1;
		finished = true;
		
		// mdec.buf[3]は、下位4ビットだけが有効な値である
		// とりあえず解析せずに値をしまう。
		mdec.scroll = mdec.buf[3] & 0x0f;
		if (mdec.scroll & 0x08) {
			// マイナスの値だった
			mdec.scroll |= 0xfffffff0;
		}
	}
	return finished;
}

void Mouse::out(byte data)
{
	IO8 keycmd(Keyboard::PORT_KEYCMD);
	IO8 keydat(Keyboard::PORT_KEYDAT);
	Keyboard::wait_sendready();
	keycmd << Mouse::KEYCMD_SENDTO_MOUSE;
	Keyboard::wait_sendready();
	keydat << data;
}


