enum RenderTransferMode {
	Transfer,
	Flip,
	Direct
}
class GameRenderer extends Renderer {
	buffer: HTMLCanvasElement[];
	fc: CanvasRenderingContext2D;
	bc: CanvasRenderingContext2D;
	scene: Scene;
	game: Game;
	bg:ImageData;
	container:HTMLElement;
	handler:HTMLDivElement;
	flipNo:number;
	transferMode:RenderTransferMode;
	disableClear:bool;
	frontCanvasSize:CommonSize;
	frontCanvasOffset:CommonOffset;

	constructor(game:Game, container?:HTMLElement, transferMode?:RenderTransferMode, disableBg?:bool) {
		super();
		this.game = game;
		this.container = container ? container : document.getElementById("jgame");
		if (! this.container) {
			var div = document.createElement("div");
			div.id = "jgame";
			var bodies = document.getElementsByTagName("body");
			if (bodies.length == 0)
				throw "can not initialize game engine";

			bodies[0].appendChild(div);
			this.container = div;
		}

		this.handler = <HTMLDivElement>document.createElement("div");
		this.container.appendChild(this.handler);

		this.changeTransferMode(transferMode ? transferMode : RenderTransferMode.Transfer);

		if (!disableBg) {
			this.bg = this.fc.getImageData(0, 0, this.game.width, this.game.height);
			for (var i=0; i<this.bg.data.length; i++)
				this.bg.data[i] = 255;
		}
	}

	changeFrontCanvasSize(size:CommonSize, offset?:CommonOffset) {
		this.frontCanvasSize = size;
		this.frontCanvasOffset = offset;
		this.refresh();
	}

	changeTransferMode(mode:RenderTransferMode) {
		this.transferMode = mode;
		if (this.transferMode == RenderTransferMode.Flip) {
			this.handler.style.position = "relative";
			this.handler.style.width = this.game.width + "px";
			this.handler.style.height = this.game.height + "px";
		}
		this.refresh();
	}

	changeScene(scene:Scene) {
		this.scene = scene;
	}

	flip() {
		var c = this.fc;
		this.fc = this.bc;
		this.bc = this.fc;
		this.flipNo = this.flipNo ? 0 : 1;

		//ちらつくし遅い
		//this.buffer[this.flipNo].style.zIndex = "1";
		//this.buffer[this.flipNo].style.visibility = "visible";
		//this.buffer[this.flipNo ? 0 : 1].style.zIndex = "0";
		//this.buffer[this.flipNo ? 0 : 1].style.visibility = "hidden";

		//遅い
		this.buffer[this.flipNo].style.zIndex = "1";
		this.buffer[this.flipNo ? 0 : 1].style.zIndex = "0";

		//ちらつく上にかなり遅い
		//this.buffer[this.flipNo].style.display = "block";
		//this.buffer[this.flipNo ? 0 : 1].style.display = "none";

		//ちらつく
		//this.buffer[this.flipNo].style.visibility = "visible";
		//this.buffer[this.flipNo ? 0 : 1].style.visibility = "hidden";
	}

	render() {
		// 無駄な処理だけど、更新検知ちゃんとした方が最終的には軽い、と思う
		var hasUpdate:bool = false;
		if (this.scene.layerCount == 1) {
			// 単一レイヤーの場合、バックバッファに直接描く
			var layer = this.scene.root;
			if (! layer.isUpdate()) {
			} else {
				hasUpdate = true;
				if (!this.disableClear)
					this.bc.putImageData(this.bg, 0, 0);
				this.renderParent(layer, this.bc);
				layer.reflected();
			}
		} else {
			for (var i in this.scene.layers) {
				if (this.scene.layers[i].isUpdate()) {
					hasUpdate = true;
					break;
				}
			}

			if (hasUpdate) {
				if (!this.disableClear)
					this.bc.putImageData(this.bg, 0, 0);
				for (var i in this.scene.layers) {
					var layer = this.scene.layers[i];
					if (layer.isUpdate()) {
						layer.context.clearRect(0, 0, layer.width, layer.height);
						this.renderParent(layer, layer.context);
					}
					this.bc.drawImage(layer.canvas, 0, 0);//layer.x, layer.y);
					layer.reflected();
				}
			}
		}

		if (hasUpdate) {
			if (this.filter) {
				//フィルタがある場合、転送モードの設定は無効になる
				var imageData = this.bc.getImageData(0, 0, this.game.width, this.game.height);
				this.filter.filter(imageData);
				this.fc.putImageData(imageData, 0, 0);
			} else {
				if (this.bc != this.fc) {
					this.fc.drawImage(this.buffer[1], 0, 0);
				} else if (this.transferMode == RenderTransferMode.Flip) {
					this.flip();
				}
			}
		}
	}

	refresh() {
		delete this.buffer;
		this.buffer = new HTMLCanvasElement[];

		if (this.transferMode == RenderTransferMode.Flip) {
			this.handler.innerHTML = "";
			for (var i=0; i<2; i++) {
				this.buffer[i] = window.createCanvas(this.game.width, this.game.height);;
				this.buffer[i].style.position="absolute";
				this.buffer[i].style.zIndex = i.toString();
				this.handler.appendChild(this.buffer[i]);
			}
			this.fc = this.buffer[1].getContext("2d");
			this.bc = this.buffer[0].getContext("2d");
			this.flipNo = 1;
			if (this.frontCanvasSize) {
				this.buffer[1].style.width = this.frontCanvasSize.width+"px";
				this.buffer[1].style.height = this.frontCanvasSize.height+"px";
			}
		} else if (this.transferMode == RenderTransferMode.Transfer) {
			this.handler.innerHTML = "";
			for (var i=0; i<2; i++) {
				this.buffer[i] = window.createCanvas(this.game.width, this.game.height);;
			}
			this.handler.appendChild(this.buffer[0]);
			this.fc = this.buffer[0].getContext("2d");
			this.bc = this.buffer[1].getContext("2d");
		} else {
			this.handler.innerHTML = "";
			this.buffer[0] = window.createCanvas(this.game.width, this.game.height);;
			this.handler.appendChild(this.buffer[0]);
			this.fc = this.buffer[0].getContext("2d");
			this.bc = this.fc;
		}
		if (this.frontCanvasSize) {
			this.buffer[0].style.width = this.frontCanvasSize.width+"px";
			this.buffer[0].style.height = this.frontCanvasSize.height+"px";
			if (this.frontCanvasOffset) {
				this.handler.style.position = "relative";
				this.handler.style.left = this.frontCanvasOffset.x+"px";
				this.handler.style.top = this.frontCanvasOffset.y+"px";
			}
		}
	}
}