/// マラソン用スクリプト
/// DQ9-MAP解析板（簡易検索） http://dq9.hustle.ne.jp/mapsearch.cgi を非常に参考にしています


gMaxRow = 30;
gMaxColumn = 3;
gWait = 0;  // 開始前の待ち時間
gSearch = "ソーマ|げんま";
gImageType = 0;

gSec = 0;  // 前回更新時の秒数
gStart = 0;
gRunning = false;
gTimerID = false;


/// @brief 階層に対応する列番号を返す
function getColumnIndex(floor) {
	for (var i = 0; i < BOXES.length; i++) {
		if (BOXES[i][0] == floor) {
			return i;
		}
	}
	return 0;
}


/// @brief 取得アイテムを調べる
/// @param[in] map 地図のシード
/// @param[in] floor 階層 (1..18)
/// @param[in] type 宝箱種別 (1..3)
/// @param[in] rank 宝箱ランク (1..10)
/// @param[in] sec 秒数 (7..)
function getItemName(map, floor, type, rank, sec) {
	var ITEMS = [
			['やくそう', 'おもいでのすず', 'まほうのせいすい', 'せいすい', 'グビアナどうか', 'どくけしそう', 'こんぼう', 'まんげつそう', 'キメラのつばさ', '125G', 'ニーソックス', '上やくそう', 'ぎんのリスト', 'うさぎのおまもり'],
			['まりょくの土', 'ようがんのカケラ', '天使のすず', 'シルバートレイ', 'げんこつダケ', 'いやしそう', '上どくけしそう', '268G', 'グビアナどうか', 'ばくだん石', 'てつのクギ', 'きんのゆびわ', 'きんのブレスレット', 'てっかめん'], 
			['ひとくいばこ', 'ガマのあぶら', 'ちいさなメダル', 'げんこつダケ', 'グビアナどうか', '450G', 'てっこうせき', 'スライムトレイ', 'ルビーのげんせき', '命の石', 'グビアナぎんか', 'ちからのゆびわ', 'はやてのリング'],
			['ミミック', 'どくどくヘドロ', '花のみつ', 'ちいさなメダル', 'グビアナぎんか', 'まほうのせいすい', '670G', 'ひらめきのジュエル', 'つけもの石', 'かがみ石', 'ゆうわくの弓', 'ふしぎなボレロ', 'せいじゃのはい', 'うらみのほうじゅ'],
			['ミミック', 'ばんのうぐすり', 'ヘパイトスのひだね', 'まほうのせいすい', 'あらくれベルト', 'メイド服', 'あらくれブーツ', 'あらくれマスク', 'ヘッドドレス', 'あらくれズボン', 'ぶどうエキス', 'とうこんエキス', 'あぶないビスチェ', 'ちいさなメダル', 'まてきの杖', 'あやかしそう'],
			['ミミック', 'おかしなくすり', 'ヘパイトスのひだね', 'グビアナぎんか', '天使のはね', 'ヘビーメタル', 'ぶしんのリスト', 'オープンフィンガー', 'ミスリルこうせき', '古強者のグローブ', 'ちいさなメダル', 'じごくの弓', 'しんかんのブーツ', 'ドクロのゆびわ', 'まじんのかなづち', 'サタンヘルム', 'あくまのムチ'],
			['ミミック', 'せいじゃのはい', 'ヘビーメタル', 'ほしのカケラ', 'けんじゃのせいすい', '880G', '超ばんのうぐすり', 'しわよせのくつ', 'しわよせのぼうし', 'ちいさなメダル', '古強者のよろい', 'だいまどうシューズ', '古強者のブーツ', 'ぶしんのブーツ', 'まじょのブーツ', 'しんかんのタイツ', 'はめつの盾', 'さとりのワンピース', 'ドクロのかぶと', 'マタドールグラブ'],
			['パンドラボックス', 'せいれいせき', 'ミスリルこうせき', 'けんじゃのせいすい', '1500G', 'ちいさなメダル', 'グビアナきんか', 'きんかい', 'えいゆうのやり', 'こがらしのダガー', 'ドラゴンの杖', 'カルベロビュート', 'まじゅうのツメ', '風林火山', 'ふんさいのおおなた', 'メガトンハンマー', 'ペンタグラム'],
			['パンドラボックス', '天使のはね', 'げんませき', '3000G', 'けんじゃのせいすい', 'ちいさなメダル', 'グビアナきんか', 'しにがみの首かざり', 'オリハルコン', 'メタスラの剣', 'メタスラのやり', 'メタスラの盾', 'メタスラよろい', 'メタスラヘルム', 'メタスラのこて', 'メタスラブーツ'],
			['パンドラボックス', 'リサイクルストーン', 'グビアナきんか', 'おもいでのすず', 'けんじゃのせいすい', '天使のソーマ', 'せかいじゅのは', 'きんかい', 'オリハルコン', 'ほしくずのつるぎ', 'きしんのまそう', 'サウザンドダガー', 'ひかりの杖', 'グリンガムのムチ', 'しゅらのこん', '竜王のツメ', 'ひっさつのおうぎ', 'グレートアックス', '大地くだき', 'メテオエッジ', '天使の弓'] ];

	var RANGES = [
			[9, 19, 24, 34, 44, 52, 57, 65, 75, 85, 87, 95, 97, 99], 
			[7, 15, 25, 27, 37, 47, 57, 67, 75, 83, 93, 95, 97, 99], 
			[9, 19, 29, 39, 49, 59, 69, 70, 80, 90, 95, 97, 99], 
			[4, 19, 34, 46, 56, 71, 83, 85, 90, 95, 96, 97, 98, 99], 
			[4, 19, 29, 44, 45, 46, 47, 48, 49, 50, 60, 70, 71, 83, 84, 99], 
			[9, 24, 39, 54, 64, 70, 71, 72, 82, 83, 93, 94, 95, 96, 97, 98, 99], 
			[9, 19, 29, 39, 49, 64, 70, 72, 74, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99], 
			[4, 17, 30, 40, 55, 70, 85, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99], 
			[9, 19, 29, 39, 49, 64, 74, 84, 92, 93, 94, 95, 96, 97, 98, 99], 
			[14, 24, 34, 44, 59, 69, 77, 82, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99] ];

	var seed = map + floor + sec - 5;
	var high = seed >> 16;

	for (var i = 0; i < type; i++) {
		seed = (seed & 0xffff) * 1103515245 + 12345;
		high = (high * 1103515245 + (seed >> 16)) & 0xffff;
	}
	var rand = Math.min(Math.floor((high & 0x7fff) * 100 / 0x7fff), 99);
	
	for (var i = 0; ; i++) {
		if (rand <= RANGES[rank - 1][i]) {
			return ITEMS[rank - 1][i];
		}
	}
}


/// @brief 表の先頭列に書く秒数の文字列を返す
function getTimeStrForTable(sec) {
	return (sec < 8) ? "即" : Math.floor(sec);
}


/// @brief 表の先頭列に書く秒数の文字列 "%02d:%02.1f" を返す
function getTimeStrForWatch(sec) {
	var h = "0" + Math.floor(Math.abs(sec) / 60);
	var s = "0" + Math.floor(Math.abs(sec) % 60);
	var f = Math.floor((Math.abs(sec) * 10) % 10);
	var p = (sec < 0) ? "-" : " ";
	return p + h.substr(h.length - 2) + ":" + s.substr(s.length - 2) + "." + f;
}


/// @brief 全体を初期化する
function initialize() {
	initializeGlobalParameter();
	initializeTable(gMaxRow, gMaxColumn);
	initializeSelect();
	initializeMiniMap();
	update();
}


/// @brief CookieからGlobal変数を初期化
function initializeGlobalParameter() {
	var ary = document.cookie.split("; ");
	var i = 0;
	while (ary[i]) {
		var txt = ary[i];
		if (txt.substr(0, 9) == "marathon=") {
			var ary2 = txt.substr(9, txt.length).split("%00");
			if (ary2[0]) {
				gMaxColumn = getColumnNum(unescape(ary2[0]));
			}
			if (ary2[1]) {
				gMaxRow = getRowNum(unescape(ary2[1]));
			}
			if (ary2[2]) {
				gWait = getWaitNum(unescape(ary2[2]));
			}
			if (ary2[3]) {
				gSearch = unescape(ary2[3]);
			}
			if (ary2[4]) {
				gImageType = getWaitNum(unescape(ary2[4]));
			}
			return;
		}
		i++;
	}
}


/// @brief 地図画像の初期化
function initializeMiniMap() {
	if (isShowMiniMap()) {
		var div = document.createElement("div");
		document.body.appendChild(div);
		div.id = "minimap";
		div.style.backgroundImage = "url(" + IMAGE + ")";
	}
}


/// @brief コンボボックスの初期化
function initializeSelect() {
	var select = document.getElementById("floorSelect");
	var max_floor = BOXES[BOXES.length-1][0] + 1;
	for (var i = 1; i < max_floor; i++) {
		var option = document.createElement("option");
		select.appendChild(option);
		option.setAttribute("value", i);
		option.innerHTML = "B" + i + "F";
	}
	select.value = "3";
}


/// @brief 表を初期化する
/// @param[in] row 行数 (1..)
/// @param[in] column 列数 (3..)
function initializeTable(row, column) {
	var table = document.getElementById("marathon");
	
	{
		var thead = document.createElement("thead");
		table.appendChild(thead);
		
		var tr = document.createElement("tr");
		thead.appendChild(tr);
		
		if (isShowTableMap()) {
			var th = document.createElement("th");
			tr.appendChild(th);
			updateClassAttribute(th, "map");
			th.innerHTML = "地図";
		}
		
		{
			var th = document.createElement("th");
			tr.appendChild(th);
			updateClassAttribute(th, "sec");
			th.innerHTML = "秒";
		}
		
		for (var j = 0; j < column; j++) {
			var th = document.createElement("th");
			tr.appendChild(th);
		}
	}
	
	var tbody = document.createElement("tbody");
	table.appendChild(tbody);
	
	for (var i = 0; i < row; i++) {
		var tr = document.createElement("tr");
		tbody.appendChild(tr);
		
		if ((i == 0) && isShowTableMap()) {
			var td = document.createElement("td");
			tr.appendChild(td);
			td.rowSpan = row;
			td.id = "minimap";
			td.style.backgroundImage = "url(" + IMAGE + ")";
		}
		
		{
			var td = document.createElement("td");
			updateClassAttribute(td, "sec");
			tr.appendChild(td);
		}
		
		for (var j = 0; j < column; j++) {
			var td = document.createElement("td");
			tr.appendChild(td);
		}
	}
}


/// @brief 表にマップを表示するか
function isShowTableMap() {
	return ((IMAGE != "") && (gImageType == 2));
}


/// @brief 画面右下に小さなマップを表示するか
function isShowMiniMap() {
	return ((IMAGE != "") && (gImageType == 1));
}


/// @brief 次の階に移動する
function nextFloor() {
	var select = document.getElementById("floorSelect");
	var index = select.selectedIndex + 1;
	if (index == select.length) {
		index = 2;
	}
	select.selectedIndex = index;
	update();
}


/// @brief スタートボタン / リセットボタン
function onButtonStart() {
	gRunning = !gRunning;
	gSec = 0;
	if (gRunning) {
		gStart = (new Date()).getTime() + gWait * 1000;
		document.getElementById("startButton").setAttribute("value", "リセット");
		gTimerID = setInterval(timer, 20);  // 50fps
	} else {
		document.getElementById("startButton").setAttribute("value", "開始");
		clearInterval(gTimerID);
	}
	update();
}


/// @brief タイマー
function timer() {
	var sec = ((new Date()).getTime() - gStart) / 1000;
	if (Math.floor(gSec) < Math.floor(sec)) {
		if (sec >= 8) {
			update();
		} else {
			updateWatch(sec);
		}
	} else if (Math.floor(gSec * 10) < Math.floor(sec * 10)) {
		updateWatch(sec);
	}
	gSec = sec;
}

/// @brief 全体を更新する
function update() {
	var sec = gRunning ? ((new Date()).getTime() - gStart) / 1000 : -gWait;
	var select = document.getElementById("floorSelect");
	var floor = select.options[select.selectedIndex].value;
	
	updateMapImage(floor);
	updateTable(sec, getColumnIndex(floor));
	updateWatch(sec);
}


/// @brief class属性をつける
function updateClassAttribute(element, value) {
	if (value == null) {
		element.removeAttribute("class");
		element.removeAttribute("className");
	} else {
		element.setAttribute("class", value);
		element.setAttribute("className", value);
	}
}


/// @brief
function updateMapImage(floor) {
	if (isShowTableMap() || isShowMiniMap()) {
		var element = document.getElementById("minimap");
		element.style.backgroundPosition = "0 " + -112 * (floor-1) + "px";
	}
}


/// @brief
function updateTable(sec, column) {
	var sec_start = Math.max(Math.floor(sec), 7);
	
	var table = document.getElementById("marathon");
	var match = new RegExp(gSearch);
	
	{
		var offset = isShowTableMap() ? 2 : 1;
		var children = table.getElementsByTagName("thead")[0].rows[0].childNodes;
		for (var j = 0; j < gMaxColumn; j++) {
			if (column + j < BOXES.length) {
				var box = BOXES[column + j];
				children[j + offset].innerHTML = box[3];
			} else {
				children[j + offset].innerHTML = "";
			}
		}
	}
	
	var tbody = table.lastChild;
	for (var i = 0; i < gMaxRow; i++) {
		var offset = ((i == 0) && isShowTableMap()) ? 2 : 1;
		var children = tbody.rows[i].childNodes;
		var sec_row = sec_start + i;
		children[offset-1].innerHTML = (sec_row < 8) ? "即" : getTimeStrForTable(sec_row);
		for (var j = 0; j < gMaxColumn; j++) {
			var txt = "";
			if (column + j < BOXES.length) {
				var box = BOXES[column + j];
				txt = getItemName(SEED, box[0], box[1], box[2], sec_row);
			}
			children[j + offset].innerHTML = txt;
			if (txt.match(match)) {
				updateClassAttribute(children[j + offset], "hit");
			} else {
				updateClassAttribute(children[j + offset], null);
			}
		}
	}
}


/// @brief
function updateWatch(sec) {
	document.getElementById("watchText").value = getTimeStrForWatch(sec);
}

