
var Scr;
var Nomi;
//var XmlHttp;
var Interval;
var Timeout;
var Act;


/* ========== 
** 定数
*/
var WIDTH = 478;
var HEIGHT = 358;
var SIZE = 4;

/* ========== 
** グローバルに使う関数
*/
/*  */
function printCsl(str) {
	var Console = document.getElementById('console');
	Console.replaceChild(document.createTextNode(str), Console.firstChild);
}

createXmlHttp = function() {
  var xmlhttp = false;

  try {
    xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
  } catch (e) {
    try {
      xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (E) {
      xmlhttp = false;
    }
  }
  if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
    xmlhttp = new XMLHttpRequest();
  }

  return xmlhttp;
}

function getData(num, act) {
	Act = act;
	if(xmlhttp) {
		//xmlhttp.onreadystatechange = functionthis.statechange;
		xmlhttp.open('GET', './xmlconv.cgi?' + num, true);
		xmlhttp.onreadystatechange = function() {
			//alert((new Date()).getSeconds());
			if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
				Act.httpAction(xmlhttp.responseText);
			}
		}
		xmlhttp.send(null);
	}
}

/* ========== 
** 自機オブジェクト
*/
function Player() {
	this.x = 100;
	this.y = 300;
	this.yfloat = this.y;
	this.r = true;
	this.DX = 2;
	this.dx = this.DX;
	this.DY = -4;
	this.dy = this.DY;
	this.DDY = .32;
	this.isJet = false;
	this.isReverse = false;
	this.isJump = true;
	
	// ノミ本体を作る
	this.obj = document.createElement('div');
	this.obj.id = 'player';
	Scr.obj.appendChild(this.obj);
	Scr.moveObj(this);
	
	// 初期化
	this.initialize = function(ax, ay) {
		with(this) {
			x = ax;
			y = ay;
			yfloat = y;
			r = true;
			dx = DX;
			dy = DY;
			isJet = false;
			isReverse = false;
			isJump = true;
			Scr.moveObj(this);
			obj.style.visibility = 'visible';
		}
	}
	
	// 1コマ分動かす
	this.move = function() {
		this.x = (this.r) ? (this.x + this.dx) : (this.x - this.dx);
		this.dy = (this.isReverse) ? (this.dy - this.DDY) : (this.dy + this.DDY);
		this.yfloat += this.dy;
		this.y = Math.round(this.yfloat);
		Scr.moveObj(this);
	}
	
	// ジャンプ
	this.jump = function() {
		if(this.isJump && !this.isJet) {
			this.r = !this.r;
			this.dx = this.DX;
			this.dy = (this.isReverse) ? (-this.DY) : (this.DY);
		}
	}
	
	// ブロックの種類による状態変更
	this.changeType = function(past, now) {
		switch(past) {
			case 'reverse' :
				this.isReverse = false;
				break;
			case 'jet' :
				this.isJet = false;
				break;
			case 'hide' :
				this.obj.style.visibility = 'visible';
				break;
			case 'slick' :
				this.isJump = true;
				break;
		}
		switch(now) {
			case 'reverse' :
				this.isReverse = true;
				break;
			case 'jet' :
				if(!this.isJet) {
					this.isJet = true;
					this.r = !this.r;
					this.dx = this.DX * 3;
					this.dy *= -1;
					this.dy -= this.DDY;
				}
				break;
			case 'hide' :
				this.obj.style.visibility = 'hidden';
				break;
			case 'slick' :
				this.isJump = false;
				break;
		}
	}
}

/* ========== 
** ブロック
*/
function Block(props) {
	switch(props.figure) {
		case 'square':
			this.child = new squareBlock(props, this);
			break;
		case 'line':
			this.child = new lineBlock(props, this);
			break;
		case 'circle':
			this.child = new circleBlock(props, this);
			break;
	}
	this.x = props.x;
	this.y = props.y;
	this.width = props.width;
	this.height = this.child.height;
	if((props.type == 'blink_a') || (props.type == 'blink_b')) {
		this.isBlink = true;
		this.blinkNum = (props.type == 'blink_a') ? 0: 1;
		this.type = 'norm';
	}
	else {
		this.type = props.type;
	}
	this.isVisible = true;
	//this.obj = document.createElement('div');
	this.child.create();
	Scr.obj.appendChild(this.obj);
	Scr.putObj(this);
}
// 当たり判定
Block.prototype.check = function() {
	if((this.isVisible) && (this.x <= Nomi.x + SIZE) && (Nomi.x <= this.x + this.width) && (this.y <= Nomi.y + SIZE) && (Nomi.y <= this.y + this.height) && (this.child.check())) {
		return this.type;
	}
	return '';
}
// ブロック除去
Block.prototype.removeObj = function() {
	//this.child.removeObj();
	delete this.child;
	Scr.obj.removeChild(this.obj);
}
// 点滅
Block.prototype.blink = function(num) {
	if(this.isBlink) {
		this.isVisible = (this.blinkNum == num);
		this.obj.style.visibility = this.isVisible ? 'visible' : 'hidden';
	}
}

/* ========== 
** 四角ブロック
*/
function squareBlock(props, wrap) {
	this.wrap = wrap;
	this.height = props.height;
}
squareBlock.prototype.create = function() {
	this.wrap.obj = document.createElement('div');
	this.wrap.obj.className = 'block square_' + this.wrap.type;
}
squareBlock.prototype.check = function() {
	return true;
}
squareBlock.prototype.removeObj = function() {
	// 
}

/* ========== 
** 円ブロック
*/
function circleBlock (props, wrap) {
	this.wrap = wrap;
	this.height = props.width;
}
circleBlock.prototype.create = function() {
	this.wrap.obj = document.createElement('img');
	this.wrap.obj.src = 'imggen.cgi?circle.' + this.wrap.type + '.' + this.wrap.width;
	this.wrap.obj.className = 'block';
//	this.obj.width = this.wrap.width;
//	this.obj.height = this.height;
//	this.wrap.obj.appendChild(this.obj);
}
circleBlock.prototype.check = function() {
	return (Math.sqrt(Math.pow(((this.wrap.x + this.wrap.width/2) - (Nomi.x + SIZE/2)), 2) + Math.pow(((this.wrap.y + this.wrap.height/2) - (Nomi.y + SIZE/2)), 2)) < (this.wrap.width/2 + SIZE/2));
}
circleBlock.prototype.removeObj = function() {
	this.wrap.obj.removeChild(this.obj);
}

/* ========== 
** 線ブロック
*/
function lineBlock(props, wrap) {
	this.wrap = wrap;
	this.tilt = props.height / props.width
	this.height = props.height + props.weight - 1;
	this.bheight = props.height;
	this.weight = props.weight;
	this.dir = props.dir;
}
lineBlock.prototype.create = function() {
	this.wrap.obj = document.createElement('img');
	this.wrap.obj.src = 'imggen.cgi?line.' + this.wrap.type + '.' + this.dir + '.' + this.wrap.width + '.' + this.bheight + '.' + this.weight;
	this.wrap.obj.className = 'block';
	//this.obj.width = this.wrap.width;
	//this.obj.height =this.height;
	//this.wrap.obj.appendChild(this.obj);
}
lineBlock.prototype.check = function() {
	var ty = Nomi.x + SIZE / 2 - this.wrap.x;
	if(this.dir == 'up') ty = this.wrap.width - ty;
	ty *= this.tilt;
	var ty2 = SIZE * this.tilt / 2;
	if((this.wrap.y + ty <= Nomi.y + SIZE + ty2) && (Nomi.y <= this.wrap.y + this.weight + ty + ty2)) {
		return true;
	}
	return false;
}
lineBlock.prototype.removeObj = function() {
	this.wrap.obj.removeChild(this.obj);
}

/* ========== 
** ブロック管理
*/
function Blocks() {
	this.blocks = new Array;
	
	// ステージ構築
	this.build = function(blocks) {
		for(var i in blocks) {
			this.blocks[i] = new Block(blocks[i]);
		}
	}
	
	// ステージ除去
	this.remove = function() {
		for(var i in this.blocks) {
			this.blocks[i].removeObj();
			delete this.blocks[i];
		}
		delete this.blocks;
		this.blocks = new Array;
	}
	
	// 当たり判定
	this.check = function() {
		// 画面からはみ出てないかチェック
		if((Nomi.x < 0) || (WIDTH - SIZE < Nomi.x) || (Nomi.y < 0) || (HEIGHT - SIZE < Nomi.y)) {
			return 'norm';
		}
		// 全ブロックをチェック
		for(var i = this.blocks.length - 1; i >= 0; i--) {
			var r = this.blocks[i].check();
			if(r == 'erase') return '';
			if(r != '' ) return r;
		}
		return '';
	}
	
	this.blink = function(flag) {
		for(var i in this.blocks) {
			this.blocks[i].blink(flag);
		}
	}
}


/* ====================
** ゲーム実行中の管理
*/
function Game(ctrl) {
	this.isPlay = false;
	this.itvID;
	this.blocks = new Blocks();
	this.ctrl = ctrl;
	this.isPrepared = false;
	
	Interval = this;
	
	// ステージセッティング
	this.prepare = function(x, y, blocks) {
		if(this.isPrepared) this.clear();
		Nomi.initialize(x, y);
		this.blocks.build(blocks);
		this.framecount = 0;
		this.pastType = 'norm';
		this.isPrepared = true;
	}
	
	// ステージ除去
	this.clear = function() {
		this.blocks.remove();
	}
	
	// ゲームを実行状態に
	this.play = function() {
		this.itvID = setInterval("Interval.frame();", 30);
		this.isPlay = true;
	}
	
	// ゲームを一時中断状態に
	this.pause = function() {
		clearInterval(this.itvID);
		this.isPlay = false;
	}
	
	// フレームごとの処理
	this.frame = function() {
		if(this.isPlay) {
			Nomi.move();
			var res = this.blocks.check();
			if((res == 'norm') || (res == 'blink_a') || (res == 'blink_b')) {
				this.pause();
				this.ctrl.toDead();
			}
			else if(res == 'goal') {
				this.pause();
				this.ctrl.toGoal();
			}
			if(this.pastType != res) Nomi.changeType(this.pastType, res);
			this.pastType = res;
			if(this.framecount % 100 == 0) this.blocks.blink(Math.floor(this.framecount / 100) % 2);
			this.framecount++;
		}
	}
	
	// ジャンプ
	this.jump = function() {
		if(this.isPlay) {
			Nomi.jump();
		}
	}
}

/* ====================
** 画面遷移とか
*/
function Controller() {
	this.stagedata = '';
	
	this.httpAction = function(ret) {
		eval('this.stagedata = ' + ret);
		this.setStage2();
	}
	this.setStage = function(num) {
		if(this.state != 'play') {
			this.state = 'wait';
			var elm = document.getElementById('stageSelect');
			elm.options[num - 1].selected = true;
			elm.blur();
			if(this.stage != num){
				this.stage = num;
				Scr.printStageTitle('Loading Stage Data...');
				getData(num, this);
			}
			else {
				this.setStage2();
			}
		}
	}
	
	this.setStage2 = function() {
		Scr.printStageTitle('STAGE ' + this.stage + ' : ' + this.stagedata.title);
		this.game.prepare(this.stagedata.x, this.stagedata.y, this.stagedata.blocks);
		setCookie('playingStage', ('classic|' + this.stage), getExpDate2(90));
		Scr.printMsg('Ready');
		this.state = 'ready';
	}
	
	this.toGoal = function() {
		Scr.printMsg('Goal');
		this.state = 'wait';
		setTimeout("Timeout.setStage(" + (this.stage + 1) + ");", 2000);
		this.stageSel.setFlag(this.stage - 1);
	}
	
	this.toDead = function() {
		Scr.printMsg('Failed');
		this.state = 'wait';
		setTimeout("Timeout.setStage(" + this.stage + ");", 2000);
	}
	
	this.mouseDown = function() {
		if(this.state == 'play') {
			this.game.jump();
		}
		else if(this.state == 'ready') {
			this.game.play();
			this.state = 'play';
			Scr.printMsg('');
		}
	}
	
	this.game = new Game(this);
	this.stageSel = new StgSel(this);
	Timeout = this;
}

/* ====================
** 画面情報保持
*/
function Screen() {
	this.obj = document.getElementById('mainWin');
	this.msg = document.getElementById('overLayMsg');
	this.title = document.getElementById('stageTitle');
	this.stg = document.getElementById('stageSelect');
	
	// ゲーム領域の左上の座標を取得
	var left = 0;
	var top = 0;
	for (var o = this.obj; o ; o = o.offsetParent) {
		left += (o.offsetLeft - o.scrollLeft);
		top  += (o.offsetTop - o.scrollTop);
	}
	//this.left = left;
	//this.top  = top;
	this.left=0;
	this.top=0;
	
	// 渡されたオブジェクトを移動
	this.moveObj = function(ist) {
		ist.obj.style.left = (ist.x + this.left) + 'px' ;
		ist.obj.style.top = (ist.y + this.top) + 'px';
	}
	
	// 渡されたオブジェクトを配置
	this.putObj = function(ist) {
		ist.obj.style.width = ist.width + 'px';
		ist.obj.style.height = ist.height + 'px';
		this.moveObj(ist);
	}
	
	// メッセージを書き換える
	this.printMsg = function(str) {
		this.msg.replaceChild(document.createTextNode(str), this.msg.firstChild);
	}
	
	// ステージ名を書き換える
	this.printStageTitle = function(str) {
		this.title.replaceChild(document.createTextNode(str), this.title.firstChild);
	}
}

/* ====================
** ステージセレクトリストボックス
*/
function StgSel(control) {
	this.ctrl = control;
	this.obj = document.getElementById('stageSelect');
	this.flag = new Array;
	this.httpAction = function(ret) {
		var where = (navigator.appName == "Microsoft Internet Explorer") ? -1 : null;
		this.titles = eval(ret);
		for(var i = 0; i < this.titles.length; i++) {
			var opt = document.createElement("option");
			var flag = (this.flag[i] == 0) ? '・' : 'レ';
			opt.text = flag + ' '+ (i + 1) + ' : ' + this.titles[i];
			opt.value = (i + 1);
			this.obj.add(opt, where);
		}
		
		// ページロード後に前回やってたステージを読み込む
		var cstage = getCookie('playingStage');
		//printCsl(cstage);
		if(cstage == null) cstage = 'classic|1';
		cstage = cstage.substr(cstage.indexOf('|', 0) + 1, 4);
		setTimeout("Timeout.setStage(" + cstage + ");", 100);
	}
	
	this.setFlag = function(num){
		this.flag[num] = 1;
		this.obj.options[num].text = 'レ ' + (num + 1) + ' : ' + this.titles[num];
		this.saveCookie();
	}
	
	this.loadCookie = function() {
		var fstr = getCookie('clearFlag_classic');
		if(fstr == null) fstr = '00000000000000000';
		//printCsl(fstr);
		for(var i = 0; i < fstr.length; i++) {
			var fdig = (fstr.charCodeAt(i)-48).toString(2);
			fdig = '000000'.substr(0, 6-fdig.length) + fdig;
			for(var di = 0; di < fdig.length; di++) {
				this.flag[i*6+di] = fdig.charAt(di);
			}
		}
	}
	
	this.saveCookie = function() {
		var buf = '';
		var out = '';
		for(var i = 0; i < this.flag.length; i++) {
			buf += this.flag[i];
			if(buf.length == 6) {
				out += String.fromCharCode(parseInt(buf, 2) + 48);
				buf = '';
			}
		}
		if(buf != '') {
			buf += '000000'.substr(0, 6-buf.length);
			out += String.fromCharCode(parseInt(buf, 2) + 48);
		}
		setCookie('clearFlag_classic', out, getExpDate2(90));
	}
	
	this.loadCookie();
	getData(0, this);
}

/* ====================
** いわゆるmain
*/
onload = function() {
	// スペースキーを押した時
	document.onkeypress = function(evt) {
		evt = (evt) ? evt : ((window.event) ? event : null);
		if(evt) {
			var charCode = (evt.charCode) ? (evt.charCode) : (evt.keyCode);
			if(charCode == 32) {
				control.mouseDown();
				return false;
			}
		}
	}
	
	// 画面情報をいろいろまとめておくオブジェクト作成
	Scr = new Screen();
	
	// マウスクリックの時もスペースキーと同じに
	Scr.obj.onmousedown = function() {
		control.mouseDown();
	}
	/*Scr.obj.ondblclick = function() {
		control.mouseDown();
	}*/
	
	// インスタンスを作る
	Nomi = new Player();
	xmlhttp = createXmlHttp();
	var control = new Controller();
	
	// ステージ選択
	Scr.stg.onchange = function() {
		control.setStage(Scr.stg.selectedIndex + 1);
	}
	// キーを殺す
	Scr.stg.onkeypress = function() {
		return false;
	};
}

