///<reference path="all.ts"/>
module jg {
	/**
	 * リソースを読み込むくラス
	 */
	export class ResourceLoader {
		/** 読み込み対象のリソース */
		resource: Resource;

		/**
		 * コンストラクタ
		 * @param resource 読み込み対象のリソース
		 */
		constructor(resource:Resource) {
			this.resource = resource;
		}

		/**
		 * リソースを読み込む。サブクラスでオーバーライドする想定であり、このメソッドは何もしない
		 * @param url リソースのURL
		 * @param identifier リソースの識別子
		 */
		load(url:string, identifier:string) {

		}
	}

	/**
	 * 画像リソースを読み込む
	 */
	export class ImageResourceLoader extends ResourceLoader {
		/**
		 * 画像リソースを読み込む
		 * @param url 画像リソースのURL
		 * @param identifier リソースの識別子
		 */
		load(url:string, identifier:string) {
			var image = new Image();
			image.src = this.resource.structure.imageUrl(url);
			var caller = this;
			var callback = this.completed;
			image.onerror = function() {
				callback.call(caller, identifier, image, false);
			};
			image.onload = function() {
				callback.call(caller, identifier, image, true);
			};
		}

		/**
		 * 完了時のコールバック。リソースクラスに画像を登録し、読み込み完了を通知する
		 * @param name 画像の識別子
		 * @param image 読み込んだ画像
		 * @param is_success trueで成功、falseでエラー
		 */
		completed(name:string, image:HTMLImageElement, is_success:boolean) {
			if (! is_success)
				console.log("error: "+name);
			else
				this.resource.images[name] = image;

			this.resource.requestCompleted(name);
		}
	}

	/**
	 * 外部JavaScriptを読み込むクラス。
	 * このクラスではjavascriptの依存関係を解決するため、先に読み込んだリソースの読み込みが完了するまで、次のリソースを読み込むことはない
	 */
	export class ScriptResourceLoader extends ResourceLoader {
		/** ロード中かをあらわすフラグ */
		static loading:boolean;

		/**
		 * javascriptリソースを読み込む
		 * @param url javascriptリソースのURL
		 * @param identifier リソースの識別子
		 */
		load(url:string, identifier:string) {
			var callback = this.completed;
			var waitLoader = () => {
				if (ScriptResourceLoader.loading) {
					window.setTimeout(waitLoader, 100);
					return;
				}

				ScriptResourceLoader.loading = true;
				var script = <HTMLScriptElement>document.createElement("script");
				var heads = document.getElementsByTagName("head");
				if (heads.length == 0)
					throw "can not find head tag";
				script.src = url+"?"+(new Date()).getTime();
				script.onload = () => {
					callback.call(this, identifier, script, true);
					ScriptResourceLoader.loading = false;
				}
				script.onerror = () => {
					callback.call(this, identifier, script, false);
					ScriptResourceLoader.loading = false;
				}
				heads[0].appendChild(script);
			}
			waitLoader();
		}

		/**
		 * 完了時のコールバック。リソースクラスにスクリプトを登録し、読み込み完了を通知する
		 * @param name スクリプトの識別子
		 * @param image 読み込んだスクリプト
		 * @param is_success trueで成功、falseでエラー
		 */
		completed(name:string, script:HTMLScriptElement, is_success:boolean) {
			if (! is_success)
				console.log("error: "+name);
			else
				this.resource.scripts[name] = script;

			this.resource.requestCompleted(name);
		}
	}

	/**
	 * サウンドを読み込む
	 */
	export class SoundResourceLoader extends ResourceLoader {
		/**
		 * サウンドリソースを読み込む
		 * @param url サウンドリソースのURL
		 * @param identifier リソースの識別子
		 */
		load(url:string, identifier:string) {
			var audio = new Audio(null);
			audio.autoplay = false;
			audio.preload = "auto";
			audio.src = this.resource.structure.soundUrl(url);
			audio.load();
			audio.addEventListener("canplaythrough", () => {
				this.completed(identifier, audio, true);
			}, true);
			audio.addEventListener("error", () => {
				this.completed(identifier, audio, false);
			}, true);
		}

		/**
		 * 完了時のコールバック。リソースクラスにサウンドを登録し、読み込み完了を通知する
		 * @param name サウンドの識別子
		 * @param image 読み込んだサウンド
		 * @param is_success trueで成功、falseでエラー
		 */
		completed(name:string, audio:HTMLAudioElement, is_success:boolean) {
			if (! is_success)
				console.log("error: "+name);
			else
				this.resource.sounds[name] = audio;

			this.resource.requestCompleted(name);
		}
	}

	/*
	//webaudio version
	export class SoundResourceLoader extends ResourceLoader {
		load(url:string, identifier:string) {
			var request = new XMLHttpRequest();
			request.open("GET", this.resource.structure.soundUrl(url), true);
			request.responseType = "arraybuffer";

			var callback = this.completed;
			request.onload = () => {
				var context = SimpleSound.getAudioContext();
				if (context) {
					context.decodeAudioData(
						request.response,
						(decodedAudio:AudioBuffer) => {
							callback.call(this, identifier, decodedAudio, true);
						},
						() => {
							callback.call(this, identifier, null, false);
						}
					);
				} else {
					callback.call(this, identifier, null, false);
				}
			}
			request.onerror = () => {
				callback.call(this, identifier, null, false);
			}

			request.send();
		}

		completed(name:string, audio:AudioBuffer, is_success:bool) {
			if (! is_success)
				console.log("error: "+name);
			else
				this.resource.sounds[name] = audio;

			this.resource.requestCompleted(name);
		}
	}
	*/
}