﻿/*
 * WINGs JS Library
 * runtime
 */

var WINGs = new Object();
WINGs.version = '0.0.0.7';

// Objectを拡張
// 注入関数
Object.inject = Object.prototype.inject = function (target,source) {
	if ( source == undefined )
	{
		source = target;
		for (var property in source)
		{
			this[property] = source[property];
		}
		return this;
	}
	else
	{
		for (var property in source)
		{
			switch(property)
			{
				case "extend":
				case "inject":
				case "implement":
				case "importTo":
				case "unimportFrom":
					break;
				default:
					target[property] = source[property];
			}
		}
		return target;
	}
};

/*
 * 若干クラスベースに書けるようにするためのObject生成関数
 * 使い方: 
 * var cls = Class();
 * cls.prototype = {
 *   ctor : function () {   //コンストラクタ
 *	  ～
 *   },
 *   ～ : function () {
 *	  ～
 *   }
 * }
 */
function Class (def) {
	var d;
	d = function () {
		this.ctor.apply(this, arguments);
	}
	for (var property in def)
	{
		d.prototype[property] = def[property];
	}
	d.inject = function (source) {
		for (var property in source)
		{
			this.prototype[property] = source[property];
		}
		return this;
	};
	if ( def["ctor"] != undefined )
	{
		d.extend = function (soruce) {
			var c = soruce;
			for (var property in this.prototype)
			{
				switch(property)
				{
					case "extend":
					case "inject":
					case "implement":
						break;
					default:
						if ( c[property] == undefined )
						{
							c[property] = this.prototype[property];
						}
				}
			}
			c["base"] = this.prototype;
			return Class(c);
		};
	}
	else
	{
		d.implement = function (soruce) {
			var c = soruce;
			for (var property in this.prototype)
			{
				switch(property)
				{
					case "extend":
					case "inject":
					case "implement":
						break;
					default:
						if ( c[property] == undefined )
						{
							//c[property] = this.prototype[property];
							throw System.MustImplementError(property);
						}
				}
			}
			return Class(c);
		};
	}
	return d;
}

/*
 * インタフェース
 * Classへのショートカット
 */
function Interface (def) {
	return Class(def);
}

/*
 * VB.NETのモジュール的な。
 * あまり意味は無い。
 * 使い方: 
 * var cls = Module({
 *   ～ : function () {
 *	  ～
 *   }
 * });
 */
function Module (def) {
	if ( def == undefined )
	{
		def = function () {};
	}
	return def;
}

/*
 * 列挙体
 * Moduleへのショートカット。
 */
function Enum (def) {
	var rt = Module(def);
	return rt;
}

/*
 * 擬似名前空間
 * 使い方: 
 * var cls = Namespace();
 * cls.～ = ～;
 */
function Namespace (def) {
	if ( def == undefined )
	{
		def = new Object();
	}
	def.importTo = function (destination)
	{
		for (var property in this)
		{
			switch(property)
			{
				case "importTo":
				case "unimportFrom":
				case "toSource":
				case "inject":
					break;
				default:
					if ( destination[property] == undefined )
					{
						destination[property] = this[property];
					}
					else
					{
						throw System.NameCollisionError(property);
					}
			}
		}
	}
	def.unimportFrom = function (destination)
	{
		for (var property in this)
		{
			switch(property)
			{
				case "importTo":
				case "unimportFrom":
				case "toSource":
				case "inject":
					break;
				default:
					if ( destination[property] != undefined )
					{
						destination[property] = undefined;
					}
			}
		}
	}
	return def;
}

/*
 * イベント(クラス)
 */
var Event = Class({
	events : Object,
	ctor : function () {
		this.events = new Array();
	},
	RaiseEvent : function () {
		for (var property in this.events)
		{
			if ( typeof this.events[property] == "function" )
			{
				this.events[property].apply(this,arguments);
			}
		}
	},
	AddHandler : function (delegate) {
		this.events.push(delegate);
	},
	RemoveHandler : function (delegate) {
		for (var property in this.events)
		{
			if ( this.events[property] == delegate )
			{
				delete this.events[property];
			}
		}
	}
});

/*
 * 名前空間インポートステートメント
 */
function imports (s) {
	s.importTo(this);
}

/*
 * 名前空間アンインポートステートメント
 */
function unimports (s) {
	s.unimportFrom(this);
}

/*
 * document.getElementByIdへのショートカット
 * IDの配列を渡すと要素の配列を返す
 */
function $ () {
	if ( arguments.length == 1 ) {
		if ( typeof arguments[0] == 'string' )
		{
			return document.getElementById(arguments[0]);
		}
		else
		{
			return arguments[0];
		}
	}
	var rt = new Array();
	for ( var i in arguments )
	{
		if ( typeof arguments[i] == 'string' )
		{
			rt[i] = document.getElementById(arguments[i]);
		}
		else
		{
			rt[i] = arguments[i];
		}
	}
	return rt;
}

// 試行関数
function $T () {
	for (var i=0;i<arguments.length;i++)
	{
		try
		{
			var lbd = arguments[i];
			return lbd();
		}
		catch (ex)
		{
		}
	}
	return undefined;
}

/*
 * メイン名前空間
 */
var System = Namespace();

/*
 * 名前空間インポート時にコリジョンが起きたときに発生する例外
 */
System.NameCollisionError = function (name) {
	var ex = new Error();
	ex.name = "System.NameCollisionError"
	ex.description = ex.message = name;
	return ex;
};

/*
 * 実装すべきメンバが実装されてないときに発生する例外
 */
System.MustImplementError = function (name) {
	var ex = new Error();
	ex.name = "System.MustImplementError"
	ex.description = ex.message = name;
	return ex;
};

System.IEnumerable = Interface({
	GetEnumerator : function () {}
});

System.IForEachable = Interface({
	foreach : function (func) {}
});

System.IEnumerator = Interface({
	Current : undefined,
	MoveNext : function () {},
	Reset : function () {}
});

Array.Enumerator = System.IEnumerator.implement({
	_c : 0,
	_p : undefined,
	ctor : function (parent) {
		this._p = new Array();
		for ( var i in parent )
		{
			this._p.push(i);
		}
		this.Current = undefined;
	},
	Current : "",
	MoveNext : function () {
		this.Current = _p[this._c];
		this._c += 1;
		return this.Current != undefined;
	},
	Reset : function () {
		this.Current = undefined;
	}
});

Object.inject(Array.prototype,System.IEnumerable.implement({
	GetEnumerator : function () {
		return new Array.Enumerator(this);
	}
}));

Object.inject(Array.prototype,System.IForEachable.implement({
	foreach : function (func) {
		var en = this.GetEnumerator();
		while ( en.MoveNext() )
		{
			func(this.Current);
		}
	}
}));
