/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var maskat = {
	/** マスカットフレームワークのバージョン識別子 */
	version: "2.0.0.v20080521",
	
	lang: {
		Object: {
			/**
			 * スコープ内から指定したパス文字列で取得できるオブジェクトを
			 * 返します。
			 *
			 * @param path パス文字列 (プロパティを "." で区切った文字列)、
			 *             または文字列の配列
			 * @param scope スコープの起点オブジェクト、省略時は window
			 *
			 * @return JavaScript オブジェクト、見つからなければ undefined
			 */
			find: function(path, scope){
				var segments = (path instanceof Array) ? path : path.split(".");
				scope = (arguments.length > 1) ? scope : window;

				if (scope) {
					for (var i = 0; i < segments.length; i++) {
						if (typeof(scope[segments[i]]) == "undefined") {
							return undefined;
						}
						scope = scope[segments[i]];
					}
				}
				return scope;
			},
			
			/**
			 * スコープ内の指定したパスにオブジェクトを生成します。
			 *
			 * パス上に該当するオブジェクトが存在しない場合には、それらの
			 * オブジェクトが自動的に生成されます。
			 *
			 * @param path パス文字列 (プロパティを "." で区切った文字列)、
			 *             または文字列の配列
			 * @param scope スコープの起点オブジェクト、省略時は window
			 *
			 * @return 生成されたオブジェクト
			 */
			create: function(path, scope){
				var segments = (path instanceof Array) ? path : path.split(".");
				scope = (arguments.length > 1) ? scope : window;

				if (scope) {
					for (var i = 0; i < segments.length; i++) {
						if (!scope[segments[i]]) {
							scope[segments[i]] = {};
						}
						scope = scope[segments[i]];
					}
				}
				return scope;
			},
			
			/**
			 * あるオブジェクトのプロパティをすべて、もう一方のオブジェクトに
			 * コピーします。
			 *
			 * @param object コピー先のオブジェクト
			 * @param properties コピーするプロパティを格納したオブジェクト
			 *
			 * @return プロパティをコピーされたオブジェクト
			 */
			populate: function(object, properties){
				for (var key in properties) {
					object[key] = properties[key];
				}
				return object;
			},

			/**
			 * 指定したオブジェクトのプロパティをすべて削除します。
			 *
			 * @param object プロパティを削除するオブジェクト
			 */
			dispose: function(object) {
				// TODO: Safari 2.02 以前には hasOwnProperty メソッドがない
				for (var property in object) {
					if (object.hasOwnProperty(property)) {
						delete object[property];
					}
				}
			}
		},
		
		Class: {
			/**
			 * 新しいクラスを宣言します。
			 *
			 * この静的メソッドは新しいクラスのコンストラクタ関数を作成し、
			 * prototype オブジェクトに指定されたプロパティを追加します。
			 *
			 * @param name クラス名を表す文字列
			 * @param properties プロパティを格納したオブジェクト
			 *
			 * @return 新しいクラスのコンストラクタ関数
			 */
			declare: function(name, properties){
				/* サブクラスが先に宣言された場合、親クラスは存在している */
				var clazz = maskat.lang.Object.find(name);
				if (!clazz) {
					/* コンストラクタ関数を生成 */
					clazz = function() {
						this.initialize.apply(this, arguments);
					};
					maskat.lang.Object.populate(clazz, this.methods);

					/* コンストラクタ関数を名前空間に格納 */
					var index = name.lastIndexOf(".");
					var namespace = (index == -1) ? window :
						maskat.lang.Object.create(name.substring(0, index));
					var simpleName = name.substring(index + 1, name.length);
					namespace[simpleName] = clazz;
				}
				
				if (properties) {
					/* 他のクラスを継承しない (ルート階層) */
					clazz.addProperties(properties);
					
					delete clazz.deferred;
					var children = clazz.subclasses;
					if (children) {
						for (var i = 0; i < children.length; i++) {
							children[i].inherit(clazz, children[i].properties);
						}
					}
				} else {
					/* 他のクラスを継承する: プロパティ追加を遅延 */
					clazz.deferred = true;
				}
				return clazz;
			},
			
			methods: {
				/**
				 * このクラスに指定したプロパティを追加します。
				 *
				 * @param properties プロパティを格納したオブジェクト
				 *
				 * @return このクラス
				 */
				addProperties: function(properties){
					/* 静的プロパティをクラスに追加 */
					if (properties._static) {
						maskat.lang.Object.populate(this, properties._static);
						delete properties._static;
					}
					
					/* プロパティを prototype オブジェクトに追加 */
					maskat.lang.Object.populate(this.prototype, properties);
					
					/*
					 * コンストラクタが省略されている場合には、デフォルトの
					 * コンストラクタを定義する
					 */
					if (!this.prototype.initialize) {
						this.prototype.initialize = maskat.lang.EmptyFunction;
					}
					
					/* クラス・イニシャライザを呼び出し */
					if (this.initialize) {
						this.initialize();
					}
					return this;
				},
				
				/**
				 * このクラスを引数 name で指定したクラスのサブクラスにして、
				 * プロパティを追加します。
				 *
				 * @param name 親クラス名を表す文字列
				 * @param properties プロパティを格納したオブジェクト
				 *
				 * @return このクラス
				 */
				extend: function(name, properties){
					var parent = maskat.lang.Object.find(name);
					if (!parent) {
						/* 親クラスが未定義の場合: クラスを宣言する */
						parent = maskat.lang.Class.declare(name);
					}
					this.superclass = parent;
					
					if (!parent.subclasses) {
						parent.subclasses = [];
					}
					parent.subclasses.push(this);
					
					if (parent.deferred) {
						/* 親クラスの初期化が完了していないため、継承を遅延 */
						this.properties = properties;
					} else {
						/* 親クラスを継承させる */
						this.inherit(parent, properties);
					}
					return this;
				},
				
				/**
				 * このクラスを引数 parent で指定したクラスのサブクラスにして、
				 * プロパティを追加します。
				 *
				 * @private
				 *
				 * @param name 親クラス名を表す文字列
				 * @param properties プロパティを格納したオブジェクト
				 */
				inherit: function(parent, properties){
					/* 親クラスの initialize 関数をダミーに置き換える */
					var base = parent.prototype.initialize;
					parent.prototype.initialize = maskat.lang.EmptyFunction;
					
					/* 親クラスを継承する */
					this.prototype = new parent();
					this.prototype.initialize = base;
					this.prototype.base = base;
					this.addProperties(properties);
					
					/* 親クラスの initialize 関数を元に戻す */
					parent.prototype.initialize = base;
					
					/* このクラスにサブクラスがある場合、自分を継承させる */
					var children = this.subclasses;
					if (children) {
						for (var i = 0; i < children.length; i++) {
							if (children[i].deferred) {
								children[i].inherit(this, children[i].properties);
							}
						}
					}
					delete this.deferred;
				}
			}
		},
		
		String: {
			/**
			 * 指定した文字列から、先頭と末尾の空白を取り除いた新しい文字列を
			 * 返します。
			 *
			 * @param string 文字列
			 *
			 * @return 文字列の先頭と末尾の空白を取り除いた文字列
			 */
			trim: function(string){
				return string.replace(/^\s+|\s+$/g, "");
			}
		},
		
		/** 空の関数 */
		EmptyFunction: function(){
		},
		
		/** 常に null を返す関数 */
		ReturnNullFunction: function(){
			return null;
		},
		
		/** 常に true を返す関数 */
		ReturnTrueFunction: function(){
			return true;
		},
		
		/** 常に false を返す関数 */
		ReturnFalseFunction: function(){
			return false;
		}
	}
};
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * XMLHttpRequest のプーリング機構を持つ通信マネージャです。
 *
 * 送信キューにコンテキスト (maskat.comm.HttpContext のインスタンス) を追加
 * することにより通信がスケジューリングされ、通信処理の各段階でコンテキスト
 * のコールバック関数が実行されます。
 */
maskat.lang.Class.declare("maskat.comm.CommunicationManager", {
	
	_static: {
		/**
		 * このクラスの唯一のインスタンスを返します。(Singleton パターン)
		 *
		 * @return このクラスの唯一のインスタンス
		 */
		getInstance: function(param) {
			var self = arguments.callee;
			if (!self.instance) {
				var sendInterval = maskat.app.getProperty("maskat.comm.sendInterval");
				var timeoutInterval = maskat.app.getProperty("maskat.comm.timeoutInterval");
				var poolSize = maskat.app.getProperty("maskat.comm.poolSize");				
				self.instance = new this(sendInterval, timeoutInterval, poolSize);
			}
			return self.instance;
		}
	},
	
	/**
	 * コンストラクタ
	 *
	 * @param sendInterval 送信キューを処理する間隔 (ms)
	 * @param timeoutInterval HTTP 応答待ちのタイムアウトを確認する間隔 (ms)
	 * @param poolSize XMLHttpRequest のプールサイズ
	 */
	initialize: function(sendInterval, timeoutInterval, poolSize){
		this.queue = [];
		this.waitings = [];
		this.completed = [];
		this.locked = false;

		/* HTTP 要求送信スレッドの生成 */		
		this.senderThread = new maskat.lang.Thread(
			this,
			this.processRequest,
			null,
			sendInterval || 100);

		/* タイムアウト確認スレッドの生成 */		
		this.timeoutThread = new maskat.lang.Thread(
			this,
			this.checkTimeout,
			null,
			timeoutInterval || 500);

		/* XMLHttpRequest プールの生成 */		
		this.initPool(poolSize || 2);
	},
	
	/**
	 * XMLHttpRequest をプールから取得します。
	 * プールがすべて利用されている場合には新しいインスタンスを生成します。
	 *
	 * @return XMLHttpRequest のインスタンス
	 */
	getXMLHttpRequest: function() {
		if (this.pool.length) {
			return this.pool.shift();
		}
		return maskat.util.CrossBrowser.createXMLHttpRequest();
	},

	/**
	 * XMLHttpRequest のプールをパラメータで指定されたサイズで初期化します。
	 */
	initPool: function(size) {
		this.poolSize = size;
		this.pool = [];
		for (var i = 0; i < size; i++) {
			this.pool.push(maskat.util.CrossBrowser.createXMLHttpRequest());
		}
	},
	
	/**
	 * XMLHttpRequest のプールサイズをパラメータで指定されているサイズまで
	 * 縮小します。
	 */
	shrinkPool: function() {
		for (var i = this.poolSize; i < this.pool.length; i++) {
			delete this.pool[i];
		}
		this.pool.length = this.poolSize;
	},
	
	/**
	 * HTTP コンテキストを送信キューに追加し、通信をスケジュールします。
	 *
	 * @param context 送信コンテキスト
	 */
	enqueue: function(context){
		this.queue.push(context);
		try {
			context.setStatus(maskat.comm.HttpContext.READY);
		} catch (e) {
			this.queue.shift();
			throw e;
		}
		/*
		 * 送信キューが空の場合は送信スレッドは停止状態しているため、
		 * スレッドを開始する
		 */
		if (this.queue.length == 1) {
			this.senderThread.start();
		}
	},

	/**
	 * 送信待ちキューからコンテキストを取得し、HTTP 要求を実行します。
	 *
	 * このメソッドは HTTP 要求送信スレッドから、パラメータで指定された
	 * インターバルで起動されます。
	 */
	processRequest: function() {
		/* 他のコンテキストが同期通信中の場合はロック開放まで待機 */
		if (this.locked) {
			return;
		}

		/* 同期通信の場合はロックを取得 */
		var context = this.queue.shift();
		this.locked = !context.async;

		/* 送信キューが空になった場合、送信スレッドを停止する */
		if (!this.queue.length) {
			this.senderThread.stop();
		}

		/* XMLHttpRequest にパラメータとコールバック関数を設定 */
		try {
			var xhr = this.getXMLHttpRequest();
			var self = this;
			xhr.open(context.method, context.url, context.async);
			xhr.onreadystatechange = function(){
				self.processResponse(context);
			};
		} catch (e) {
			this.finishProcess(context, e);
			return;
		}
		
		/*
		 * リクエストヘッダの設定:
		 * 
		 * XHR をプールから再利用した場合でも、open() メソッドを実行すると
		 * 以前に設定されていたリクエストヘッダはクリアされる
		 */
		var headers = context.requestHeaders;
		if (headers) {
			for (var n in headers) {
				xhr.setRequestHeader(n, headers[n]);
			}
		}

		/*
		 * 応答待ちリストが空の場合、タイムアウト監視スレッドは停止状態なので
		 * スレッドを開始する
		 */
		if (!this.waitings.length) {
			this.timeoutThread.start();
		}

		/* HTTP 要求を送信し、コンテキスト応答待ちリストに追加する */
		this.waitings.push(context);
		context.xhr = xhr;
		context.sentAt = (new Date()).getTime();
		
		try {
			context.setStatus(maskat.comm.HttpContext.WAIT);
		} catch (e) {
			/*
			 * openされたXHRはsend完了もしくはabortされるまで占有されます。
			 * FireFoxではopen後のabortで発生するreadyStateはcomplete(4)
			 */
			try {
				context.xhr.onreadystatechange = null;
			} catch (ex) {
				context.xhr.onreadystatechange = function() {};
			}
			context.xhr.abort();
			this.finishProcess(context, e);
			return;
		}
		xhr.send(context.requestMessage);

		/*
		 * Firefox の同期通信は送信処理が終わるまで send 関数から復帰せず、
		 * onreadystatechange 関数を呼び出さない
		 */
		if (navigator.appName == "Netscape" && !context.async) {
			if (context.status == maskat.comm.HttpContext.WAIT) {
				this.processResponse(context);
			}
		}
	},
	
	/**
	 * レスポンス処理
	 * サーバとのレスポンス処理を行うためのコールバック関数
	 *
	 * @param xhr XMLHttpRequest
	 * @param context 送信コンテキスト
	 */
	processResponse: function(context) {
		var xhr = context.xhr;
		/*
		 * FireBugを利用している場合、処理済リクエストのonreadystatechange
		 * が再度呼び出される。context.xhrは既に削除されており存在しない。
		 */
		if (!xhr || context.status != maskat.comm.HttpContext.WAIT) {
			return;
		}
		try {
			if (xhr.readyState == 4) {
				if (xhr.status == 200) {
					maskat.util.CrossBrowser.checkParseError(xhr);

					context.responseMessage = xhr.responseText;
					context.responseXML = xhr.responseXML;
					context.responseHeaders = this.parseResponseHeaders(
						xhr.getAllResponseHeaders());
					
					/*
					 * ロック中 (同期通信中) に非同期処理が完了した場合には
					 * 同期通信の完了を待つ
					 */
					if (context.async && this.locked) {
						this.completed.push(context);
					} else {
						context.setStatus(maskat.comm.HttpContext.COMPLETE);
					}
				} else if (xhr.status != 0) {
					maskat.util.CrossBrowser.checkHttpError(xhr);
				}
				this.finishProcess(context);
			}
		} catch (e) {
			var error = e;
			if (!(e instanceof maskat.lang.Error)) {
				error = maskat.util.CrossBrowser.getHttpError(xhr);
				if (!error) {
					error = e;
				}
			}
			this.finishProcess(context, error);
		}
	},
	
	/**
	 * レスポンスヘッダ文字列を解析し、ヘッダ名と値のペアを要素とする配列を
	 * 返します。
	 *
	 * @param headers すべてのレスポンスヘッダを含んだ文字列
	 *     "name1:value1\nname2:value2\n..."
	 *
	 * @return レスポンスヘッダの解析済み配列
	 *     {
	 *         name1: "value1",
	 *         name2: "value2",
	 *         ...
	 *     }
	 */
	parseResponseHeaders: function(headers) {
		if (!headers) {
			return null;
		}

		var result = {};
		var lines = headers.split(/\r?\n/);
		var pair;
		for (var i = 0; i < lines.length; i++) {
			if (lines[i].length > 1) {
				/* レスポンスヘッダ行を名前／値ペアに分割する */
				pair = lines[i].split(/\s*:\s*/);
				if (result[pair[0]]) {
					result[pair[0]] = result[pair[0]] + " " +
						pair[1].replace(/, /g, " ");
				} else {
					result[pair[0]] = pair[1].replace(/, /g, " ");
				}
			}
		}
		return result;
	},
	
	/**
	 * 送信プロセス終了処理
	 *
	 * @param context 通信が終了したコンテキスト
	 * @param error 発生したエラー（正常時はundefined)
	 */
	finishProcess: function(context, error) {
		/*
		 * エラー発生によるfinishProcess呼び出し
		 * 処理中断 (InterruptedError)による呼び出しはステータス変更を行わない
		 */
		if (error && !(error instanceof maskat.lang.InterruptedError)) {
			context.error = error;
			try {
				context.setStatus(maskat.comm.HttpContext.ERROR);
			} catch (ex) {
				context.error.cause = ex;
			}
		}
		/* XMLHttpRequest をプールに戻す */
		if (context.xhr) {
			this.pool.push(context.xhr);
			delete context.xhr;
		}
		/* 応答待ちリストからコンテキストを削除 */
		for (var i = 0; i < this.waitings.length; i++) {
			if (context === this.waitings[i]) {
				this.waitings.splice(i, 1);
				break;
			}
		}
		
		/* 応答待ちリストが空の場合、タイムアウト監視スレッドを停止 */
		if (!this.waitings.length) {
			this.waitings.length = 0;
			this.timeoutThread.stop();
			this.shrinkPool();
		}

		/*
		 * 同期通信が終了した場合、ロックフラグの解除を待っている非同期通信の
		 * 結果をリリースする
		 */
		if (!context.async) {
			for (var i = 0; i < this.completed.length; i++) {
				try {
					this.completed[i].setStatus(maskat.comm.HttpContext.COMPLETE);
				} catch (e) {
					this.completed[i].error = e;
					try {
						this.completed[i].setStatus(maskat.comm.HttpContext.ERROR);
					} catch (ex) {
						this.completed[i].error.cause = ex;
					}
				}
			}
			this.completed.length = 0;
			this.locked = false;
		}
	},
	
	/**
	 * HTTP 応答待ちのキューを走査し、タイムアウト時間が経過している場合に
	 * タイムアウト処理を発生させます。
	 *
	 * このメソッドはタイムアウト処理スレッドから、パラメータで指定された
	 * インターバルで起動されます。
	 */
	checkTimeout: function() {
		var context;
		for (var i = 0; i < this.waitings.length; i++) {
			context = this.waitings[i];
			if (context.isTimeout()) {
				try {
					context.setStatus(maskat.comm.HttpContext.TIMEOUT);
				} catch (e) {
					context.error = e;
				}
				/*
				 * abortを実行するとonreadystatechange関数をIEはstatus=0で呼び出します。
				 * FireFoxではNS_ERROR_NOT_AVAILABLEエラーとして呼び出されるのでonready
				 * statechange関数を無効にしてabortを呼んでいます。
				 */
				try {
					context.xhr.onreadystatechange = null;
				} catch (ex) {
					context.xhr.onreadystatechange = function() {};
				}
				context.xhr.abort();
				this.finishProcess(context);
			}
		}
	}
});

/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.comm.HttpContext", {

	/** 通信ステータスを表す定数値の定義 */
	_static: {
		INIT: "init",
		READY: "ready",
		WAIT: "wait",
		COMPLETE: "complete",
		ERROR: "error",
		TIMEOUT: "timeout"
	},

	initialize: function(method, url, param){
		this.status = maskat.comm.HttpContext.INIT;
		
		this.url = url;
		this.method = method || "GET";
		this.async = param.async;
		this.sentAt = null;
		this.timeout = param.timeout? param.timeout : 0;
		this.requestHeaders = {};
		this.requestMessage = param.request;
		this.responseHeaders = [];
		this.responseMessage = "";
		this.error = null;
		
		this.requestHeaders["Content-Type"] = "application/xml";
		this.requestHeaders["If-Modified-Since"] = "Thu, 01 Jun 1970 00:00:00 GMT";

		var headers = param.headers;
		if (headers) {
			for (var i = 0; i < headers.length; i++) {
				this.requestHeaders[headers[i].name] = headers[i].value;
			}
		}
	},

	send: function() {
		maskat.comm.CommunicationManager.getInstance().enqueue(this);
	},

	setStatus: function(status) {
		if (this.status != status) {
			this.status = status;
			this.stateChanged();
		}
	},

	stateChanged: function(){
		switch (this.status) {
		case maskat.comm.HttpContext.WAIT:
			this.onWait();
			break;
		case maskat.comm.HttpContext.COMPLETE:
			this.onComplete();
			break;
		case maskat.comm.HttpContext.TIMEOUT:
			this.onTimeout();
			break;
		case maskat.comm.HttpContext.ERROR:
			this.onError();
			break;
		default:
			break;
		}
	},

	/**
	 * HTTP 要求を送信する直前に呼び出されるコールバックメソッドです。
	 */
	onWait: function(){
		/* NOP */
	},
	
	/**
	 * HTTP 応答を受信した直後に呼び出されるコールバックメソッドです。
	 */
	onComplete: function(){
		/* NOP */
	},
	
	/**
	 * HTTP 要求の応答待ちがタイムアウトした場合に呼び出されるコールバック
	 * メソッドです。
	 */
	onTimeout: function(){
		/* NOP */
	},

	/**
	 * 通信エラー発生時に呼び出されるコールバックメソッドです。
	 *
	 * このメソッドの実行時は、コンテキストの error プロパティで発生した
	 * エラーを参照することができます。
	 */
	onError: function(){
		/* NOP */
	},

	/**
	 * HTTP 要求の応答待ちがタイムアウトしているかどうかを返します。
	 *
	 * @return 応答待ちがタイムアウトしている場合は true
	 */
	isTimeout: function(){
		if (!this.sentAt || !this.timeout) {
			return false;
		}
		var now = (new Date()).getTime();
		return 	(now - this.sentAt) >= this.timeout;
	}
	
});


/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.control.ApplicationController", {

	initialize: function(){
		this.app = null;
		this.init = null;
		this.commands = {};
	},

	setApplication: function(app){
		this.app = app;
	},

	getCommand: function(event){
		var path = [event.widgetId, event.type, (event.branch || "")];
		return maskat.lang.Object.find(path, this.commands);
	},

	addCommand: function(command){
		var branch = command.branch || "";
		var scope = maskat.lang.Object.create(
			[command.widgetId, command.eventType], this.commands);
		scope[branch] = command;
	},

	start: function() {
		if (this.init) {
			this.init.execute(this.app);
		}
	},

	handleEvent: function(event){
		var command = this.getCommand(event);
		if (command) {
			command.execute(this.app);
		}
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.control.Command", {

	execute: function(app) {
		/* NOP */
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.control.CommandSet")
	.extend("maskat.control.Command", {

	initialize: function() {
		this.priorCommands = null;
		this.commands = null;
	},

	execute: function(app) {
		/* 優先コマンド (JavaScript/CSS ロード) の実行 */
		if (this.priorCommands) {
			for (var i = 0; i < this.priorCommands.length; i++) {
				this.executeCommand(app, this.priorCommands[i]);
			}
		}	

		/* 通常コマンドの実行 */
		if (this.commands) {
			for (var j = 0; j < this.commands.length; j++) {
				this.executeCommand(app, this.commands[j]);
			}
		}	
	
	},

	executeCommand: function(app, command){
		try {
			command.execute(app);
		} catch (e) {
			var logger = maskat.log.LogFactory.getLog("maskat.control");
			var msg = e.getMessages ? e.getMessages().join("\n") : e.message;
			logger.error(msg);
		}
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.control.HideLayoutCommand")
	.extend("maskat.control.Command", {

	initialize: function(layoutId) {
		this.layoutId = layoutId;
	},

	execute: function(app) {
		var layout = app.getLayout(this.layoutId);
		if (layout) {
			layout.setVisible(false);
		}
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.control.LoadJavaScriptCommand", {

	initialize: function() {
		this.url = null;
		this.async = false;
	},

	execute: function(app) {
		if (!this.url.match(/.js$/)) {
			this.url = this.url + ".js";
		}

		app.loadJavaScript(this.url, this.async);
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.control.LoadLayoutCommand")
	.extend("maskat.control.Command", {

	initialize: function() {
		this.layoutURL = null;
		this.eventURL = null;
		this.elementId = null;
		this.visible = null;
	},

	execute: function(app) {
		if (!this.eventURL) {
			this.eventURL = this.layoutURL.replace(/\.xml$/, "_e.xml");
		}
		
		var element = document.getElementById(this.elementId);
		app.loadLayout(this.layoutURL, this.eventURL, element, this.visible);
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.control.LoadStyleSheetCommand")
	.extend("maskat.control.Command", {

	initialize: function() {
		this.url = null;
	},

	execute: function(app) {
		if (!this.url.match(/.css$/)) {
			this.url = this.url + ".css";
		}

		app.loadStyleSheet(this.url);
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.control.ShowLayoutCommand")
	.extend("maskat.control.Command", {

	initialize: function(layoutId) {
		this.layoutId = layoutId;
	},

	execute: function(app) {
		var layout = app.getLayout(this.layoutId);
		if (layout) {
			layout.setVisible(true);
		}
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.control.TransitionXMLReader")
	.extend("maskat.xml.XMLObjectBinder", {

	_static: {
		getInstance: function() {
			var self = arguments.callee;
			if (!self.instance) {
				self.instance = new this();
			}
			return self.instance;
		}
	},
	
	initialize: function(){
		this.base({
			"#document": {
				children: {
					transitionDef: {}
				}
			},

			transitionDef: {
				type: maskat.control.ApplicationController,
				children: {
					init: { property: "init" },
					transition: {
						property: "transitions",
						method: "addCommand",
						repeat: true
					}
				}
			},

			init: {
				type: maskat.control.CommandSet,
				children: {
					loadJS: { property: "priorCommands", repeat: true },
					loadCSS: { property: "priorCommands", repeat: true },
					loadLayout: { property: "commands", repeat: true }
				}
			},

			transition: {
				type: maskat.control.CommandSet,
				attributes: {
					component: { type: "string", required: true, property: "widgetId" },
					event: { type: "string", property: "eventType" },
					branch: { type: "string" }
				},
				children: {
					loadJS: { property: "priorCommands", repeat: true },
					loadCSS: { property: "priorCommands", repeat: true },
					loadLayout: { property: "commands", repeat: true },
					removeLayout: { property: "commands", repeat: true },
					showLayout: { property: "commands", repeat: true },
					hideLayout: { property: "commands", repeat: true }
				}
			},
			
			loadLayout: {
				type: maskat.control.LoadLayoutCommand,
				attributes: {
					xmlFile: { type: "string", required: true, property: "layoutURL" },
					target: { type: "string", property: "elementId" },
					show: { type: "boolean", defaultValue: false, property: "visible" }
				}
			},

			loadJS: {
				type: maskat.control.LoadJavaScriptCommand,
				attributes: {
					fileName: { type: "string", required: true, property: "url"  }
				}
			},

			loadCSS: {
				type: maskat.control.LoadStyleSheetCommand,
				attributes: {
					fileName: { type: "string", required: true, property: "url"  }
				}
			},

			showLayout: {
				type: maskat.control.ShowLayoutCommand,
				attributes: {
					layout: { type: "string", required: true, property: "layoutId"  }
				}
			},

			hideLayout: {
				type: maskat.control.HideLayoutCommand,
				attributes: {
					layout: { type: "string", required: true, property: "layoutId"  }
				}
			},

			removeLayout: {
				type: maskat.control.UnloadLayoutCommand,
				attributes: {
					layout: { type: "string", required: true, property: "layoutId" }
				}
			}
		});
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.control.UnloadLayoutCommand")
	.extend("maskat.control.Command", {

	initialize: function(layoutId) {
		this.layoutId = layoutId;
	},

	execute: function(app) {
		app.unloadLayout(this.layoutId);
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.core.Application", {

	_static: {
		/**
		 * 起動ステージ 0:
		 * 
		 * この関数は maskat.js の読み込み時に実行され、HTML 文書の読み込みが
		 * 完了後にできるだけ早い段階で起動ステージ 1 (bootstrap 関数) が実行
		 * されるようにハンドラ関数 (bootstrap) を登録します。
		 */
		initialize: function(){
			if (navigator.userAgent.indexOf("MSIE") != -1) {
				document.write('<script id="__init_script" defer="true" src="//:"></script>');
			}
			
			/*
			 * Firefox (Gecko) の場合:
			 *
			 * DOMContentLoaded イベントを利用し、onload イベントの発生前に
			 * マスカットフレームワークを初期化する
			 */
			if (document.addEventListener) {
				document.addEventListener("DOMContentLoaded", this.bootstrap, false);
			}
			
			/*
			 * Internet Explorer の場合:
			 *
			 * script 要素の defer 属性と onreadystatechange イベントを利用し、
			 * onload イベントの発生前にマスカットフレームワークを初期化する
			 */
			if (document.getElementById) {
				var deferScript = document.getElementById("__init_script");
				if (deferScript) {
					deferScript.onreadystatechange = function() {
						if (this.readyState == "complete") {
							maskat.core.Application.bootstrap();
						}
					};

					/* 読み込みが既に完了しているかどうかを確認 */
					deferScript.onreadystatechange();
					deferScript = null;
				}
			}
			
			/* その他のブラウザでは onload イベントを利用 */
			window.onload = this.bootstrap;
		},
		
		/**
		 * 起動ステージ 1:
		 * 
		 * HTML 文書の読み込み完了後、onload イベントの発生より以前の段階で
		 * 実行されます。プラグインのインストールとアプリケーションの起動を
		 * 行います。
		 */
		bootstrap: function(){
			/* この関数が 1 回だけ実行されることを保証する */
			var self = arguments.callee;
			if (self.initialized) {
				return;
			}
			self.initialized = true;
		
			/* フレームワークパスを自動検出して maskat.location に格納 */
			var scripts = document.getElementsByTagName("script");
			var regexp = /\/core\/maskat\.js$/;

			for (var i = 0; i < scripts.length; i++) {
				var src = scripts[i].getAttribute("src");
				var match = src && src.match(regexp);
				if (match) {
					maskat.location = src.substring(0, match.index + 1);
					break;
				}
			}

			try {
				/* 設定ファイルの読み込み */
				var app = maskat.core.Application.getInstance();
				app.loadProperties(maskat.location + "properties.json");
				maskat.app = app;

				/* プラグインマネージャの生成 */
				var manager = new maskat.core.PluginManager(app.getProperty("maskat.core.plugins"));

				/*
				 * すべてのプラグインのロード完了時にアプリケーションの実行を
				 * 開始するようにコールバック関数を設定
				 */
				manager.onReady = function() {
					manager.start();
					app.loadController("transition.xml");
					app.start();
				};
				manager.install();
			} catch (e) {
				var logger = maskat.log.LogFactory.getLog("maskat.core");
				logger.error(e.getMessages ? e.getMessages().join("\n") : e.message);
			}
		},
		
		/**
		 * このクラスの唯一のインスタンスを返します。(Singleton パターン)
		 *
		 * @return このクラスの唯一のインスタンス
		 */
		getInstance: function(){
			var self = arguments.callee;
			if (!self.instance) {
				self.instance = new this();
			}
			return self.instance;
		}
	},
	
	/**
	 * 新しいアプリケーションのインスタンスを生成します。
	 */
	initialize: function(){
		this.layouts = {};
		this.stylesheets = null;
		this.scripts = null;
		this.controller = null;
		
		this.properties = new maskat.util.Properties({
			"maskat.core.plugins": { type: "object", defaultValue: {} },
			"maskat.comm.sendInterval": { type: "number", defaultValue: 100 },
			"maskat.comm.timeoutInterval": { type: "number", defaultValue: 500 },
			"maskat.comm.poolSize": { type: "number", defaultValue: 2 },
			"maskat.log.default.level": { type: "string", defaultValue: "INFO" },
			"maskat.log.factory": {
				type: "string",
				defaultValue: "maskat.log.SimpleLogFactory"
			},
			"maskat.ui.dialog.factory": {
				type: "string",
				defaultValue: "maskat.ui.JavaScriptDialogFactory"
			}
		});
	},
	
	/**
	 * アプリケーションのプロパティを指定した URL から JSON フォーマットで
	 * 読み込みます。
	 * 
	 * @param url プロパティファイル (JSON 形式) の URL
	 */
	loadProperties: function(url){
		this.properties.load(url);
	},

	/**
	 * マスカットアプリケーションのプロパティを取得します。
	 * 
	 * @param key プロパティキー
	 */
	getProperty: function(key){
		return this.properties.getProperty(key);
	},

	/**
	 * アプリケーションの実行を開始します。
	 */
	start: function(){
		/* アプリケーションコントローラを起動 */
		if (this.controller) {
			this.controller.start();
		}
	},

	/**
	 * 画面遷移定義 XML を読み込んで、アプリケーションコントローラを
	 * 構成します。
	 * 
	 * @param url 画面遷移定義 XML の URL
	 */
	loadController: function(url){
		var controller;
		try {
			controller = maskat.control.TransitionXMLReader.getInstance().load(url);
			controller.setApplication(this);
			this.controller = controller;
		} catch (e) {
			var cause = e.cause;
			if (e.cause && e.cause.key == "HTTP_404") {
				/*
				 * 画面遷移定義 XML が見つからない (HTTP ステータス 404) の
				 * 場合はエラーではなく、警告メッセージを表示
				 */
				var logger = maskat.log.LogFactory.getLog("maskat.core");
				logger.warn(e.getMessages ? e.getMessages().join("\n") : e.message);
			} else {
				/* その他の例外は呼び出し元にスロー */
				throw e;
			}
		}
		return controller;
	},
	
	/**
	 * 指定したレイアウト ID に対応するレイアウトを取得します。
	 * 
	 * @param layoutId レイアウト ID
	 * 
	 * @return 指定したレイアウト ID に対応するレイアウト、
	 *          存在しない場合は undefined
	 */
	getLayout: function(layoutId){
		return this.layouts ? this.layouts[layoutId] : undefined;
	},
	
	/**
	 * 指定したレイアウト ID に対応するレイアウトをロードします。
	 * 
	 * @param layoutURL レイアウト定義 XML の URL
	 * @param eventURL イベント定義 XML の URL
	 * @param element レイアウトをロードする HTML 要素
	 * @param visible レイアウトを表示する場合は true、非表示の場合は false
	 * 
	 * @return ロードされたレイアウト
	 */
	loadLayout: function(layoutURL, eventURL, element, visible){
		var layout;

		/* すでにロード済みの場合、レイアウトの表示／非表示を設定する */
		for (var name in this.layouts) {
			layout = this.layouts[name];
			if (layout.url == layoutURL) {
				layout.setVisible(visible);
				return layout;
			}
		}	

		/* レイアウトを新規にロードする */
		layout = maskat.layout.LayoutXMLReader.getInstance().load(layoutURL);
		layout.url = layoutURL;
		this.layouts[layout.getWidgetId()] = layout;
		
		if (eventURL) {
			var dispatcher = maskat.event.EventXMLReader.getInstance().load(eventURL);
			layout.addEventListener(dispatcher);
			dispatcher.setController(this.controller);
		}

		layout.load(element, visible);
		return layout;
	},
	
	/**
	 * 指定したレイアウト ID に対応するレイアウトをアンロードします。
	 * 
	 * @param layoutId レイアウト ID
	 */
	unloadLayout: function(layoutId){
		var layout = this.getLayout(layoutId);
		if (layout) {
			layout.unload();
			delete this.layouts[layoutId];
		}
	},
	
	/**
	 * 新しい CSS スタイルシートを読み込みます。
	 * 
	 * @param url CSS スタイルシート (*.css) の URL
	 */
	loadStyleSheet: function(url){
		if (this.stylesheets && this.stylesheets[url]) {
			return;
		}
		
		/* head 要素の子要素として style 要素を追加 */
		var link = document.createElement("link");
		link.rel = "stylesheet";
		link.type = "text/css";
		link.href = url;
		
		var head = document.getElementsByTagName("head")[0];
		head.appendChild(link);
		
		if (!this.stylesheets) {
			this.stylesheets = {};
		}
		this.stylesheets[url] = link;
	},
	
	/**
	 * 新しい JavaScript ファイルを読み込みます。
	 * 
	 * 非同期読み込みの場合、このメソッドの呼び出し直後には JavaScript が
	 * 解析されていないため、読み込んだスクリプトの内容を利用できません。
	 * このため、setTimeout 関数などを用いて解析を待つ必要があります。
	 * 
	 * @param url JavaScript ファイル (*.js) の URL
	 * @param async 非同期読み込みの場合は true
	 */
	loadJavaScript: function(url, async){
		if (async) {
			if (this.scripts && this.scripts[url]) {
				return;
			}

			/* head 要素の子要素として script 要素を追加 */
			var script = document.createElement("script");
			script.type = "text/javascript";
			script.src = url;
			var head = document.getElementsByTagName("head")[0];
			head.appendChild(script);
			
			if (!this.scripts) {
				this.scripts = {};
			}
			this.scripts[url] = script;
		} else {
			/*
			 * HTTP GET メソッドで取得した JavaScript ソースコードを
			 * グローバルスコープでソースコードを eval() する
			 */
			var source = maskat.util.CrossBrowser.getTextFrom(url);
			this.loadJavaScriptFromString(source, false);
		}
	},

	/**
	 * JavaScript ソースコードを文字列から読み込みます。
	 *
	 * 非同期読み込みの場合、このメソッドの呼び出し直後には JavaScript が
	 * 解析されていないため、読み込んだスクリプトの内容を利用できません。
	 * このため、setTimeout 関数などを用いて解析を待つ必要があります。
	 * 
	 * @param source JavaScript ソースコード文字列
	 * @param async 非同期読み込みの場合は true
	 */
	loadJavaScriptFromString: function(source, async){
		if (async) {
			/* head 要素の子要素として script 要素を追加 */
			var script = document.createElement("script");
			script.type = "text/javascript";
			script.text = source;
			var head = document.getElementsByTagName("head")[0];
			head.appendChild(script);
		} else {
			/* グローバルスコープでソースコードを eval する */
			if (window.execScript) {
				window.execScript(source, "JavaScript");
			} else if (window.eval) {
				window.eval(source);
			} else {
				eval(source);
			}
		}
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.core.Plugin", {

	_static: {
		/** プラグインの動作状態を表す定数 */
		INIT: 1,
		INSTALL: 2,
		LOADING: 3,
		READY: 4,
		RUNNING: 5,

		/** プラグインのクラスを登録するレジストリ */
		registry: {},		

		/**
		 * レジストリにプラグインの実装クラスを登録します。
		 *
		 * プラグインの実装クラスは maskat.core.Plugin クラスを継承し、引数
		 * なしのコンストラクタを持っている必要があります。
		 * 
		 * @param clazz プラグインの実装クラス
		 */
		register: function(clazz) {
			var pluginId = clazz.prototype.getPluginId();
			this.registry[pluginId] = clazz;
		}
	},

	/**
	 * コンストラクタ
	 */
	initialize: function() {
		this.status = maskat.core.Plugin.INIT;
		this.properties = new maskat.util.Properties();
	},

	/**
	 * プラグインの実行状態を返します。
	 *
	 * @return プラグインの実行状態
	 */
	getStatus: function(status) {
		return this.status;
	},

	/**
	 * プラグインの実行状態を設定します。
	 *
	 * @param status プラグインの実行状態
	 */
	setStatus: function(status) {
		this.status = status;
	},

	/**
	 * プラグインのプロパティ値を取得します。
	 *
	 * @return 指定したキーに対応するプロパティ値 
	 */
	getProperty: function(key) {
		return this.properties.getProperty(key);
	}, 

	/**
	 * プラグインのプロパティを設定します。
	 *
	 * @param key プロパティキー
	 * @param value プロパティの値
	 */
	setProperty: function(key, value) {
		this.properties.setProperty(key, value);
	}, 

	/**
	 * プラグインのプロパティをプロパティキーと値が対になったオブジェクトで
	 * まとめて設定します。
	 *
	 * @param values プロパティキーと値が対になったオブジェクト 
	 */
	setProperties: function(values) {
		this.properties.setProperties(values);
	}, 

	/**
	 * プラグイン識別子を返します。
	 * 
	 * @return プラグイン識別子
	 */
	getPluginId: function() {
		return null;
	},

	/**
	 * プラグインのバージョン識別子を返します。
	 * 
	 * @return プラグインのバージョン識別子
	 */
	getVersion: function() {
		return null;
	},

	/**
	 * このプラグインが別のプラグインに依存している場合、依存している
	 * プラグインの識別子を配列で返します。
	 *
	 * @return プラグイン識別子を要素とする配列、依存関係がなければ null
	 */
	getDependencies: function() {
		return null;
	},

	/**
	 * プラグインのロードが完了したかどうかを返します。
	 * 
	 * このメソッドが true を返すまでマスカットアプリケーションの実行は
	 * 開始しません。
	 * 
	 * @return ロードが完了していれば true、それ以外の場合は false
	 */
	isLoaded: function() {
		return true;
	},

	/**
	 * プラグインに必要なリソースをロードします。
	 * 
	 * @param app このプラグインを使用するマスカットアプリケーション
	 */
	load: function() {
		/* NOP */
	},

	/**
	 * プラグインの実行を開始します。
	 */
	start: function() {
		/* NOP */
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.core.PluginManager", {

	/**
	 * コンストラクタ
	 */
	initialize: function(properties) {
		this.plugins = {};
		this.properties = properties || {};
		this.loader = new maskat.lang.Thread(this, this.process, null, 100);
	},

	install: function() {
		for (var pluginId in this.properties) {
			if (this.properties[pluginId].enabled) {
				this.installPlugin(pluginId);
			}
		}

		/* プラグインローダーのスレッドを起動 */
		if (!this.loader.isRunning()) {
			this.loader.start();
		}
	},

	start: function() {
		for (var pluginId in this.plugins) {
			this.startPlugin(pluginId);
		}
	},

	/**
	 * プラグインローダーのスレッドから一定間隔で実行されるメソッドです。
	 *
	 * プラグインごとに動作ステータスを確認し、ライフサイクルを管理します。
	 * 動作ステータスは以下のように進行します。
	 *
	 *  - INIT:    plugin.js を読み込み中
	 *  - INSTALL: プラグイン (plugin.js) を読み込み中 
	 *  - LOADING: リソース (JavaScript/CSS など) を読み込み中
	 *  - READY:   リソースのロードが完了し、実行可能
	 *  - RUNNING: プラグインを実行中
	 */
	process: function() {
		try {
			/* 各プラグインの状態によって処理を分岐 */
			for (var pluginId in this.plugins) {
				var plugin = this.getPlugin(pluginId); 
				if (plugin) {
					switch (plugin.getStatus()) {
					case maskat.core.Plugin.INSTALL:
						/* インストール済みの場合はロード処理を実行 */
						this.loadPlugin(pluginId);
						break;
			
					case maskat.core.Plugin.LOADING:
						/* ロード中の場合はロードが完了しているか確認 */
						if (plugin.isLoaded()) {
							plugin.setStatus(maskat.core.Plugin.READY); 
						}
						break;
					}
				} else {
					/*
					 * プラグイン (plugin.js) の自動読み込み中の場合は
					 *インストール処理を再試行
					 */
					this.installPlugin(pluginId);
				}
			}
			
			/* すべてのプラグインのロードが完了した場合、スレッドを停止 */
			if (this.isReady()) {
				this.loader.stop();
				this.onReady();
			}
		} catch (e) {
			this.loader.stop();
			var logger = maskat.log.LogFactory.getLog("maskat.core");
			logger.error(e.getMessages ? e.getMessages().join("\n") : e.message);
		}
	},

	/**
	 * すべてのプラグインのロードが完了しているかどうかを返します。
	 *
	 * @return ロードが完了している場合は true, それ以外の場合は false
	 */
	isReady: function() {
		for (var pluginId in this.plugins) {
			var plugin = this.getPlugin(pluginId);
			if (!plugin || plugin.getStatus() < maskat.core.Plugin.READY) {
				return false;
			}
		}
		return true;
	},

	/**
	 * すべてのプラグインのロード完了時に実行されるコールバックメソッドです。
	 *
	 * このメソッドはサブクラスやインスタンスメソッドでオーバーライドされる
	 * ことを意図しています。
	 */
	onReady: function() {
		/* NOP */
	},

	/**
	 * 指定されたプラグイン識別子を持つプラグインを検索し、プラグインの
	 * インスタンスを返却します。
	 * 
	 * @return プラグインのインスタンス
	 */
	getPlugin: function(pluginId) {
		return this.plugins[pluginId];
	},

	/**
	 * 新しいプラグインをインストールします。
	 *
	 * @param pluginId プラグイン識別子
	 */
	installPlugin: function(pluginId) {
		var pluginClass = maskat.core.Plugin.registry[pluginId]; 
		var plugin = this.getPlugin(pluginId);

		/* プラグインクラスが未登録の場合、plugin.js を自動的に読み込む */		
 		if (!pluginClass) {
 			if (typeof(plugin) == "undefined") {
				maskat.app.loadJavaScript(
					maskat.location + pluginId + "/plugin.js", true);
				this.plugins[pluginId] = false;
			}
			return;
		}

		/* プラグインを取得 (または生成) する */
		if (!plugin) {
			plugin = new pluginClass();
			this.plugins[pluginId] = plugin; 
		}

		/* すでにインストール処理を開始済みの場合は何もしない */
		if (plugin.getStatus() >= maskat.core.Plugin.INSTALL) {
			return;
		}
		plugin.setStatus(maskat.core.Plugin.INSTALL);
		plugin.setProperties(this.properties[pluginId]);

		/* 依存関係にあるプラグインをインストール */
		var dependencies = plugin.getDependencies();
		if (dependencies) {
			for (var i = 0; i < dependencies.length; i++) {
				this.installPlugin(dependencies[i]);
			}
		}
	},

	/**
	 * プラグインのロード処理を実行します。
	 *
	 * 指定されたプラグインが他のプラグインに依存している場合、依存している
	 * プラグインのロード後にロード処理が開始されます。
	 *
	 * @param pluginId プラグイン識別子
	 */
	loadPlugin: function(pluginId) {
		var plugin = this.getPlugin(pluginId);

		/* すでにロード処理を開始済みの場合は何もしない */
		if (plugin.getStatus() >= maskat.core.Plugin.LOADING) {
			return;
		}

		/* 依存関係にあるプラグインのロード完了まで待機する */
		var dependencies = plugin.getDependencies();
		if (dependencies) {
			for (var i = 0; i < dependencies.length; i++) {
				var dependee = this.getPlugin(dependencies[i]);
				if (!dependee || dependee.getStatus() < maskat.core.Plugin.READY) {
					return;
				}
			}
		}

		/* プラグインのロード処理を実行 */
		if (!plugin.isLoaded()) {
			plugin.load();
		}
		plugin.setStatus(maskat.core.Plugin.LOADING);
	},

	/**
	 * プラグインの実行を開始します。
	 *
	 * 指定されたプラグインが他のプラグインに依存している場合、依存している
	 * プラグインの実行後に実行が開始されます。
	 *
	 * @param pluginId プラグイン識別子
	 */
	startPlugin: function(pluginId){
		var plugin = this.getPlugin(pluginId);

		/* すでに実行中の場合は何もしない */
		if (plugin.getStatus() >= maskat.core.Plugin.RUNNING) {
			return;
		}
		plugin.setStatus(maskat.core.Plugin.RUNNING);

		/* 依存関係にあるプラグインを再帰的に実行 */
		var dependencies = plugin.getDependencies();
		if (dependencies) {
			for (var i = 0; i < dependencies.length; i++) {
				this.startPlugin(dependencies[i]);
			}
		}

		/* プラグインを実行 */
		plugin.start(this);
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.event.Event", {

	/**
	 * コンストラクタ
	 *
	 * @param layout イベントが発生したレイアウト
	 * @param widget イベントが発生したマスカット部品
	 * @param type イベントタイプ
	 */
	initialize: function(layout, widget, type){
		this.layout = layout;
		this.layoutId = layout.getWidgetId();
		this.widget = widget;
		this.widgetId = widget.getWidgetId();
		this.type = type;
		this.branch = null;
		this.cancel = false;
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.event.EventDispatcher", {

	initialize: function(){
		this.url = null;
		this.headers = null;
		this.handlers = {};
		this.controller = null;
		this.layout = null;
		this.logger = maskat.log.LogFactory.getLog("maskat.event");
	},

	setController: function(controller){
		this.controller = controller;
	},

	setLayout: function(layout){
		/* レイアウトのイベントハンドラを登録 */
		this.handlers[layout.getWidgetId()] = this.events;

		var widget;
		var handler;
		for (var widgetId in this.handlers) {
			/*
			 * 参照整合性チェック:
			 *
			 * イベント定義 XML に記述されたマスカット部品がレイアウトに
			 * 存在しない場合には警告メッセージを出力する
			 */
			widget = layout.getWidget(widgetId) || layout.getVariable(widgetId);
			if (typeof(widget) == "undefined") {
				this.logger.warn(maskat.util.Message.format("MISSING_WIDGET", {
					layoutId: layout.getWidgetId(),
					widgetId: widgetId
				}));
			}

			/* イベントハンドラの参照を解決する */
			for (var eventType in this.handlers[widgetId]) {
				handler = this.handlers[widgetId][eventType];
				handler.setDispatcher(this);
				if (handler.ref) {
					this.resolveHandlerReference(handler);
				}
			}
		}
	},

	resolveHandlerReference: function(handler){
		var eventRef = this.eventRefs[handler.ref];

		if (eventRef.headers) {
			handler.headers = eventRef.headers.concat(handler.headers || []);
		}

		if (!handler.marshaller) {
			handler.marshaller = eventRef.marshaller;
		}

		if (!handler.unmarshaller) {
			handler.unmarshaller = eventRef.unmarshaller;
		}
	},

	handleEvent: function(event){
		if (event.widget == event.layout && event.type == "onload") {
			this.setLayout(event.layout);
		}

		var handler = maskat.lang.Object.find([event.widgetId, event.type],
			this.handlers);
			
		if (handler) {
			try {
				handler.startHandle(event);
			} catch (e) {
				event.cancel = true;
				if (e instanceof maskat.lang.InterruptedError) {
					var msg = e.getMessages ? e.getMessages().join("\n") : e.message;
					this.logger.info(msg);
				} else {
					this.logger.error(e.message);
				}
			}
		}
	},

	finishHandle: function(event) {
		if (!event.cancel && this.controller) {
			this.controller.handleEvent(event);
		}
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.event.EventHandler", {

	/**
	 * コンストラクタ
	 */
	initialize: function(){
		this.dispatcher = null;
		this.onStart = null;
		this.onFinish = null;
		this.logger = maskat.log.LogFactory.getLog("maskat.event");
	},

	/**
	 * このイベントハンドラを管理するイベントディスパッチャを設定します。
	 * マスカット部品で発生したイベントは最初にイベントディスパッチャに
	 * 通知され、適切なハンドラが起動されます。
	 *
	 * イベントディスパッチャはレイアウト内のイベント処理に共通する設定を
	 * 保持しています。
	 *
	 * @param dispatcher イベントディスパッチャ
	 */
	setDispatcher: function(dispatcher){
		this.dispatcher = dispatcher;
	},

	/**
	 * イベントハンドラの開始処理を実行します。
	 *
	 * イベントハンドラ開始時のコールバック関数を実行し、確認ダイアログが
	 * 設定されている場合はダイアログを表示します。コールバック関数や確認
	 * ダイアログで処理の中止が要求された場合、それ以降のイベントの処理は
	 * 行われません。
	 * 
	 * @param event マスカット部品で発生したイベント
	 */
	startHandle: function(event){
		/* コールバック関数 (start) を実行 */
		if (this.onStart) {
			var param = { stopProcess: false };
			this.onStart(param);
			if (param.stopProcess) {
				throw new maskat.lang.InterruptedError("INTERRUPTION_ERROR");
			}
		}

		/* 入力値検証を実行 */
		if (!this.validate(event)) {
			event.cancel = true;
			return;
		}

		if (this.confirmDialog) {
			/* 確認ダイアログを表示 */
			var self = this;
			var dialog = event.layout.getWidget(this.confirmDialog);
			dialog.proceed = function (e) { self.handle(event); }
			dialog.setVisible(true);
		} else {
			this.handle(event);
		}
	},

	/**
	 * マスカット部品で発生したイベントの処理を行います。
	 *
	 * イベントハンドラのサブクラスでは、このメソッドをオーバーライドして
	 * イベント処理を実装する必要があります。なお、イベント処理の完了後に
	 * finishHandle(event) メソッドが実行されるように実装してください。
	 *
	 * @param event マスカット部品で発生したイベント
	 */
	handle: function(event){
		this.finishHandle(event);
	},

	/**
	 * イベントハンドラの終了処理を実行します。
	 *
	 * イベントハンドラ終了時のコールバック関数を起動し、終了ダイアログが
	 * 設定されている場合はダイアログを表示します。
	 * 
	 * @param event マスカット部品で発生したイベント
	 */
	finishHandle: function(event){
		/* コールバック関数 (finish) を実行 */
		if (this.onFinish) {
			this.onFinish();
		}

		/* 終了ダイアログを表示 */
		if (this.endDialog) {
			var dialog = event.layout.getWidget(this.endDialog);
			dialog.setVisible(true);
		}

		/* 画面遷移の分岐先を Ajax 部品から取得 (マスカット 1.4.4 互換) */
		var widget = event.widget.getWidget();
		if (!event.branch && widget) {
			event.branch = widget.branch || "";
		}

		this.dispatcher.finishHandle(event);
	},

	/**
	 * 入力データを検証します。
	 *
	 * このメソッドはイベントハンドラの処理が開始する前に呼び出されます。
	 * 検証に失敗した場合、ハンドラは実行されません。エラーメッセージを
	 * 表示する責任は、validate メソッドの実装側にあります。
	 *
	 * @return 入力値検証に成功した場合は true、失敗した場合は false
	 */
	validate: function(event){
		return true;
	}
	
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.event.EventXMLReader")
	.extend("maskat.xml.XMLObjectBinder", {

	_static: {
		getInstance: function() {
			var self = arguments.callee;
			if (!self.instance) {
				self.instance = new this();
			}
			return self.instance;
		}
	},
	
	initialize: function(){
		this.base({
			"#document": {
				children: {
					eventDef: {}
				}
			},

			eventDef: {
				type: maskat.event.EventDispatcher,
				attributes: {},
				children: {
					remoteUrl: {},
					header: { property: "headers", repeat: true },
					component: { property: "handlers", repeat: true, key: "id", value: "events" },
					event: { property: "events", repeat: true, key: "id" },
					eventRef: {  property: "eventRefs", repeat: true, key: "id" },
					desc: {}
				}
			},
	
			remoteUrl: {
				attributes: {
					url: { type: "string", required: true }
				}
			},
	
			header: {
				attributes: {
					name: { type: "string", required: true },
					value: { type: "string", required: true }
				}
			},
	
			component: {
				attributes: {
					id: { type: "string", required: true }
				},
				children: {
					event: { property: "events", repeat: true, key: "id" },
					desc: {}
				}
			},
	
			event: {
				attributes: {
					id: { type: "string", required: true },
					remoteUrl: { type: "string", property: "url" },
					type: {
						type: "enum",
						values: [ "local", "remote" ],
						defaultValue: "remote"
					},
					async: { type: "boolean", defaultValue: true },
					ref: { type: "string" },
					marshal: { type: "function" },
					unmarshal: { type: "function" },
					start: { type: "function", property: "onStart" },
					before: { type: "function", property: "onBeforeRequest" },
					after: { type: "function", property: "onAfterResponse" },
					finish: { type: "function", property: "onFinish" },
					timeout: { type: "number" },
					onTimeoutError: { type: "function" },
					confirmDialog: { type: "string" },
					endDialog: { type: "string" }
				},
				children: {
					header: { property: "headers", repeat: true },
					param: { property: "marshaller" },
					result: { property: "unmarshaller" },
					desc: {}
				}
			},
	
			eventRef: {
				attributes: {
					id: { type: "string", required: true }
				},
				children: {
					header: { property: "headers", repeat: true },
					param: { property: "marshaller" },
					result: { property: "unmarshaller" },
					desc: {}
				}
			},
	
			param: {
				type: maskat.event.RequestMarshaller,
				attributes: {
					rootNode: { type: "string" },
					ns: { type: "string" },
					soap: { type: "boolean", defaultValue: false }
				},
				children: {
					source: { property: "sources", repeat: true },
					desc: {}
				}
			},
	
			source: {
				attributes: {
					obj: { type: "string", required: true },
					node: { type: "string" },
					childNode: { type: "string" },
					idxRef: { type: "string" },
					fromkey: { type: "number" },
					type: { type: "string" },
					regexp: { type: "string" },
					min: { type: "number" },
					max: { type: "number" },
					desc: { type: "string" },
					sendBlankElement: { type: "boolean", defaultValue: false },
					teleType: { type: "string" }
				},
				children: {
					bind: { property: "binds", repeat: true },
					desc: {}
				}
			},
	
			result: {
				type: maskat.event.ResponseUnmarshaller,
				attributes: {
					rootNode: { type: "string" },
					ns: { type: "string" },
					onErrorTele: { type: "function" },
					soap: { type: "boolean", defaultValue: false }
				},
				children: {
					target: { property: "targets", repeat: true },
					desc: {}
				}
			},
	
			target: {
				attributes: {
					out: { type: "string", property: "widgetId", required: true },
					"in": { type: "string", property: "node" },
					inkey: { type: "string", property: "childNode" },
					type: {
						type: "enum",
						values: [ "local", "remote" ]
					},
					teleType: { type: "string" },
					workType: { type: "function" }
				},
				children: {
					bind: { property: "binds", repeat: true },
					desc: {}
				}
			},
	
			bind: {
				attributes: {
					node: { type: "string", required: true },
					fromkey: { type: "string", property: "property" },
					tokey: { type: "string", property: "property" }
				}
			},
	
			desc: {
				children: {
					"#text": {}
				}
			}
		});
	},

	createObject: function(element){
		switch (element.nodeName) {
		case "event":
			/* イベント種別に応じてハンドラクラスを生成する */
			if (element.getAttribute("type") == "local") {
				return new maskat.event.LocalEventHandler();
			} else {
				return new maskat.event.RemoteEventHandler();
			}

		case "target":
			/*
			 * type 属性のデフォルト値はローカルイベントとリモートイベント
			 * の場合で異なる
			 */
			var event = element.parentNode.parentNode;
			var binder = new maskat.xml.XMLObjectBinder();
			binder.type = event.getAttribute("type") || "remote";
			return binder;

		case "bind":
			var parentName = element.parentNode.nodeName;
			/* 親要素が source の場合、fromkey 属性が必須 */
			if (parentName == "source" && !element.getAttribute("fromkey")) {
				throw new maskat.lang.Error("MISSING_ATTRIBUTE",
					{ attributeName: "fromkey" });
			}
			/* 親要素が target の場合、tokey 属性が必須 */
			if (parentName == "target" && !element.getAttribute("tokey")) {
				throw new maskat.lang.Error("MISSING_ATTRIBUTE",
					{ attributeName: "tokey" });
			}
			/* falls through */
		default:
			return {};
		}
	}


});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.event.LocalEventHandler")
	.extend("maskat.event.EventHandler", {

	/**
	 * コンストラクタ
	 */
	initialize: function() {
		this.base.apply(this, arguments);
	},

	/**
	 * ローカルイベントの処理を行います。
	 *
	 * ローカルイベントハンドラはブラウザ上の JavaScript 関数によってイベント
	 * を処理します。レイアウト内のマスカット部品や変数のデータを相互に代入
	 * したり、任意の JavaScript 関数を実行することが可能です。
	 *
	 * @param event マスカット部品で発生したイベント
	 */
	handle: function(event){
		/* ローカルデータバインディングを実行 */
		if (this.unmarshaller) {
			this.unmarshaller.unmarshal(null, event.layout);
		}

		/* イベントハンドラの終了処理を実行 */
		this.finishHandle(event);
	}
	
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.event.RemoteEventContext")
	.extend("maskat.comm.HttpContext", {

	initialize: function(handler, event){
		this.base(handler.method, handler.url, handler);
		this.handler = handler;
		this.event = event;

		if (!this.requestHeaders["maskat_layoutID"]) {
			this.requestHeaders["maskat_layoutID"] = event.layoutId;
		}
		if (!this.requestHeaders["maskat_componentID"]) {
			this.requestHeaders["maskat_componentID"] = event.widgetId;
		}
		if (!this.requestHeaders["maskat_eventID"]) {
			this.requestHeaders["maskat_eventID"] = event.type;
		}
	},
	
	onWait: function(){
		if (this.handler.onBeforeRequest) {
			var param = {
				sendXML: this.requestMessage,
				xhr: this.xhr,
				stopProcess: false
			};
			try {
				this.handler.onBeforeRequest(param);

				if (param.stopProcess) {
					throw new maskat.lang.InterruptedError("INTERRUPTION_ERROR");
				}
				
			} catch (e) {
				if (e instanceof maskat.lang.InterruptedError) {
					var msg = e.getMessages ? e.getMessages().join("\n") : e.message;
					this.handler.logger.info(msg);
				}
				throw e;
			}
		}
			
		if (!this.async) {
			this.dialog = maskat.ui.Dialog.openProgress(
				"",
				maskat.util.Message.format("SYNC_EVENT_IN_PROGRESS"),
				Infinity);
		}
	},
	
	onComplete: function(){
		if (!this.async) {
			this.dialog.done();
		}

		try {
			if (this.handler.onAfterResponse) {
				var param = {
					recvDOM: this.responseXML,
					xhr: this.xhr,
					stopProcess: false
				};
				this.handler.onAfterResponse(param);
				
				if (param.stopProcess) {
					throw new maskat.lang.InterruptedError("INTERRUPTION_ERROR");
				}
			}
			this.handler.handleResponse(this.event, this);
			
		} catch (e) {
			if (e instanceof maskat.lang.InterruptedError) {
				var msg = e.getMessages ? e.getMessages().join("\n") : e.message;
				this.handler.logger.info(msg);
			}
			throw e;
		}
	},
	
	onTimeout: function(){
		this.handler.handleRequestTimeout(this.event);
	},

	onError: function(){
		this.handler.handleError(this.event, this.error);
	}
	
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.event.RemoteEventHandler")
	.extend("maskat.event.EventHandler", {

	/**
	 * コンストラクタ
	 */
	initialize: function(){
		this.base.apply(this, arguments);
		this.url = null;
		this.method = "POST";
		this.headers = null;
		this.onBeforeRequest = null;
		this.onAfterResponse = null;
		this.onTimeoutError = null;
		this.marshaller = null;
		this.unmarshaller = null;
	},

	/**
	 * このイベントハンドラを管理するイベントディスパッチャを設定します。
	 * マスカット部品で発生したイベントは最初にイベントディスパッチャに
	 * 通知され、適切なハンドラが起動されます。
	 *
	 * イベントディスパッチャはレイアウト内のイベント処理に共通する設定を
	 * 保持しています。
	 *
	 * @param dispatcher イベントディスパッチャ
	 */
	setDispatcher: function(dispatcher){
		this.dispatcher = dispatcher;

		/* リモート URL の省略時はデフォルト URL を使用 */
		if (!this.url) {
			this.url = dispatcher.url;
		}

		/* グローバルヘッダを追加 */
		if (dispatcher.headers) {
			this.headers = dispatcher.headers.concat(this.headers || []);
		}
	},

	/**
	 * リモートイベントの処理を行います。
	 *
	 * リモートイベントハンドラはサーバとの XML HTTP 通信によってイベントを
	 * 処理します。レイアウト内のマスカット部品や変数のデータを抽出して要求
	 * メッセージを生成し、サーバに HTTP 要求を送信します。
	 *
	 * @param event マスカット部品で発生したイベント
	 */
	handle: function(event) {
		try {
			/* 要求メッセージのデータバインディングを実行 */
			var context = new maskat.event.RemoteEventContext(this, event);
			context.requestMessage = this.marshal(event.layout);
			context.send();
		} catch (e) {
			event.cancel = true;
			var msg = maskat.util.Message.format("REQUEST_BIND_ERROR", {
				widgetId: event.widgetId,
				type: event.type
			});
			var submsg = e.getMessages ? e.getMessages().join("\n") : e.message;
			this.logger.error(msg + "\n" + submsg);
		}
	},

	marshal: function(layout) {
		if (this.marshaller) {
			return this.marshaller.marshal(layout);
		}
		return undefined;
	},
	
	/**
	 * 応答メッセージの受信処理を行います。
	 *
	 * リモートイベントハンドラは応答メッセージの情報を抽出し、レイアウト内の
	 * マスカット部品や変数に格納します。
	 *
	 * @param event マスカット部品で発生したイベント
	 * @param context 通信終了後のコンテキスト
	 */
	handleResponse: function(event, context){
		/* 応答メッセージのデータバインディングを実行 */
		try {
			var doc = context.responseXML || context.responseMessage;
			if (doc && doc.nodeName && doc.documentElement.nodeName == "errors") {
				if (this.unmarshaller.onErrorTele) {
					this.unmarshaller.onErrorTele(doc);
				} else {
					throw new maskat.lang.InterruptedError("INTERRUPTION_ERROR");
				}
			} else {
				this.unmarshal(doc, event.layout);
			}
		} catch (e) {
			event.cancel = true;
			throw new maskat.lang.Error("RESPONSE_BIND_ERROR", {
				widgetId: event.widgetId,
				type: event.type
			}, e);
		}

		/* イベントハンドラの終了処理を実行 */
		this.finishHandle(event);
	},

	unmarshal: function(doc, layout) {
		if (doc && this.unmarshaller) {
			this.unmarshaller.unmarshal(doc, layout);
		}
	},

	/**
	 * 応答メッセージ待ちのタイムアウト処理を行います。
	 *
	 * 応答メッセージ待ち状態のまま指定されたタイムアウト時間が経過した場合、
	 * タイムアウト処理が起動されます。
	 *
	 * @param event マスカット部品で発生したイベント
	 */
	handleRequestTimeout: function(event) {
		event.cancel = true;
		if (this.onRequestTimeout) {
			/* タイムアウト発生時のコールバック関数を実行 */
			this.onRequestTimeout();
		} else {
			/* コールバック関数が指定されていない場合はログを出力 */
			var msg = maskat.util.Message.format("RESPONSE_TIMEOUT", {
				widgetId: event.widgetId,
				type: event.type
			});
			this.logger.error(msg);
		}
	},

	/**
	 * エラー処理を行います。
	 *
	 * @param event マスカット部品で発生したイベント
	 */
	handleError: function(event, error) {
		event.cancel = true;
		this.logger.error(error.message);
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.event.RequestMarshaller")
	.extend("maskat.xml.XMLObjectBinder", {

	initialize: function(){
		this.base();
		this.rootNode = null;
		this.ns = "";
		this.soap = false;
		this.sources = [];
		this.configured = false;
	},

	marshal: function(layout) {
		if (!this.rootNode) {
			return null;
		}
		if (!this.configured) {
			this.configure();
		}

		var values = [];
		for (var i = 0; i < this.sources.length; i++) {
			var source = this.sources[i];
			var widgetId = source.obj;

			var widget = layout.getWidget(widgetId);
			var value;

			if (source.idxRef) {
				var reference = layout.getWidget(source.idxRef);
				if (reference) {
					value = reference.getValue(source.teleType);
				} else {
					value = layout.getVariable(source.idxRef);
				}
			} else {
				if (widget) {
					value = widget.getValue(source.teleType);
	            } else {
	            	value = layout.getVariable(widgetId);
				}
			}
            
			if (typeof(source.fromkey) != "undefined") {
			    /* 選択されたセルを送信 */
				var index = widget.getValue("selectedIndex");
				values[i] = value[index][source.fromkey];
			} else if (typeof(source.idxRef) != "undefined") {
                if (typeof(source.childNode) == "undefined") {
				    /* 選択された単一行を送信 */
                    var index = widget.getValue("selectedIndex");
                    values[i] = value[index];
                } else {
				    /* 選択された複数行を送信 */
					var indexes = widget.getValue("selectedIndexes");
					var rows = [];
					for (var j = 0; j < indexes.length; j++) {
						rows.push(value[indexes[j]]);
					}
					values[i] = rows;
				}
			} else {
				/* マスカット部品の値をそのまま使用する */
				values[i] = value;
			}
			
			/* sendBlankElement 属性への対応 */
			switch (typeof(values[i])) {
			case "string":
				/* 空文字列の場合 */
				if (values[i] == "" && !source.sendBlankElement) {
					values[i] = undefined;
				}
				break;
				
			case "object":
				/* null または空の配列の場合 */
				if (values[i] == null ||
				    values[i] instanceof Array && values[i].length == 0) {
					values[i] = source.sendBlankElement ? null : undefined;
				}
				break;

			case "undefined":
				/* 未定義の場合 */
				values[i] = source.sendBlankElement ? null : undefined;
				break;
			}
		}

		return this.write(values);
	},

	configure: function() {
		this.configured = true;

		if (this.soap) {
			// TODO: add soap envelope
		} else {
			this.setRootElement(this.ns, this.rootNode);
		}

		if (this.ns) {
			this.addPrefixMapping("", this.ns);
		}

		/* 応答メッセージのルート要素に対応するバインディングを生成 */
		var root = this.addElementBinding(this.ns, this.rootNode);

		for (var i = 0; i < this.sources.length; i++) {
			var source = this.sources[i];
			var wrapper;
			if (source.node) {
				/*
				 * マーシャル対象のデータをルート要素の子要素 (wrapper) の
				 * 内部に出力する
				 */
				root.addChildBinding(source.node, { property: i });
				wrapper = this.addElementBinding(this.ns, source.node);
			}

			var object;
			if (source.childNode) {
				/*
				 * 繰り返し要素が定義されている場合、マスカット部品または変数
				 * から配列を取得し、配列の各要素を XML 要素へバインドする
				 */
				if (source.node) {
					wrapper.addChildBinding(source.childNode, { repeat: true });
				} else {
					/*
					 * childNode 属性が指定された場合は node 属性は省略可能
					 * この場合、ルート要素の直下に繰り返し要素を出力する
					 */
					root.addChildBinding(source.childNode, { property: i, repeat: true });
				}
				object = this.addElementBinding(this.ns, source.childNode);
			} else if (source.binds) {
				/*
				 * 繰り返し要素は未定義だが子要素へのバインドが定義されている
				 * 場合、マスカット部品または変数からオブジェクトを取得し、
				 * そのプロパティを子要素へバインドする
				 */
				object = wrapper;
			} else {
				/* 文字列からテキストノードへのバインドを定義 */
				wrapper.addChildBinding("#text", {});
			}
	
			if (object && source.binds) {
				/* 子要素へのバインドを定義 */
				for (var j = 0; j < source.binds.length; j++) {
					var bind = source.binds[j];
					var property = this.addElementBinding(this.ns, bind.node);
					property.addChildBinding("#text", { property: bind.property });
					object.addChildBinding(bind.node);
				}
			}
		}
	}

});/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.event.ResponseUnmarshaller", {

	initialize: function(){
		this.soap = false;
		this.ns = "";
		this.rootNode = null;
		this.targets = [];
		this.configured = false;
	},

	unmarshal: function(doc, layout) {
		if (!this.configured) {
			this.configure();
		}

		for (var i = 0; i < this.targets.length; i++) {
			var target = this.targets[i];
			switch (target.type) {
			case "local":
				/* ローカルデータバインディングを実行 */
				var src = layout.getWidget(target.node);
				var value;
				if (src) {
					value = src.getValue();
				} else {
					value = layout.getVariable(target.node);
				}
				
				var dst = layout.getWidget(target.widgetId);
				if (target.workType) {
					var arg1 = src ? src.getWidget() : value;
					var arg2 = dst ? dst.getWidget() : layout.getVariable(target.widgetId);
					target.workType(arg1, arg2);
				} else {
					if (dst) {
						dst.setValue(value);
					} else {
						layout.setVariable(target.widgetId, value);
					}
				}
				break;

			case "remote":
				/* 応答メッセージのバインディングを実行 */
				var values = doc ? target.read(doc) : null;
				var widget = layout.getWidget(target.widgetId);
				if (widget) {
					widget.setValue(values[i], target.teleType);
				} else {
					layout.setVariable(target.widgetId, values[i]);
				}
				break;
			}
		}
	},

	configure: function() {
		this.configured = true;

		for (var i = 0; i < this.targets.length; i++) {
			var target = this.targets[i];
			if (target.type == "local") {
				continue;
			}
			
			if (this.soap) {
				// TODO: add soap envelope
			} else {
				target.setRootElement(this.ns, this.rootNode);
			}
	
			/* 応答メッセージのルート要素に対応するバインディングを生成 */
			var root = target.addElementBinding(this.ns, this.rootNode);

			var wrapper;
			if (target.node) {
				/*
				 * アンマーシャル対象のデータはルート要素の子要素 (wrapper) の
				 * 内部に格納されている
				 */
				wrapper = target.addElementBinding(this.ns, target.node);
				root.addChildBinding(target.node);
				root.addChildBinding("*", { validate: false });
			} else {
				/* アンマーシャル対象のデータはルート要素の内部に格納されている */
				wrapper = root;
			}
	
			var object;
			if (target.childNode) {
				/*
				 * 繰り返し要素が定義されている場合、繰り返し単位となる個々の
				 * 要素をオブジェクトへバインドし、それらを要素とする配列を
				 * マスカット部品または変数にバインドする
				 */
				object = target.addElementBinding(this.ns, target.childNode);
				wrapper.addChildBinding(target.childNode, { property: i, repeat: true });
				wrapper.addChildBinding("*", { validate: false });
			} else if (target.binds) {
				/*
				 * 繰り返し要素は未定義だが、プロパティへのバインドが定義されて
				 * いる場合、単一のオブジェクトへのバインドを定義
				 */
				root.addChildBinding(target.node, { property: i });
				object = wrapper;
			} else {
				/* テキスト要素から文字列へのバインドを定義 */
				wrapper.addChildBinding("#text", { property: i });
				object = null;
			}
	
			if (object && target.binds) {
				/* オブジェクトのプロパティへのバインドを定義 */
				for (var j = 0; j < target.binds.length; j++) {
					var bind = target.binds[j];
					var property = target.addElementBinding(this.ns, bind.node);
					property.addChildBinding("#text", { property: bind.property });
					object.addChildBinding(bind.node);
				}
				object.addChildBinding("*", { validate: false });
			}
		}
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 maskat.lang.Class.declare("maskat.key.KeyEventManager", {
	
	_static: {
		getInstance: function() {
			var self = arguments.callee;
			if (!self.instance) {
				self.instance = new this();
			}
			return self.instance;
		}
	},
	
	handle: function(event) {
		var manager = maskat.key.KeyEventManager.getInstance();
		var element = event.currentTarget || event.srcElement;
		var widget = manager.getWidget(manager.getRootElement(element));
		if (!widget || !widget.canFocus()) {
			if (event.keyCode == 9) {
				return false;
			}
			return true;
		}
		var result = true;
		
		if (!widget.handleKeyEvent(event)) {
			result = false;
			
		} else if (event.keyCode == 9) {
			var next = manager.nextWidget(widget, event.shiftKey);
			if (next) {
				try {
					next.setFocus();
				} catch (e) {}
				result = false;
			}
		}
		if (!result) {
			/* FIreFox */
			if (event.preventDefault) {
				event.preventDefault();
			/* IE */
			} else {
				event.returnValue = false;
			}
			/* FireFox */
			if (event.stopPropagation) {
				event.stopPropagation();
			/* IE */
			} else {
				event.cancelBubble  = true;
			}
		}
		return result;
	},
	
	getRootElement: function(element) {
		while (element && !element._layoutId) {
			element = element.parentNode;
		}
		return element;
	},
	
	getWidget: function(element) {
		if (element) {
			var layout = maskat.app.getLayout(element._layoutId);
			return layout.getWidget(element._widgetName);
		}
		return null;
	},
	
	nextWidget: function(widget, shift) {
		var activeLayout = widget.getLayout();
		var tabIndexes = activeLayout.getTabIndexes();
		var pos = -1;
		for (var i = 0; i < tabIndexes.length; i++) {
			var name = widget.getTabIndexGroupName() || widget.name;
			if (tabIndexes[i] == name) {
				pos = i;
				break;
			}
		}
		for (var j = 0; j < tabIndexes.length - 1; j++) {
			if (!shift) {
				pos++;
				if (pos >= tabIndexes.length) pos = 0;
			} else {
				pos--;
				if (pos < 0) pos = tabIndexes.length - 1;
			}
			var next = activeLayout.getWidget(tabIndexes[pos]);
			if (next.canFocus()) {
				return next;
			}
		}
		return widget;
	}
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * マスカットフレームワーク用のエラークラスです。
 *
 * マスカットフレームワークで新しいエラークラスを定義する場合、このクラスを
 * 継承する必要があります。
 */
maskat.lang.Class.declare("maskat.lang.Error").extend("Error", {

	/**
	 * コンストラクタ
	 *
	 * @param key エラーメッセージのメッセージキー
	 * @param param エラーのパラメータ
	 * @param cause このエラーの原因となった下位レベルのエラー
	 */
	initialize: function(key, param, cause){
		this.message = maskat.util.Message.format(key, param);
		this.key = key;
		this.param = param;
		this.cause = cause;
	},

	/**
	 * エラーメッセージの配列を返します。
	 *
	 * このエラーが下位レベルのエラーを含んでいる場合、エラーチェーンの
	 * 順番に従ってメッセージが格納されます。
	 *
	 * @return エラーメッセージの配列
	 */
	getMessages: function() {
		var messages = [];

		var error = this;
		do {
			messages.push(error.message);
			error = error.cause;
		} while (error);

		return messages;
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * マスカットフレームワーク用の割り込みエラークラスです。
 *
 * マスカットフレームワークで割り込みが発生した場合、throwされます。
 */
maskat.lang.Class.declare("maskat.lang.InterruptedError").extend("maskat.lang.Error", {

	/**
	 * コンストラクタ
	 *
	 * @param key エラーメッセージのメッセージキー
	 * @param param エラーのパラメータ
	 * @param cause このエラーの原因となった下位レベルのエラー
	 */
	initialize: function(key, param, cause){
		this.base(key, param, cause);
	}
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * setInterval 関数を利用した擬似スレッド処理を行うクラスです。
 * 指定されたオブジェクトのメソッドを、一定間隔で繰り返し実行します。
 */
maskat.lang.Class.declare("maskat.lang.Thread", {

	/**
	 * コンストラクタ
	 *
	 * @param object オブジェクト
	 * @param method メソッドとして呼び出す関数、またはメソッド名の文字列
	 * @param args メソッド実行時に引数として与える配列
	 * @param interval 呼び出し間隔
	 */
	initialize: function(object, method, args, interval) {
		this.object = object;
		
		switch (typeof(method)) {
		case "string":
			this.method = object[method];
			break;
		case "function":
			this.method = method;
			break;
		}
		
		this.args = args;
		this.interval = interval;
		this.intervalId = null;
	},

	/**
	 * スレッドの実行を開始します。
	 */
	start: function() {
		if (!this.isRunning()) {
			var self = this;
			this.intervalId = setInterval(function() {
				self.method.apply(self.object, self.args || []);
			}, this.interval);
		}
	},
	
	/**
	 * スレッドを停止します。
	 */
	stop: function() {
		if (this.isRunning()) {
			clearInterval(this.intervalId);
			delete this.intervalId;
		}
	},

	/**
	 * スレッドが実行中かどうかを返します。
	 *
	 * @return スレッドが実行中の場合は true、それ以外の場合は undefined
	 */
	isRunning: function() {
		return this.intervalId;
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.layout.ExpressionEvaluator")
	.extend("maskat.layout.Widget", {

    createWidget: function(parent) {
    	/* NOP */
    },

	getWidgetId: function(){
		return this.name;
	},

	getValue: function(key){
		return eval(key);
	},
	
	setValue: function(value, key){
		eval(key + " = value");
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.layout.Layout")
	.extend("maskat.layout.Widget", {

	initialize: function(layoutId){
		this.layoutId = layoutId;
		this.div = null;
		this.widgets = null;
		this.scope = window;
		this.children = null;
		this.listeners = null;
	},
	
	load: function(element, visible) {
		this.div = document.createElement("div");
		this.div.id = this.layoutId;
		element.appendChild(this.div);

		this.setVisible(false);
        this.accept(new maskat.layout.WidgetCreationVisitor(this));
		this.tabIndexes = this.createTabIndexes();
        
        if (visible) {
			this.setVisible(true);
		}

		this.notifyEvent("onload");
	},

	unload: function() {
		this.notifyEvent("onunload");
		this.setVisible(false);
        this.accept(new maskat.layout.WidgetDisposalVisitor());
	},

	setVisible: function(visible) {
		if (this.div && this.div.style) {
			this.div.style.visibility = visible ? "visible" : "hidden";
		}
	},

	addEventListener: function(listener) {
		if (!this.listeners) {
			this.listeners = [];
		}
		this.listeners.push(listener);
	},

	dispatchEvent: function(event) {
		if (!this.listeners) {
			return;
		}
		for (var i = 0; i < this.listeners.length; i++) {
			this.listeners[i].handleEvent(event);
		}
	},

	getWidget: function(widgetId) {
		return this.widgets[widgetId];
	},

	defineVariable: function(name, value) {
		if (name in this.scope) {
			throw new maskat.lang.Error("DUPLICATED_VARIABLE",
				{ layoutId: this.layoutId, name: name });	
		}
		this.scope[name] = value;
	},

	getVariable: function(name) {
		if (!(name in this.scope)) {
			throw new maskat.lang.Error("UNDEFINED_VARIABLE",
				{ layoutId: this.layoutId, name: name });	
		}
		return this.scope[name];
	},

	setVariable: function(name, value) {
		if (!(name in this.scope)) {
			throw new maskat.lang.Error("UNDEFINED_VARIABLE",
				{ layoutId: this.layoutId, name: name });	
		}
		this.scope[name] = value;
	},

	getWidgetId: function(){
		return this.layoutId;
	},

	getLayout: function(){
		return this;
	},
	
	getElement: function(){
		return this.div;
	},

	dispose: function() {
		this.div.parentNode.removeChild(this.div);
		delete this.div;
		delete this.tabIndexes;
	},
	
	createTabIndexes: function() {
		var list = [];
		for (prop in this.widgets) {
			var widget = this.widgets[prop]
			if (widget.getTabIndex() > -1 && widget.name) {
				list.push(widget);
			}
		}
		list.sort(function(a, b) {return a.getTabIndex() - b.getTabIndex()});
		var indexes = [];
		for (var i = 0; i < list.length; i++) {
			indexes.push(list[i].name);
		}
		return indexes;
	},
	
	getTabIndexes: function() {
		return this.tabIndexes;
	}
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.layout.LayoutFactory")
	.extend("maskat.layout.WidgetLibrary", {

	config: {
		"#document": {
			children: {
				layoutDef: {}
			}
		},

		layoutDef: {
			type: maskat.layout.Layout,
			children: {
				layout: {},
				javaScriptGlobal: { property: "children", repeat: true }
			}
		},
		
		layout: {
			attributes: {
				name: { type: "string", required: true, property: "layoutId" },
				refParentHTML: { type: "string" }
			},
			children: {
				"*": { property: "children", repeat: true }
			}
		},

		evaluator: {
			type: maskat.layout.ExpressionEvaluator,
			attributes: {
				name: { type: "string", required: true }
			}
		},
		
		desc: {
			children: {
				"#text": {}
			}
		}
	},

	getBindingConfiguration: function() {
		return this.config;
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.layout.LayoutXMLReader")
	.extend("maskat.xml.XMLObjectBinder", {

	_static: {
		getInstance: function() {
			var self = arguments.callee;
			if (!self.instance) {
				self.instance = new this();
			}
			return self.instance;
		}
	},
	
	initialize: function(){
		this.base.apply(this, arguments);
		this.libraries= null;
	},

	createObject: function(element){
		var uri = element.namespaceURI || "";
		var widget;
		if (this.libraries[uri]) {
			widget = this.libraries[uri].create(element);
		}
		return widget || {};
	},

	addWidgetLibrary: function(library) {
		var uri = library.getNamespaceURI() || "";
		if (!this.libraries) {
			this.libraries = {};
		}
		this.libraries[uri] = library;

		var config = library.getBindingConfiguration();
		this.addBindingConfiguration(uri, config);
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.layout.Widget", {

	/**
	 * コンストラクタ
	 */
	initialize: function(){
		this.parent = null;
		this.children = null;
		this.tabIndex = -1;
	},

	/**
	 * このマスカット部品を格納しているレイアウトを取得します。
	 *
	 * マスカット部品はツリー構造を持ち、レイアウトはそのルート要素
	 * となるノードです。
	 *
	 * @return このマスカット部品を格納しているレイアウト
	 */
	getLayout: function(){
		var parent = this.getParent();
		return parent ? parent.getLayout() : null;
	},
	
	/**
	 * このマスカット部品の親となるマスカット部品を取得します。
	 *
	 * @return このマスカット部品の親となるマスカット部品
	 */
	getParent: function(){
		return this.parent;
	},
	
	/**
	 * このマスカット部品の親となるマスカット部品を設定します。
	 *
	 * @param parent このマスカット部品の親となるマスカット部品
	 */
	setParent: function(parent){
		this.parent = parent;
	},
	
	/**
	 * このマスカット部品に子ノードとなるマスカット部品を追加します。
	 *
	 * @param parent 子ノードとなるマスカット部品
	 */
	addChild: function(child){
		if (!this.children) {
			this.children = [];
		}
		this.children.push(child);
		child.setParent(this);
	},

	/**
	 * このマスカット部品の子ノードの配列を取得します。
	 *
	 * @return このマスカット部品の子ノードの配列
	 */
	getChildren: function(){
		return this.children;
	},

	/**
	 * このマスカット部品の部品 ID を取得します。部品 ID はレイアウト内で
	 * 一意の値となる必要があります。
	 *
	 * @return このマスカット部品の部品 ID
	 */
	getWidgetId: function(){
		return null;
	},

	/**
	 * このマスカット部品が参照している Ajax 部品を返します。
	 *
	 * @return このマスカット部品が参照している Ajax 部品
	 */
	getWidget: function(){
		return null;
	},

	/**
	 * このマスカット部品が参照する Ajax 部品を生成し、その Ajax 部品への
	 * 参照を返します。
	 *
	 * @param このマスカット部品の親となるマスカット部品
	 *
	 * @return 生成した Ajax 部品
	 */
	createWidget: function(parent) {
		return null;
	},

	/**
	 * Ajax 部品を生成後の後処理を行います。
	 */
    postCreateWidget: function() {
    },

	/**
	 * このマスカット部品が使用しているリソースを開放します。
	 */
	dispose: function() {
		maskat.lang.Object.dispose(this);
	},

	/**
	 * このマスカット部品が参照している HTML 要素を返します。
	 *
	 * @return このマスカット部品が参照している HTML 要素
	 */
	getElement: function(){
		return null;
	},
	
	/**
	 * このマスカット部品に含まれるコントロール要素を返します。
	 *
	 * コントロール要素は HTML DOM 要素のうち、以下のいずれかのクラスに属する
	 * ものです。
	 *
	 *  - HTMLAnchorElement
	 *  - HTMLInputElement
	 *  - HTMLSelectElement
	 *  - HTMLTextAreaElement
	 *
	 * 詳細については「Document Object Model (DOM) Level 2 Specification」を
	 * 参照してください。
	 * http://www.w3.org/TR/2000/CR-DOM-Level-2-20000510/html.html 
	 *
	 * @return このマスカット部品に含まれるコントロール要素
	 */
	getControlElement: function(){
		return null;
	},
	
	/**
	 * このマスカット部品が保持しているデータ値を取得します。
	 *
	 * @return このマスカット部品が保持しているデータ値
	 */
	getValue: function(){
		return this.value;
	},
	
	/**
	 * このマスカット部品にデータ値を格納します。
	 *
	 * @param value このマスカット部品に格納するデータ値
	 */
	setValue: function(value){
		this.value = value;
	},
	
	/**
	 * このマスカット部品にデータ値をリセットします。
	 */
	clear: function(){
		delete this.value;
	},
	
	/**
	 * このマスカット部品に対するキーイベントを処理します。
	 *
	 * @param event キーイベント
	 *
	 * @return 部品がキーイベントを処理した場合は false、それ以外は true
	 */
	handleKeyEvent: function(event){
		return true;
	},
	
	/**
	 * このマスカット部品にフォーカスを設定します。
	 */
	setFocus: function(){
	},
	
	/**
	 * このマスカット部品のフォーカス移動が可能かを返します。
	 *
	 * @return 部品にフォーカスを移動できる場合はtrue、できない場合はfalse
	 */
	canFocus: function() {
	    return this.tabIndex > -1 && this.isEnabled();
    },
    
    /**
     * このマスカット部品が表示されているかを返します。
     *
     * @return 部品が表示されている場合はtrue、非表示の場合はfalse
     */
    isEnabled: function() {
		return true;
    },
    
    /**
     * このマスカット部品の表示、非表示を定義します。
     *
     * @param enable 表示の場合true、非表示の場合false
     */
    setEnabled: function(enable) {
	},
	
	/**
	 * このマスカット部品にキーイベントリスナを設定します。
	 *
	 * @param element イベントリスナを定義するエレメント
	 */
	addKeyEventListener: function(element){
		element._layoutId = this.getLayout().getWidgetId();
		element._widgetName = this.name;
		
		maskat.util.CrossBrowser.addEventListener(element, "keydown",
			maskat.key.KeyEventManager.getInstance().handle);
	},
	
	/**
	 * このマスカット部品のタブインデックスを返します。
	 *
	 * @return タブインデックス
	 */
	getTabIndex: function() {
		return this.tabIndex;
	},
	
	/**
	 * このマスカット部品のタブインデックスグループ名を返します。
	 *
	 * @return タブインデックスグループ名
	 */
	getTabIndexGroupName: function() {
		return this.tabIndexGroupName;
	},
	
	/**
	 * このマスカット部品で発生したイベントをリスナに通知します。
	 *
	 * @param eventType イベントタイプ
	 */
	notifyEvent: function(eventType) {
		var layout = this.getLayout();
		var event = new maskat.event.Event(layout, this, eventType);
		layout.dispatchEvent(event);
	},

	/**
	 * マスカット部品のツリー構造を走査する WidgetVisitor を受け入れます。
	 *
	 * @param visitor 受け入れる WidgetVisitor のインスタンス
	 */
	accept: function(visitor) {
		var visitChildren = visitor.visit(this);
		var children = this.getChildren();
		if (visitChildren && children) {
			for (var i = 0; i < children.length; i++) {
				if (children[i] instanceof maskat.layout.Widget) {
					children[i].accept(visitor);
				}
			}
		}
		visitor.postVisit(this);
	}
	
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.layout.WidgetCreationVisitor", {

	initialize: function(layout) {
		this.layout = layout;
		this.stack = [];
	},

	visit: function(widget) {
		var parent;
		if (this.stack.length > 0) {
			parent = this.stack[this.stack.length - 1];
		}
	
		widget.createWidget(parent);
		widget.setParent(parent);

		var widgetId = widget.getWidgetId();
		if (widgetId) {
			/* レイアウトにマスカット部品を登録 */
			if (!this.layout.widgets) {
				this.layout.widgets = {};
			}
			this.layout.widgets[widgetId] = widget;

			/* レイアウトにマスカット部品を登録 (マスカット 1.4.4 互換) */
			if (!this.layout.components) {
				this.layout.components = {};
			}
			this.layout.components[widgetId] = widget.getWidget();

			/* グローバル変数に Ajax 部品を登録 (マスカット 1.4.4 互換) */
			window[widgetId] = widget.getWidget();
		}

		this.stack.push(widget);
		return true;
	},
	
	postVisit: function(widget) {
		widget.postCreateWidget();
		this.stack.pop();
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.layout.WidgetDisposalVisitor", {

	visit: function(widget) {
		return true;
	},
	
	postVisit: function(widget) {
		widget.dispose();
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.layout.WidgetLibrary", {

	getPrefix: function() {
		return null;
	},

	getNamespaceURI: function() {
		return null;
	},

	getBindingConfiguration: function() {
		return null;
	},

	create: function(element) {
		return null;
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * ログ出力 API を定義する抽象クラスです。
 */
maskat.lang.Class.declare("maskat.log.Log", {
	
	/** ログレベルの定義 */
	_static: {
		TRACE: 1,
		DEBUG: 2,
		INFO: 3,
		WARN: 4,
		ERROR: 5,
		FATAL: 6
	},
	
	initialize: function() {
		this.level = maskat.log.Log.WARN;
	},

	/**
	 * トレースログを記録します。
	 *
	 * @param message ログメッセージ
	 * @param error エラーオブジェクト (省略可能)
	 */
	trace: function(message, error) {
		/* NOP */
	},

	/**
	 * デバッグログを記録します。
	 *
	 * @param message ログメッセージ
	 * @param error エラーオブジェクト (省略可能)
	 */
	debug: function(message, error) {
		/* NOP */
	},

	/**
	 * 情報ログを記録します。
	 *
	 * @param message ログメッセージ
	 * @param error エラーオブジェクト (省略可能)
	 */
	info: function(message, error) {
		/* NOP */
	},

	/**
	 * 警告ログを記録します。
	 *
	 * @param message ログメッセージ
	 * @param error エラーオブジェクト (省略可能)
	 */
	warn: function(message, error) {
		/* NOP */
	},

	/**
	 * エラーログを記録します。
	 *
	 * @param message ログメッセージ
	 * @param error エラーオブジェクト (省略可能)
	 */
	error: function(message, error) {
		/* NOP */
	},

	/**
	 * 致命的エラーログを記録します。
	 *
	 * @param message ログメッセージ
	 * @param error エラーオブジェクト (省略可能)
	 */
	fatal: function(message, error) {
		/* NOP */
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * ロギング API を切り替えるためのファクトリを定義するクラスです。
 *
 * ログファクトリには指定された名前をもとに、適切なロガーオブジェクトを
 * 生成して返却する責任があります。
 */
maskat.lang.Class.declare("maskat.log.LogFactory", {

	_static: {
		/** ロガーオブジェクトのキャッシュ */
		cache: {},

		/**
		 * ロギング API を提供するロガーオブジェクトを取得します。
		 *
		 * @param name ロガーオブジェクトの名前
		 *
		 * @return ロガーオブジェクト
		 */
		getLog: function(name) {
			/* ロガーがキャッシュされている場合はそれを返却する */
			if (this.cache[name]) {
				return this.cache[name];
			}

			/* ログファクトリ経由でロガーを生成 */
			var log = this.getFactory().createLog(name);
			if (!log) {
				log = new maskat.log.NullLog();
			}

			this.cache[name] = log;
			return log;
		},

		/**
		 * ロガーの生成に用いるログファクトリを返却します。
		 *
		 * @return ログファクトリ
		 */
		getFactory: function() {
			/* ログファクトリが初期化済みの場合はそれを返却する */
			if (this.factory) {
				return this.factory;
			}
		
			var className;
			var type;
			try {
				/* プロパティで指定されたログファクトリを生成 */
				className = maskat.app.getProperty("maskat.log.factory");
				type = maskat.util.Converter.convert("function", className);
				this.factory = new type();
			} catch (e) {
				/* ファクトリが生成できない場合は NullLog を使用 */
				this.factory = new maskat.log.NullLogFactory();
				throw new maskat.lang.Error("LOG_FACTORY_INIT_FAILED",
					{ className: className }, e);
			}
			return this.factory;
		}
	},

	/**
	 * ロガーオブジェクトを生成します。
	 *
	 * このメソッドは抽象メソッドです。サブクラスはこのメソッドを実装し、
	 * ロガーを返却する必要があります。
	 *
	 * @param name ロガーオブジェクトの名前
	 */
	createLog: function(name) {
		return null;
	}

});/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * ログ出力を全く行わないダミーのログ実装クラスです。
 */
 maskat.lang.Class.declare("maskat.log.NullLog").extend("maskat.log.Log", {

	_static: {
		/**
		 * このクラスの唯一のインスタンスを返します。(Singleton パターン)
		 *
		 * @return このクラスの唯一のインスタンス
		 */
		getInstance: function(param) {
			var self = arguments.callee;
			if (!self.instance) {
				self.instance = new this();
			}
			return self.instance;
		}
	},
	
	trace: function(message, error) {
		/* NOP */
	},

	debug: function(message, error) {
		/* NOP */
	},

	info: function(message, error) {
		/* NOP */
	},

	warn: function(message, error) {
		/* NOP */
	},

	error: function(message, error) {
		/* NOP */
	},

	fatal: function(message, error) {
		/* NOP */
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.log.NullLogFactory")
	.extend("maskat.log.LogFactory", {

	/**
	 * ログ出力を全く行わないダミーのログ実装を返します。
	 *
	 * @param name ロガーオブジェクトの名前
	 */
	createLog: function(name) {
		return maskat.log.NullLog.getInstance();
	}

});/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.log.SimpleLog").extend("maskat.log.Log", {

	initialize: function(name, level, focus) {
		this.base.apply(this, arguments);
		this.name = name;
		this.level = level || maskat.log.Log.WARN;
		this.focus = focus;
	},

	trace: function(message, error) {
		if (this.level <= maskat.log.Log.TRACE) {
			this.log(this.format("TRACE", message), "#666666");
		}
	},

	debug: function(message, error) {
		if (this.level <= maskat.log.Log.DEBUG) {
			this.log(this.format("DEBUG", message), "green");
		}
	},

	info: function(message, error) {
		if (this.level <= maskat.log.Log.INFO) {
			this.log(this.format("INFO", message), "#000099");
		}
	},

	warn: function(message, error) {
		if (this.level <= maskat.log.Log.WARN) {
			this.log(this.format("WARN", message), "#999900");
		}
	},

	error: function(message, error) {
		if (this.level <= maskat.log.Log.ERROR) {
			this.log(this.format("ERROR", message), "red");
		}
	},

	fatal: function(message, error) {
		if (this.level <= maskat.log.Log.FATAL) {
			this.log(this.format("FATAL", message), "#660066");
		}
	},
	
	console: null,
	
	format: function(level, message) {
		return (new Date()).toLocaleString()  + " [" + this.name + "] " + level + " -  " + message;
	},
	
	log: function(message, color) {
		var doc = this.getLogDocument();
		var div = this.getLogElement(doc);
		var level = doc.createElement("pre");
		level.style.color = color ? color : "black";
		level.appendChild(doc.createTextNode(message));
		div.appendChild(level);
		div.appendChild(doc.createElement("br"));
		div.scrollTop = div.scrollHeight - div.offsetHeight;
		if (this.focus == true) {
			this.console.focus();
		}
	},	
	
	getLogDocument: function() {
		if (!this.console || this.console.closed) {
			var prop = "width=500,height=100,status=no,resizable,dependent=yes";
			this.console = window.open("", "maskatSimpleLog", prop);
		}
		return this.console.document;
	},
	
	getLogElement: function(doc) {
		var element = doc.getElementById("maskat.log.SimpleLog");
		if (!element) {
			element = doc.createElement("div");
			element.setAttribute("id", "maskat.log.SimpleLog");
			element.style.position = "absolute";
			element.style.width = "98%";
			element.style.height = "96%";
			element.style.top = "4";
			element.innerHTML = "<div style=\"height:96%;overflow:auto\"></div>";
			doc.getElementsByTagName("body").item(0).appendChild(element);
		}
		return element.getElementsByTagName("div").item(0);
	}
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.log.SimpleLogFactory")
	.extend("maskat.log.LogFactory", {

	/**
	 * コンストラクタ
	 */
	initialize: function() {
		/* ログレベルの文字列 ("INFO", "DEBUG" 等) を取得 */
		this.defaultLevel = maskat.app.getProperty("maskat.log.default.level");
	},

	/**
	 * デフォルトのロガーオブジェクトを生成します。
	 *
	 * @param name ロガーオブジェクトの名前
	 */
	createLog: function(name) {
		/* ログレベルの文字列 ("INFO", "DEBUG" 等) を取得 */
		var level = maskat.app.getProperty("maskat.log." + name + ".level")
			|| this.defaultLevel;
		return new maskat.log.SimpleLog(name, maskat.log.Log[level]);
	}

});/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.ui.AlertDialog", {

	/**
	 * javascriptアラートのコンストラクタ
	 *
	 * @param title アラートのタイトル文字列
	 * @param message アラートメッセージ文字列
	 * @param icon アイコン種別
	 * @param onClick ボタン押下時の呼び出し先関数名
	 */
	initialize: function (title, message, icon, onClick) {
		this.title = title;
		this.message = message;
		this.icon = icon;
		this.onClick = onClick;
		/* 戻り関数の存在チェック、無いときは何もしない*/
		if (typeof(this.onClick) != "function") {
			this.onClick = maskat.lang.EmptyFunction;
		}
	},

	/**
	 * アラートダイアログをPOPUPして表示します。
	 *
	 */
	open: function () {
		/* NOP */
	}
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.ui.Dialog", {

	_static: {
	
		/* ダイアログ戻り値の宣言 */
		YES: "YES",
		NO: "NO",
		OK: "OK",
		CANCEL: "CANCEL",
		
		/* アイコンURLの宣言 */
		INFO: "/rialto/rialtoEngine/images/debug/infoIcon.png",
		WARN: "/rialto/rialtoEngine/images/debug/warningIcon.png",
		ERROR:"/rialto/rialtoEngine/images/debug/errorIcon.png",
		
		/**
		 * Dialogの生成に用いるDialogFactoryを取得します。
		 *
		 * @return Dialogファクトリ
		 */
		getFactory: function() {
			/* 取得済みの場合はそれを返却する */
			if (this.factory) {
				return this.factory;
			}

			var className;
			var type;		
			try {
				/* プロパティで指定されたダイアログファクトリを取得 */　
				className = maskat.app.getProperty("maskat.ui.dialog.factory");
				type = maskat.util.Converter.convert("function", className);
				this.factory = type.getInstance();
			} catch (e) {
				var logger = maskat.log.LogFactory.getLog("maskat.ui");
				logger.error(e.getMessages ? e.getMessages().join("\n") : e.message);
			}
			/* 取得できなかった場合 */
			if (!this.factory) {
				alert("DialogFactoryが取得できません");
			}
			return this.factory;
		},
		
		/**
		 * 確認ダイアログをPOPUPして表示します。
		 *
		 * @param title ダイアログのタイトル文字列
		 * @param message ダイアログメッセージ文字列
		 * @param icon アイコン種別
		 * @param onClick ボタン押下時の呼び出し関数
		 */
		openMessage: function (title, message, icon, onClick)  {

			this.dialog = null;
			/* 未取得の場合は取得する */
			if (!this.factory) {
				this.getFactory();
			}
			/* 取得できなかった場合 */
			if (!this.factory) {
				return;
			}
			
			/* メッセージ表示クラスをファクトリ経由で生成 */
			this.dialog = 
				this.factory.createMessage (title, message, icon, onClick);
			
			/* 取得できなかった場合 */
			if (!this.dialog) {
				return;
			}
			/* メッセージの表示を実行 */
			this.dialog.open ();
			
			return this.dialog;
		},
		
		/**
		 * 入力ダイアログをPOPUPして表示します。
		 *
		 * @param title ダイアログのタイトル文字列
		 * @param message ダイアログメッセージ文字列
		 * @param icon アイコン種別
		 * @param onClick ボタン押下時の呼び出し関数
		 */
		openInput: function (title, message, icon, onClick) {
			this.dialog = null;
			/* 未取得の場合は取得する */
			if (!this.factory) {
				this.getFactory();
			}
			/* 取得できなかった場合 */
			if (!this.factory) {
				return;
			}
			
			/* 入力ダイアログクラスをファクトリ経由で生成 */
			this.dialog = 
				this.factory.createInput (title, message, icon, onClick);
			
			/* 取得できなかった場合 */
			if (!this.dialog) {
				return;
			}
			/* メッセージの表示を実行 */
			this.dialog.open ();

			return this.dialog;
		},
		
		/**
		 * アラートをPOPUPして表示します。
		 *
		 * @param title ダイアログのタイトル文字列
		 * @param message ダイアログメッセージ文字列
		 * @param icon アイコン種別
		 * @param onClick ボタン押下時の呼び出し関数
		 */
		openAlert: function (title, message, icon, onClick) {
			this.dialog = null;
			/* 未取得の場合は取得する */
			if (!this.factory) {
				this.getFactory();
			}
			/* 取得できなかった場合 */
			if (!this.factory) {
				return;
			}
			
			/* アラート表示ダイアログクラスをファクトリ経由で生成 */
			this.dialog = 
				this.factory.createAlert (title, message, icon, onClick);
			
			/* 取得できなかった場合 */
			if (!this.dialog) {
				return;
			}
			/* メッセージの表示を実行 */
			this.dialog.open ();

			return this.dialog;
		},
		
		/**
		 * 進捗状況ウィンドウをPOPUPして表示します。
		 *
		 * @param title ダイアログのタイトル文字列
		 * @param message ダイアログメッセージ文字列
		 * @param goalValue 終了進捗値(オプション)
		 * @return POPUPのインスタンス
		 */
		openProgress: function (title, message, goalValue)  {
			this.dialog = null;
			/* 未取得の場合は取得する */
			if (!this.factory) {
				this.getFactory();
			}
			/* 取得できなかった場合 */
			if (!this.factory) {
				return;
			}
			
			/* 進捗表示ダイアログクラスをファクトリ経由で生成 */
			this.dialog = 
				this.factory.createProgress (title, message, goalValue);
			
			/* 取得できなかった場合 */
			if (!this.dialog) {
				return;
			}
			/* メッセージの表示を実行 */
			this.dialog.open ();
			
			return this.dialog;
		}
	}
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * ダイアログ API を切り替えるためのファクトリを定義するクラスです。
 *
 * ダイアログファクトはロードされているプログインをもとに、適切なダイアログオブジェクトを
 * 生成して返却します。
 */
maskat.lang.Class.declare("maskat.ui.DialogFactory", {

	/**
	 * 確認ダイアログを表示するためのクラスを生成します。
	 *
	 * @param title ダイアログのタイトル文字列
	 * @param message ダイアログメッセージ文字列
	 * @param icon アイコン種別
	 * @param onClick ボタン押下時の呼び出し先関数名
	 */
	createMessage: function (title, message, icon, onClick) {
		/* NOP */
	},
	
	/**
	 * アラートダイアログを表示するためのクラスを生成します。
	 *
	 * @param title ダイアログのタイトル文字列
	 * @param message ダイアログメッセージ文字列
	 * @param icon アイコン種別
	 * @param onClick ボタン押下時の呼び出し先関数名
	 */
	createAlert: function (title, message, icon, onClick) {
		/* NOP */
	},
	
	/**
	 * 入力ダイアログを表示するためのクラスを生成します。
	 *
	 * @param title ダイアログのタイトル文字列
	 * @param message ダイアログメッセージ文字列
	 * @param icon アイコン種別
	 * @param onClick ボタン押下時の呼び出し先関数名
	 */
	createInput: function (title, message, icon, onClick) {
		/* NOP */
	},
	
	/**
	 * 進捗表示ダイアログを表示するためのクラスを生成します。
	 *
	 * @param title ダイアログのタイトル文字列
	 * @param message ダイアログメッセージ文字列
	 */
	createProgress: function (title, message) {
		/* NOP */
	}
	
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.ui.InputDialog", {

	/**
	 * javascriptの入力ダイアログコンストラクタ
	 *
	 * @param title ダイアログのタイトル文字列
	 * @param message ダイアログメッセージ文字列
	 * @param icon アイコン種別
	 * @param onClick ボタン押下時の呼び出し先関数名
	 */
	initialize: function (title, message, icon, onClick) {
		this.title = title;
		this.message = message;
		this.icon = icon;
		this.onClick = onClick;
		/* 戻り関数の存在チェック、無いときは何もしない*/
		if (typeof(this.onClick) != "function") {
			this.onClick = maskat.lang.EmptyFunction;
		}
	},

	/**
	 * 入力ダイアログをPOPUPして表示します。
	 *
	 */
	open: function () {
		/* NOP */
	}
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.ui.JavaScriptAlertDialog")
	.extend("maskat.ui.AlertDialog", {

	/**
	 * javascriptのアラートダイアログコンストラクタ
	 * 引数のtitle, iconは無視されます
	 *
	 * @param title ダイアログのタイトル文字列
	 * @param message ダイアログメッセージ文字列
	 * @param icon アイコン種別
	 * @param onClick ボタン押下時の呼び出し先関数名
	 */
	initialize: function (title, message, icon, onClick) {
		/* 引数を内部メンバとして設定 */
		this.base.apply(this, arguments);
	},

	/**
	 * javascriptのアラートダイアログをPOPUPして表示します。
	 *
	 */
	open: function () {
	
		// ダイアログボックス表示
		alert(this.message);
	
		// 関数の実行
		this.onClick();

	}
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
/**
 * JavaScriptのダイアログ表示クラスのインスタンスを生成するためのクラスです。
 *
 */
maskat.lang.Class.declare("maskat.ui.JavaScriptDialogFactory")
	.extend("maskat.ui.DialogFactory", {
	
	_static: {
		/**
		 * このクラスの唯一のインスタンスを返します。(Singleton パターン)
		 *
		 * @return このクラスの唯一のインスタンス
		 */
		getInstance: function(){
			var self = arguments.callee;
			if (!self.instance) {
				self.instance = new this();
			}
			return self.instance;
		}
	},

	/**
	 * 確認ダイアログを表示するためのクラスを生成します。
	 *
	 * @param title ダイアログのタイトル文字列
	 * @param message ダイアログメッセージ文字列
	 * @param icon アイコン種別
	 * @param onClick ボタン押下時の呼び出し先関数名
	 */
	createMessage: function (title, message, icon, onClick) {
		return new maskat.ui.JavaScriptMessageDialog (title, message, icon, onClick);
	},
	
	/**
	 * アラートダイアログを表示するためのクラスを生成します。
	 *
	 * @param title ダイアログのタイトル文字列
	 * @param message ダイアログメッセージ文字列
	 * @param onClick ボタン押下時の呼び出し先関数名
	 */
	createAlert: function (title, message, icon, onClick) {
		return new maskat.ui.JavaScriptAlertDialog (title, message, icon, onClick);
	},
	
	/**
	 * 入力ダイアログを表示するためのクラスを生成します。
	 *
	 * @param title ダイアログのタイトル文字列
	 * @param message ダイアログメッセージ文字列
	 * @param onClick ボタン押下時の呼び出し先関数名
	 */
	createInput: function (title, message, icon, onClick) {
		return new maskat.ui.JavaScriptInputDialog (title, message, icon, onClick);
	},
	
	/**
	 * 進捗表示ダイアログを表示するためのクラスを生成します。
	 *
	 * @param title ダイアログのタイトル文字列
	 * @param message ダイアログメッセージ文字列
	 * @param goalValue 終了進捗値(オプション)
	 */
	createProgress: function (title, message, goalValue) {
		return new maskat.ui.JavaScriptProgressDialog (title, message, goalValue);
	}
	
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.ui.JavaScriptInputDialog")
	.extend("maskat.ui.InputDialog", {

	/**
	 * javascriptの入力ダイアログコンストラクタ
	 *
	 * @param title ダイアログのタイトル文字列
	 * @param message ダイアログメッセージ文字列
	 * @param icon アイコン種別
	 * @param onClick ボタン押下時の呼び出し先関数名
	 */
	initialize: function (title, message, icon, onClick) {
		/* 引数を内部メンバとして設定 */
		this.base.apply(this, arguments);
	},

	/**
	 * javascriptの入力ダイアログをPOPUPして表示します。
	 *
	 */
	open: function () {
	
		/* ダイアログボックス表示と関数の実行 <CANCEL時はnull> */
		this.onClick (prompt (this.message,"") );

	}
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.ui.JavaScriptMessageDialog")
	.extend("maskat.ui.MessageDialog", {

	/**
	 * javascriptの確認ダイアログコンストラクタ
	 * 引数のtitle, iconは無視されます
	 *
	 * @param title ダイアログのタイトル文字列
	 * @param message ダイアログメッセージ文字列
	 * @param icon アイコン種別
	 * @param onClick ボタン押下時の呼び出し先関数名
	 */
	initialize: function (title, message, icon, onClick) {
		/* 引数を内部メンバとして設定 */
		this.base.apply(this, arguments);
	},

	/**
	 * javascriptの確認ダイアログをPOPUPして表示します。
	 *
	 */
	open: function () {
	
		/* ダイアログボックス表示 */
		var returnValue = confirm(this.message);
		
		/* 関数の実行 */
		this.onClick (returnValue ? maskat.ui.Dialog.OK : maskat.ui.Dialog.CANCEL);
		
	}
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.ui.JavaScriptProgressDialog")
	.extend("maskat.ui.ProgressDialog", {

	/**
	 * javascriptの進捗ダイアログコンストラクタ
	 *
	 * @param title ダイアログのタイトル文字列
	 * @param message ダイアログメッセージ文字列
	 * @param total 終了進捗値(オプション) または、doneを実行するまで終了しない処理中表示(POSITIVE_INFINITY)
	 */
	initialize: function (title, message, total) {
	
		/* 引数を内部メンバとして設定 */
		this.base.apply(this, arguments);
		
		/* totalのデフォルト設定 */
		if (!this.total || this.total == "") {
			this.total = 100;
		}
		
		/* 表示タイプの判定 */
		this.endlessMode = false;
		if (this.total == Number.POSITIVE_INFINITY) {
			this.endlessMode = true;
			this.total = 100;
		}
		
		/* 改行文字列の置換 */
		if (typeof(this.message) == "string") {
			this.message = this.message.replace( /\r?\n/g, "<br />\n");
		}
		
		/* ウインドウサイズを取得 (最小サイズ幅:500 高:50)  */
		this.getOffset (250, 50);
		/* 進捗バーの幅 */
		this.barWidth = this.width * 0.9;
		/* 進捗の最大値 */
		this.total = this.total ? this.total : 100;
		/* カレントの進捗値 */
		this.count = 0;
		/* 進捗バーのElement ID */
		this.barElementId = "";
		/* 進捗バーのElement ID */
		this.barElementId = "";
	},

	/**
	 * javascriptの進捗ダイアログをPOPUPして表示します。
	 *
	 */
	open: function () {
	
		/* ダイアログボックス表示 */
		if (!this.popup || this.popup.closed) {
			var windowParameter = "width=" + this.width;
			windowParameter += ",height=" + this.height;
			windowParameter += ",resizable=no,scrollbars=no,directories=no,location=no,menubar=no,status=no,toolbar=no";
			this.popup = window.open ("",
							this.title,
							windowParameter); 
		}else{
		    /*  既にウィンドウが開いている場合はフォーカスを当てる */
		    this.popup.focus();
		}
		
		/* Title, Bodyの設定 */
		bar = this.popup.document;
		bar.open();
		bar.write("<head><title>" + this.title + "</title></head>");
		bar.close();
		bar.bgColor = "#DCDCDC"
		
		/* メッセージの表示 */
		var divMsg = bar.createElement ("div");
		divMsg.id = 'processingMessage';
		divMsg.innerHTML = this.message;
		bar.body.appendChild(divMsg);
		
		/* 進捗バーの位置・サイズ算出 */
		var barHeight = 16; 
		this.barWidth = this.width * 0.9;
		var barTop = this.height - (barHeight + 20);
		var barLeft = this.width * 0.02;
		
		if (this.endlessMode) {
			
			/* 進捗バー表示枠の設定 */
			var barProgress = bar.createElement ("div");
			barProgress.id = 'pbar';
			barProgress.style.top = barTop;
			barProgress.style.left =(this.width - this.barWidth) / 2;
			barProgress.style.position = "absolute";

			/* 進捗バーの設定 */
			var imagePath = maskat.location + "core/images/"
			var imgTag = bar.createElement("img");
			imgTag.src = imagePath + "endless_progress.gif";
			imgTag.width = this.barWidth ;
			imgTag.height = 14;
			
			barProgress.appendChild(imgTag);
			bar.body.appendChild(barProgress);
		
		} else {
		
			/* 進捗率の表示 */
			var rateMargine = 35;
			this.barWidth = this.barWidth - rateMargine;
			this.textRate = bar.createElement ("div");
			this.textRate.id = "rate";
			this.textRate.innerHTML = "0%";
			this.textRate.style.position = "absolute";
			this.textRate.style.top = barTop;
			this.textRate.style.left = barLeft;
			bar.body.appendChild (this.textRate);
			
			/* 進捗バー枠の表示 */
			var divBar = bar.createElement ("div");
			divBar.id = 'barBorder';
			divBar.className = "progressBar";
			divBar.style.top = barTop;
			divBar.style.left = barLeft + rateMargine;
			divBar.style.width = this.barWidth;
			divBar.style.height = barHeight;
			divBar.style.backgroundColor = "white"; 
			divBar.style.borderColor = "black";
			divBar.style.borderStyle = "solid";
			divBar.style.borderWidth = "1px"; 
			divBar.style.position = "absolute";
			bar.body.appendChild(divBar);
			
			/* 進捗バーの設定 */
			var barColor = "#003399";
			var barProgress = bar.createElement ("div");
			barProgress.id = 'pbar';
			barProgress.style.top = barTop;
			barProgress.style.left = barLeft + rateMargine;
			barProgress.style.width = 0;
			barProgress.style.height = barHeight;
			barProgress.style.backgroundColor = barColor;
			barProgress.style.borderColor = barColor;
			barProgress.style.borderStyle = "solid";
			barProgress.style.borderWidth = "1px"; 
			barProgress.style.position = "absolute";
			bar.body.appendChild (barProgress);
		}
		return this.popup;

	},
	
	/**
	 * javascriptの進捗状況ウィンドウの進捗状況を更新します。
	 *
	 * @param count 進捗総数
	 */
	setProgress:function (count) {
		if (!this.isNumeric(count)) {
		    return;
		}
		this.count = count;
		/* トータルを超えている場合 */
		if (this.count > this.total) {
			this.count = this.total;
		}
		/* マイナス値の場合 */
		if (this.count < 0) {
			this.count = 0;
		}
		/* 表示の更新 */
		this.updateProgress();
		/* 終了時のClose */
		try {
		    this.popup.window.closed;
		} catch (e) {
		    this.popup = null;
		}
		if (this.count >= this.total) {
			if(this.popup) {
				this.popup.window.close();
				this.popup = null;
			}
		}
	},
	
	/**
	 * javascriptの進捗状況ウィンドウの進捗状況を加算更新します。
	 *
	 * @param addValue 進捗数
	 */
	worked:function (addValue) {
		if (this.isNumeric(addValue)) {
		    this.setProgress (Number(addValue) + Number(this.count));
		} else {
		    return;
		}
	},
	
	/**
	 * 進捗状況ウィンドウを閉じます。
	 *
	 */
	done: function() {
		this.setProgress(this.total);
	},
	
	/**
	 * 進捗状況ウィンドウの進捗状況を更新します。
	 *
	 */
	updateProgress: function () {
	
		/* 進捗率表示無し */
		if (this.endlessMode) {
			return;
		}
		/* 更新対象の存在チェック */
		if (!this.popup || this.popup.closed) {
		    return;
		}else{
		    this.popup.focus();
		}
		/* 進捗率の計算 */
		var rate = this.count * 100 / this.total;
		this.popup.document.getElementById ('rate').innerHTML 
					= Math.round (rate) + "%"; 
		/* 進捗バーの更新 */
		this.popup.document.getElementById ('pbar').style.width 
					= (this.barWidth * rate) / 100;

	},
	
	/**
	 * ダイアログサイズを算出します
	 *
	 * @param minWidth 最小幅
	 * @param minHeight 最小高さ
	 */
	getOffset: function (minWidth, minHeight) {
		var div = document.createElement("DIV");
		div.innerHTML = this.message;
		div.style.position = "absolute";
		div.style.visibility = "hidden";
		div.style.whiteSpace = "nowrap";
		document.body.appendChild(div);
		this.width = div.offsetWidth < minWidth ? minWidth : div.offsetWidth + 0;
		this.width = this.width * 1.05;
		this.height = div.offsetHeight < minHeight ? minHeight : div.offsetHeight;
		this.height += 50;
		document.body.removeChild(div);
		div = null;
	},

	/**
	 * 先頭にプラス・マイナスを含んだ数字であることをチェックします。
	 *
	 */
	isNumeric: function (value) {
	    if (typeof(value) != "string") { 
	        return true;
	    }
		return value.match(/[^+^-][\D]/g) ? false : true;
	},
	
	/**
	 * 表示中のメッセージを置き換えます
	 * 制限として、メッセージの長さによるウィンドウのリサイズは行いません
	 *
	 * @param newMessage 置き換え後のメッセージ
	 */
	replaceMessage: function (newMessage) {

		if (!this.popup || this.popup.closed) {
			/* ウィンドウが無いので無視 */
			return;
		}else{
		    /*  フォーカスを当てる */
		    this.popup.focus();
		}
	
		if (typeof(newMessage) != "string") { 
			return true;
		}

		var bar = this.popup.document;
		
		newMessage = newMessage.replace( /\r?\n/g, "<br />\n"); 
		bar.getElementById('processingMessage').innerHTML = newMessage;
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.ui.MessageDialog", {

	/**
	 * javascriptの確認ダイアログコンストラクタ
	 *
	 * @param title ダイアログのタイトル文字列
	 * @param message ダイアログメッセージ文字列
	 * @param icon アイコン種別
	 * @param onClick ボタン押下時の呼び出し先関数名
	 */
	initialize: function (title, message, icon, onClick) {
		this.title = title;
		this.message = message;
		this.icon = icon;
		this.onClick = onClick;
		/* 戻り関数の存在チェック、無いときはEmpty関数をセット*/
		if (typeof(this.onClick) != "function") {
			this.onClick = maskat.lang.EmptyFunction;
		}
	},

	/**
	 * 確認ダイアログをPOPUPして表示します。
	 *
	 */
	open: function () {
		/* NOP */
	}
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.ui.ProgressDialog", {

	/**
	 * javascriptの進捗ダイアログコンストラクタ
	 *
	 * @param title ダイアログのタイトル文字列
	 * @param message ダイアログメッセージ文字列
	 * @param total 終了進捗値(オプション)
	 */
	initialize: function (title, message, total) {
		this.title = title;
		this.message = message;
		this.total = total;
	},

	/**
	 * 進捗ダイアログをPOPUPして表示します。
	 *
	 */
	open: function () {
		/* NOP */
	},
	/**
	 * javascriptの進捗状況ウィンドウの進捗状況を更新します。
	 *
	 * @param count 進捗総数
	 */
	setProgress:function (count) {
		/* NOP */
	},
	/**
	 * javascriptの進捗状況ウィンドウの進捗状況を加算更新します。
	 *
	 * @param count 進捗数
	 */
	worked:function (count) {
		/* NOP */
	},
	/**
	 * 進捗ダイアログを閉じます。
	 *
	 */
	done: function () {
		/* NOP */
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * JavaScript におけるデータ型の変換を行います。
 *
 * このクラスの基本的な用途は、文字列をオブジェクトやプリミティブに変換する
 * ことです。コンバータ関数を定義することにより、変換可能なデータ型の種類を
 * 追加することができます。
 *
 * このクラスは static メソッドのみを持つユーティリティクラスであり、
 * インスタンス化する必要はありません。
 */
maskat.lang.Class.declare("maskat.util.Converter", {

	_static: {
		/**
		 * コンバータ関数のレジストリ
		 *
		 * プロパティ名: 変換先の型を表す文字列
		 * プロパティ値: コンバータ関数
		 */
		converters: {
			"boolean": function(value){
				switch (typeof(value)) {
				case "boolean":
					return value;
				case "string":
					value = maskat.lang.String.trim(value).toLowerCase();
					if (value == "true") {
						return true;
					} else if (value == "false") {
						return false;
					}
				default:
					return undefined;
				} 
			},
			
			"number": function(value){
				switch (typeof(value)) {
				case "number":
					return value;
				case "string":
					if (isNaN(value)) {
						return undefined;
					}
					if (value.indexOf(".") == -1) {
						return parseInt(value, 10);
					} else {
						return parseFloat(value);
					}
				default:
					return undefined;
				} 
			},
			
			"string": function(value){
				if (typeof(value) == "string") {
					return value;
				} else {
					return value.toString();
				}
			},
			
			"enum": function(value, options){
				if (typeof(value) == "string" && options.values) {
					if (options.values instanceof Array) {
						for (var i = 0; i < options.values.length; i++) {
							if (value == options.values[i]) {
								return value;
							}
						}
					} else {
						for (var key in options.values) {
							if (value == key) {
								return options.values[key];
							}
						}
					}
				}
				return undefined;
			},
			
			"object": function(value){
				switch (typeof(value)) {
				case "object":
					return value;
				case "string":
					return maskat.lang.Object.find(value);
				default:
					return undefined;
				} 
			},
			
			"function": function(value){
				switch (typeof(value)) { 
				case "function":
					return value;
				case "string":
					var func = maskat.lang.Object.find(value);
					if (func && typeof(func) == "function") {
						return func;
					}
					throw new maskat.lang.Error("MISSING_FUNCTION",
						{ functionName: value });
				default:
					return undefined;
				}
			},

			"RegExp": function(value){
				switch (typeof(value)) {
				case "object":
					return (value instanceof RegExp) ? value : undefined;
				case "string":
					return new RegExp(value);
				default:
					return undefined;
				} 
			},

			"HTMLElement": function(value){
				switch (typeof(value)) {
				case "object":
					return (value instanceof HTMLElement) ? value : undefined;
				case "string":
					return document.getElementById(value);
				default:
					return undefined;
				} 
			}
		},
		
		/**
		 * 指定された値 (オブジェクト) を指定した型に変換します。
		 * 変換に失敗した場合には例外がスローされます。
		 *
		 * @param type 変換先の型
		 * @param value 変換元の値
		 * @param options 変換オプション
		 *
		 * @return 変換された値
		 */
		convert: function(type, value, options){
			if (!this.converters[type]) {
				throw new maskat.lang.Error("UNKNOWN_CONVERTER_TYPE",
					{ type: type, value: value });
			}

			var result = this.converters[type](value, options);
			if (result === undefined) {
				throw new maskat.lang.Error("CONVERTER_ERROR",
					{ type: type, value: value });
			}
			return result;
		}
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * ブラウザ依存の処理をカプセル化します。
 *
 * このクラスは static メソッドのみを持つユーティリティクラスであり、
 * インスタンス化する必要はありません。
 */
maskat.lang.Class.declare("maskat.util.CrossBrowser", {

	_static: {
		/**
		 * 新しい XMLHttpRequest を生成します。
		 *
		 * @return XMLHttpRequest のインスタンス
		 */
		createXMLHttpRequest: function(){
			var xhr;
			
			if (window.XMLHttpRequest &&
				(navigator.appName != "Microsoft Internet Explorer" ||
				 window.location.protocol != "file:")) {
				
				xhr = new XMLHttpRequest();
			} else if (window.ActiveXObject) {
				try {
					xhr = new ActiveXObject("Msxml2.XMLHTTP");
				} catch (e) {
					try {
						xhr = new ActiveXObject("Microsoft.XMLHTTP");
					} catch (e) { /* suppress */ }
				}
			}

			if (!xhr) {
				throw new maskat.lang.Error("CREATEXHR_ERROR",
					{ agent: navigator.userAgent });
			}
			return xhr;
		},

		/**
		 * XMLHttpRequest に通信エラーが発生しているかどうかを確認し、通信
		 * エラーの場合には例外をスローします。
		 *
		 * @throws maskat.lang.Error 通信エラーが発生している場合
		 */
		checkHttpError: function(xhr) {
			var err = this.getHttpError(xhr);
			if (err) {
				throw err;
			}
		},
		
		getHttpError: function(xhr) {
			try {
				if (xhr.readyState != 4 || xhr.status != 200) {
					switch (xhr.status) {
					case 0:
						return undefined;
					case 403:
					case 404:
					case 500:
						return new maskat.lang.Error("HTTP_" + xhr.status,
							{ status: xhr.status, url: xhr.statusText });
					default:
						/*
						 * IE独自のエラー(12002-12152)が発生した場合、
						 * statusTextには "Unknown"が格納される。
						 */
						var url = xhr.statusText != "Unknown" ? xhr.statusText : "";
						return new maskat.lang.Error("HTTP_DEFAULT",
							{ status: xhr.status, url: url });
					}
				}
			} catch (e) {
				/*
				 * Firefox ではサーバサイドがダウンしている状態で send した
				 * XHRの status, statueTextにアクセスするとエラーが発生する。
				 * そのための catch 処理
				 */
				return new maskat.lang.Error("HTTP_ERROR");
			}
		},

		/**
		 * HTTP GET メソッドを用いた同期通信で XML 文書を取得し、Document
		 * ノードを返します。
		 *
		 * @return 取得した XML 文書の Document ノード
		 */
		getXMLDocumentFrom: function(url){
			var xhr = this.createXMLHttpRequest();
			
			try {
				xhr.open("GET", url, false);
				xhr.send(null);
				
			} catch (e) {
				throw new maskat.lang.Error("HTTP_404",
					{ status: 404, url: url });
			}
			if (xhr.readyState == 4) {
				switch (xhr.status) {
				case 200:
					this.checkParseError(xhr.responseXML);
					if (xhr.responseXML && xhr.responseXML.nodeType == 9) {
						return xhr.responseXML;
					}
					break;
				case 0:
					/* ローカル環境の場合 responseText から DOM を生成 */
					if (document.location.protocol == "file:" && xhr.responseText) {
						var doc = this.parseXMLDocument(xhr.responseText);
						this.checkParseError(doc);
						return doc;
					}
					break;
				default:
					this.checkHttpError(xhr);
				}
			}
		},

		/**
		 * HTTP GET メソッドを用いた同期通信でテキストを取得します。
		 *
		 * @return 取得したテキスト
		 */
		getTextFrom: function(url){
			var xhr = this.createXMLHttpRequest();
			try {
				xhr.open("GET", url, false);
				xhr.send(null);
			} catch (e) {
				throw new maskat.lang.Error("HTTP_404",
					{ status: 404, url: url });
			}
			this.checkHttpError(xhr);
			return xhr.responseText;
		},

		/**
		 * XML 文書の文字列表現から DOM オブジェクトを構築し、Document
		 * ノードを返します。
		 *
		 * @return XML 文書の Document ノード
		 */
		parseXMLDocument: function(source){
			var doc;
			if (window.DOMParser) {
				doc = (new DOMParser()).parseFromString(source, "text/xml");
			} else if (window.ActiveXObject) {
				doc = new ActiveXObject("MSXML2.DOMDocument");
				doc.async = false;
				doc.resolveExternals = false;
				doc.validateOnParse = false;
				doc.loadXML(source);
			}
			return doc;
		},
		
		/**
		 * XML 文書に解析エラーが発生しているかどうかを確認し、解析エラーの
		 * 場合には例外をスローします。
		 *
		 * @throws maskat.lang.Error 解析エラーが発生している場合
		 */
		checkParseError: function(xml) {
			if (xml.parseError && xml.parseError.errorCode < 0) {
				/* IE */
				var p = xml.parseError;
				var param = {
					msg: p.reason,
					line: p.line,
					pos: p.linepos,
					text: p.srcText
				};
				throw new maskat.lang.Error("PARSEERROR_IE", param);
			} else if (xml.documentElement &&
					   xml.documentElement.tagName == "parsererror") {
				/* Firefox */
				throw new maskat.lang.Error("PARSEERROR_DEFAULT",
					{ msg: xml.documentElement.textContent });
			}
		},

		/**
		 * HTTP GET メソッドを用いた同期通信で JSON 形式のリテラル文字列を
		 * 取得し、それを評価したオブジェクトを返します。
		 *
		 * @return オブジェクト
		 */
		loadJSONFrom: function(url){
			return this.parseJSON(this.getTextFrom(url));
		},
		
		/**
		 * JSON (JavaScript Object Notation) で記述されたリテラルを評価して
		 * オブジェクトを返します。
		 *
		 * @return オブジェクト
		 */
		parseJSON: function(text){
			/* JSON パーサが読み込まれている場合は利用する */
			if (typeof(JSON) != "undefined" && typeof(JSON.parse) == "function") {
				return JSON.parse(text);
			}
			return eval("(" + text + ")");
		},
		
		/**
		 * HTML 要素にイベントリスナを追加します。
		 *
		 * このメソッドで追加されたイベントリスナはバブリング段階で実行
		 * されます。
		 *
		 * @param node リスナを追加する HTML 要素
		 * @param eventType イベントタイプ
		 *        "click", "focus", "blur" など、先頭に "on" を含まない文字列
		 * @param listener イベントリスナとして追加される関数
		 *
		 * @return XML 文書の Document ノード
		 */
		addEventListener: function(node, eventType, listener){
			if (node.addEventListener) {
				node.addEventListener(eventType, listener, false);
			} else if (node.attachEvent) {
				node.attachEvent("on" + eventType, listener);
			} else if (node["on" + eventType]) {
				node["on" + eventType] = listener;
			}
		}
	}
});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.util.Message", {

	_static: {
		templates: {
			"CREATEXHR_ERROR": "XMLHttpRequestが生成できません。\n#{agent}",
			"HTTP_403": "HTTP #{status} - 指定されたURLにアクセスする権限がありません。\n#{url}",
			"HTTP_404": "HTTP #{status} - 指定されたURLは見つかりません。\n#{url}",
			"HTTP_500": "HTTP #{status} - 内部サーバエラーが発生しました。\n#{url}",
			"HTTP_ERROR": "サーバとの通信に失敗しました。\nサーバが落ちている可能性があります。",
			"HTTP_DEFAULT": "HTTP #{status} - サーバとの通信に失敗しました。\n#{url}",
			"PARSEERROR_IE": "#{msg} 行番号: #{line}  列番号:#{pos} #{text}",
			"PARSEERROR_DEFAULT" : "#{msg}",
			"UNDEFINED_VARIABLE": "レイアウト #{layoutId} に変数 #{name} が宣言されていません。",
			"DUPLICATED_VARIABLE": "レイアウト #{layoutId} に変数 #{name} がすでに宣言されています。",
			"MISSING_WIDGET": "レイアウト #{layoutId} にマスカット部品 #{widgetId} が定義されていません。",
			"REQUEST_BIND_ERROR" : "要求メッセージのデータバインドに失敗しました。widgetId=#{widgetId}, eventType=#{type}",
			"RESPONSE_BIND_ERROR" : "応答メッセージのデータバインドに失敗しました。widgetId=#{widgetId}, eventType=#{type}",
			"RESPONSE_TIMEOUT" : "タイムアウトが発生しました。widgetId=#{widgetId}, eventType=#{type}",
			"INTERRUPTION_ERROR": "ユーザ定義関数によりイベント処理が停止されました。",
			"SYNC_EVENT_IN_PROGRESS": "通信中です。しばらくお待ちください...",
			"XML_LOAD_ERROR": "XML の読み込みに失敗しました: #{url}",
			"ELEMENT_READ_ERROR": "#{elementName} 要素の読み込みに失敗しました。",
			"UNKNOWN_NS_URI": "未知の名前空間 URI です: #{uri}",
			"UNKNOWN_ELEMENT": "未知の XML 要素です: #{elementName}",
			"ATTRIBUTE_READ_ERROR": "#{elementName} 要素の属性 #{attributeName} の読み込みに失敗しました。",
			"MISSING_ATTRIBUTE": "必須属性 #{attributeName} が定義されていません。",
			"UNKNOWN_ATTRIBUTE": "#{elementName} 要素に未知の属性 #{attributeName} が定義されています。",
			"MISSING_FUNCTION": "関数 #{functionName} は定義されていません。",
			"INVALID_CHILD_ELEMENT": "#{childName} は #{elementName} の子要素にすることはできません。",
			"INVALID_ROOT_NODE": "#{elementName} は無効なルートノードです。",
			"MISSING_CHILD_ELEMENT": "#{elementName} 要素の子要素 #{childName} を省略することはできません。",
			"DUPLICATED_CHILD_ELEMENT": "#{elementName} 要素に子要素 #{childName} を複数回定義することはできません。",
			"LOG_FACTORY_INIT_FAILED": "ログファクトリの初期化に失敗しました: #{className}",
			"UNKNOWN_CONVERTER_TYPE": "未知のデータ型です。 #{type}",
			"CONVERTER_ERROR": "データ型の変換に失敗しました。データ型: #{type}, 値: #{value}"
		},

		loadTemplates: function(url) {
			maskat.lang.Object.populate(this.templates,
				maskat.util.CrossBrowser.loadJSONFrom(url)); 
		},

		format: function(key, values) {
			var template = this.templates[key];
			if (values && template) {
				replacer = function(str, p1, offset, s){ return values[p1]; };
				template = template.replace(/#{(.*?)}/g, replacer);
			}
			return template;
		}
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * キーと値が対になったプロパティを取得・格納する機能を持ったクラスです。
 * プロパティにはキーごとに型とデフォルト値を定義できます。
 *
 *  - 型が指定された場合、プロパティ値の格納時に自動的に型変換が行われます。
 *  - デフォルト値が指定されている場合、プロパティ値が格納されていなければ
 *    デフォルト値を値として返却します。
 */
maskat.lang.Class.declare("maskat.util.Properties", {

	/**
	 * コンストラクタ
	 *
	 * @param descriptors プロパティ記述子
	 *     {
	 *         プロパティキー: { 
	 *             type: プロパティの型を表す文字列
	 *             defaultValue: デフォルト値
	 *         },
	 *
	 *         プロパティキー: { ... },
	 *         ...
	 *     }
	 */
	initialize: function(descriptors) {
		this.types = {};
		this.defaults = {};
		this.values = {};

		for (var key in descriptors) {
			var desc = descriptors[key];
			this.defineProperty(key, desc.type, desc.defaultValue);
		}
	},

	/**
	 * 新しいプロパティキーを宣言します。
	 *
	 * @param key プロパティキー
	 * @param type プロパティの型を表す文字列
	 *             maskat.util.Converter がサポートする型を指定します。
	 * @param defaultValue デフォルト値
	 */
	defineProperty: function(key, type, defaultValue) {
		this.types[key] = type;
		this.defaults[key] = defaultValue;

		/* プロパティの値がすでに格納されている場合は型を変換 */		
		if (this.values[key]) {
			this.setProperty(key, this.values[key]);
		}
	},

	/**
	 * 指定したキーに対応するプロパティ値を格納します。
	 *
	 * @param key プロパティキー
	 * @param value プロパティの値
	 */
	setProperty: function(key, value) {
		var type = this.types[key];
		if (type) {
			value = maskat.util.Converter.convert(type, value);
		}
		this.values[key] = value;
	},

	/**
	 * プロパティキーと値が対になったオブジェクトから、プロパティ値を
	 * すべて読み込みます。
	 *
	 * @param values プロパティキーと値が対になったオブジェクト 
	 */
	setProperties: function(values) {
		for (var key in values) {
			this.setProperty(key, values[key]);
		}
	},

	/**
	 * 指定された URL から HTTP GET メソッドで JSON 形式のリテラル文字列を
	 * 取得し、そこからプロパティキーと値を読み込みます。
	 *
	 * @param url JSON ファイルを取得する URL
	 */
	load: function(url) {
		this.setProperties(maskat.util.CrossBrowser.loadJSONFrom(url));
	},

	/**
	 * 指定したキーに対応するプロパティ値を返します。
	 *
	 * @return 指定したキーに対応するプロパティ値 
	 */
	getProperty: function(key) {
		return this.values[key] || this.defaults[key];
	},

	/**
	 * すべてのプロパティキーと値が対になったオブジェクトを返します。
	 *
	 * @return プロパティキーと値が対になったオブジェクト 
	 */
	getProperties: function() {
		var result = {};
		var key;

		/* デフォルト値を result オブジェクトに格納 */
		for (key in this.defaults) {
			result[key] = this.defaults[key];
		} 

		/* プロパティ値を result オブジェクトに格納 */
		for (key in this.values) {
			result[key] = this.values[key];
		} 

		return result;
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.xml.AttributeBinding", {

	/**
	 * コンストラクタ
	 *
	 * @param name XML 属性のローカル名
	 * @param config バインディング設定
	 *     {
	 *        type:
	 *            属性の型を表す文字列 ("string", "number", "boolean" など)
	 *            指定可能な型は maskat.util.Converter を参照してください。
	 *
	 *        required:
	 *            必須属性の場合 true、省略可能の場合は false
	 *
	 *        defaultValue:
	 *            属性値が省略された場合のデフォルト値
	 *
	 *        property:
	 *            属性名と対応するオブジェクトのプロパティ名
	 *
	 *        value:
	 *            属性値のリテラル
	 *            読み込み時は常に一定の属性値が記述されていることを要求し、
	 *            書き込み時は固定値で属性値を書き出します。
	 *     }
	 */
	initialize: function(name, config) {
		this.name = name;
		this.type = config.type || "string";
		this.required = config.required || false;
		this.property = config.property || name;
		this.value = config.value;
		this.options = config;
		
		if (typeof(config.defaultValue) != "undefined") {
			this.defaultValue = maskat.util.Converter.convert(
				this.type, config.defaultValue, this.options);
		}
	},

	/**
	 * オブジェクトに XML 属性の値を読み込みます。
	 *
	 * @param object 値を格納するオブジェクト
	 * @param attribute XML 属性ノード
	 */
	read: function(object, attribute) {
		var value = this.value || (attribute && attribute.nodeValue);
		if (value || value === "") {
			object[this.property] = maskat.util.Converter.convert(
				this.type, value, this.options);
		} else if (this.required) {
			throw new maskat.lang.Error("MISSING_ATTRIBUTE",
				{ attributeName: this.name });
		} else if (typeof(this.defaultValue) != "undefined") {
			object[this.property] = this.defaultValue;
		}
	},

	/**
	 * オブジェクトのプロパティ値を XML 属性の形式で文字列バッファに
	 * 書き出します。
	 *
	 * @param object プロパティ値を取得するオブジェクト
	 * @param buffer 文字列バッファ
	 */
	write: function(object, buffer) {
		var value = this.value || object[this.property];
		if (typeof(value) != "undefined") {
			if (this.defaultValue !== value) {
				if (typeof(value) == "function") {
					value = value.toString().match(/function (\w+)/);
					value = value ? value[1] : "[function]";
				}
				buffer.push(" " + this.name + "=\"" + value + "\"");
			}
		} else if (this.required) {
			throw new maskat.lang.Error("MISSING_ATTRIBUTE",
				{ attributeName: this.name });
		}
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.xml.CDATASectionBinding", {

	/**
	 * CDATA セクションに含まれる文字列を返します。
	 *
	 * @param object オブジェクト
	 * @param cdata CDATA セクションノード
	 */
	read: function(object, cdata) {
		return cdata.nodeValue;
	},

	/**
	 * オブジェクトを CDATA セクションの形式で文字列バッファに書き出します。
	 *
	 * @param object オブジェクト
	 * @param buffer 文字列バッファ
	 */
	write: function(object, buffer) {
		buffer.push("<![CDATA[" + object + "]]>");
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.xml.ChildNodeBinding", {

	/**
	 * 子要素のバインディング設定を定義します。
	 *
	 * この XML 要素に対応するオブジェクト (親オブジェクト) は指定された
	 * プロパティを用いて子要素に対応するオブジェクト (子オブジェクト) を
	 * 参照します。
	 *
	 * @param binder このバインディングを使用する XMLObjectBinder
	 * @param name XML 要素のローカル名
	 * @param config バインディング設定
	 *     {
	 *         property:
	 *             親オブジェクトから子オブジェクトを参照するプロパティ名
	 *             property を省略した場合、親要素と子要素は同じオブジェクト
	 *             にマッピングされます。
	 *
	 *         required:
	 *             子要素の存在が必須の場合 true、省略可能の場合は false
	 *
	 *         repeat:
	 *             子要素が繰り返し出現可能の場合は true
	 *             repeat が指定された場合、親オブジェクトのプロパティは
	 *             子オブジェクトの配列にマッピングされます。
     *
	 *         key:
	 *             子要素が繰り返し出現する場合に、子オブジェクトを一意に識別
	 *             するためのインデックスとして使用するプロパティ名
	 *             repeat と組み合わせて指定します。key が指定された場合には
	 *             親オブジェクトのプロパティはハッシュにマッピングされます。
	 *
	 *         value:
	 *             プロパティの値となる子オブジェクトのプロパティ名
	 *             value が指定されている場合、親オブジェクトのプロパティは
	 *             子オブジェクトのプロパティへの参照となります。
	 *     }
	 */
	initialize: function(binder, uri, name, config) {
		this.binder = binder;
		this.uri = uri;
		this.name = name;

		config = config || {};
		this.property = config.property;
		this.method = config.method;
		this.validate = config.validate !== false;
		this.required = config.required || false;
		this.repeat = config.repeat || false;
		this.key = config.key;
		this.value = config.value;
	},

	read: function(object, element) {
		try {
			var binding = this.binder.getElementBinding(element);
		} catch (e) {
			if (this.validate) {
				throw e;
			} else {
				return;
			}
		}

		var value;
		if (typeof(this.property) != "undefined") {
			value = binding.read(null, element);
		} else {
			value = binding.read(object, element);
		}

		if (this.method) {
			object[this.method](value);
		} else if (typeof(this.property) != "undefined") {
			if (this.repeat) {
				if (this.key) {
					if (!object[this.property]) {
						object[this.property] = {};
					}
					var key = value[this.key];
					if (this.value) {
						object[this.property][key] = value[this.value];
					} else {
						object[this.property][key] = value;
					}
				} else {
					if (!object[this.property]) {
						object[this.property] = [];
					}
					if (this.value) {
						object[this.property].push(value[this.value]);
					} else {
						object[this.property].push(value);
					}
				}
			} else {
				object[this.property] = value;
			}
		}
	},

	write: function(object, buffer) {
		if (typeof(this.property) != "undefined") {
			object = object[this.property];
		}
		if (typeof(object) == "undefined") {
			return;
		}

		var binding = this.binder.getElementBinding(this.uri, this.name); 
		if (this.repeat) {
			if (object instanceof Array) {
				for (var i = 0; i < object.length; i++) {
					if (this.value) {
						var wrapper = {};
						wrapper[this.value] = object[i];
						binding.write(wrapper, buffer);
					} else {
						binding.write(object[i], buffer);
					}
				}
			} else if (this.key) {
				for (prop in object) {
					if (this.value) {
						var wrapper = {};
						wrapper[this.key] = prop;
						wrapper[this.value] = object[prop];
						binding.write(wrapper, buffer);
					} else {
						binding.write(object[prop], buffer);
					}
				}
			}
		} else {
			binding.write(object, buffer);
		}
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.xml.DocumentBinding", {

	/**
	 * コンストラクタ
	 *
	 * @param binder このバインディングを使用する XMLObjectBinder
	 * @param uri ルート要素の名前空間 URI
	 * @param name ルート要素のローカル名
	 */
	initialize: function(binder, uri, name) {
		this.binder = binder;
		this.setRootElement(uri, name);
	},

	/**
	 * XML 文書のルート要素を設定します。
	 *
	 * @param uri ルート要素の名前空間 URI
	 * @param name ルート要素のローカル名
	 */
	setRootElement: function(uri, name) {
		this.uri = uri || "";
		this.name = name;
	},

	/**
	 * XML 文書の情報をオブジェクトに読み込み、そのオブジェクトを返します。
	 *
	 * @param doc XML 文書
	 *
	 * @return XML 文書の情報を読み込んだオブジェクト
	 */
	read: function(doc) {
		var element = doc.documentElement;
		var nodeName = element.localName || element.baseName;
		if (nodeName != this.name) {
			throw new maskat.lang.Error("INVALID_ROOT_NODE",
				{ elementName: nodeName });
		}
		
		var binding = this.binder.getElementBinding(element);
		return binding.read(null, element);
	},

	/**
	 * オブジェクトを XML 文書の形式で文字列バッファに書き出します。
	 *
	 * @param object オブジェクト
	 * @param buffer 文字列バッファ
	 */
	write: function(object, buffer) {
		buffer.push("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
		var binding = this.binder.getElementBinding(this.uri, this.name);
		binding.write(object, buffer);
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.xml.ElementBinding", {

	/**
	 * コンストラクタ
	 *
	 * @param binder このバインディングを使用する XMLObjectBinder
	 * @param name XML 要素の名前空間 URI
	 * @param name XML 要素のローカル名
	 * @param config バインディング設定
	 *     {
	 *        type: XML 要素の読み込み時に生成するオブジェクトの型
	 *
	 *        attributes:
	 *            プロパティ名 = XML 属性名
	 *            プロパティ値 = XML 属性のバインディング設定
	 *                           詳細は maskat.xml.AttributeBinding を参照
	 *
	 *        children:
	 *            プロパティ名 = 子要素の XML 要素名
	 *            プロパティ値 = 子要素のバインディング設定 
	 *                           詳細は addChildBinding メソッドを参照
	 *     }
	 */
	initialize: function(binder, uri, name, config) {
		this.binder = binder;
		this.uri = uri || "";
		this.name = name;
		this.type = config && config.type;
		this.children = {};
		this.attributes = {};

		if (config && config.attributes) {
			for (var attrName in config.attributes) {
				this.addAttributeBinding(attrName, config.attributes[attrName]);
			}
		}

		if (config && config.children) {
			for (var childName in config.children) {
				this.addChildBinding(childName, config.children[childName]);
			}
		}
	},

	addAttributeBinding: function(name, config) {
		var binding = new maskat.xml.AttributeBinding(name, config);
		this.attributes[name] = binding;
	},

	getChildBinding: function(uri, name) {
		if (typeof(uri) == "object") {
			var qname = uri;
			uri = qname.namespaceURI;
			name = qname.localName || qname.baseName || qname.nodeName;
		}

		var binding = this.children[name] || this.children["*"];
		if (!binding) {
			throw new maskat.lang.Error("INVALID_CHILD_ELEMENT",
				{ elementName: this.name, childName: name });
		}
		return binding;
	},

	addChildBinding: function(name, config) {
		var uri = (name.charAt(0) == "#") ? "" : this.uri;
		var binding = new maskat.xml.ChildNodeBinding(this.binder, uri, name, config);
		this.children[name] = binding;
	},

	/**
	 * XML 要素の情報をオブジェクトに読み込み、そのオブジェクトを返します。
	 *
	 * @param object 読み込み先のオブジェクト
	 *        null または undefined の場合は新しいオブジェクトを生成する
	 * @param element XML 要素
	 *
	 * @return XML 要素の情報を読み込んだオブジェクト
	 */
	read: function(object, element) {
		object = object || this.createObject(element);

		/* 属性の読み込み */
		var attributes = element.attributes;
		for (var i = 0; i < attributes.length; i++) {
			if (attributes[i].prefix == "xmlns") {
				/* XML 名前空間宣言を登録する */
				var attrName = attributes[i].localName || attributes[i].baseName;
				this.binder.addPrefixMapping(attrName, attributes[i].nodeValue);
			} else if (attributes[i].nodeName == "xmlns") {
				/* デフォルトの XML 名前空間宣言を登録する */
				this.binder.addPrefixMapping("", attributes[i].nodeValue);
			} else {
				/* その他の属性を読み込み */
				try {
					this.readAttribute(object, attributes[i]);
				} catch (e) {
					throw new maskat.lang.Error("ATTRIBUTE_READ_ERROR", {
						elementName: this.name,
						attributeName: attributes[i].nodeName
					}, e);
				}
			}
		}

		/* 省略された属性の読み込み (必須チェック／デフォルト値) */
		for (var name in this.attributes) {
			if (name != "*" && !element.getAttribute(name)) {
				try {
					this.attributes[name].read(object, null);
				} catch (e) {
					throw new maskat.lang.Error("ATTRIBUTE_READ_ERROR", {
						elementName: this.name,
						attributeName: name
					}, e);
				}
			}
		}

		/* 子要素の読み込み */
		var children = element.childNodes;
		var occurrence = {};
		for (var j = 0; j < children.length; j++) {
			/* 子要素の出現回数をカウントする */
			var childName = children[j].localName || children[j].baseName || children[j].nodeName;
			occurrence[childName] = (occurrence[childName] || 0) + 1;
		
			switch (children[j].nodeType) {
			case 1: /* Node.ELEMENT_NODE */
			case 4: /* Node.CDATA_SECTION_NODE */
				this.readChildElement(object, children[j]);
				break;
			case 3: /* Node.TEXT_NODE */
				if (!children[j].nodeValue.match(/^\s*$/)) {
					this.readChildElement(object, children[j]);
				}
				break;
			}
		}

		/* 子要素の出現回数のチェック */
		for (var name in this.children) {
			var config = this.children[name];
			if (config.required && !occurrence[name]) {
				/* 必須の子要素が省略されている場合はエラー */
				throw new maskat.lang.Error("MISSING_CHILD_ELEMENT", {
					elementName: this.name, childName: name	});
			}
			if (!config.repeat && occurrence[name] > 1) {
				/* 繰り返しできない子要素が繰り返された場合はエラー */
				throw new maskat.lang.Error("DUPLICATED_CHILD_ELEMENT", {
					elementName: this.name, childName: name	});
			}
		}

		return object;
	},

	/**
	 * XML 要素の読み込み先として使用する新しいオブジェクトを生成します。
	 *
	 * @param element XML 要素
	 *
	 * @return オブジェクト
	 */
	createObject: function(element) {
		try {
			if (this.type) {
				return new this.type();
			}
			return this.binder.createObject(element);
		} catch (e) {
			throw new maskat.lang.Error("ELEMENT_READ_ERROR",
				{ elementName: this.name }, e);
		}
	},

	readAttribute: function(object, attribute) {
		var name = attribute.localName || attribute.baseName;
		var binding = this.attributes[name];
		if (binding) {
			binding.read(object, attribute);
		} else if (this.attributes["*"]) {
			object[name] = attribute.nodeValue;
		} else {
			throw new maskat.lang.Error("UNKNOWN_ATTRIBUTE",
				{ elementName: this.name, attributeName: name });
		}
	},

	readChildElement: function(object, element) {
		var binding = this.getChildBinding(element);
		binding.read(object, element);
	},

	/**
	 * オブジェクトを XML 要素の形式で文字列バッファに書き出します。
	 *
	 * @param object オブジェクト
	 * @param buffer 文字列バッファ
	 */
	write: function(object, buffer) {
		var prefix = this.binder.getPrefix(this.uri);
		var nodeName = prefix ? (prefix + ":" + this.name) : this.name; 

		/* XML 要素の開始タグと属性を出力 */
		buffer.push("<" + nodeName);
		
		for (var attrName in this.attributes) {
			this.writeAttribute(attrName, object, buffer);
		}
		buffer.push(">");
		var length = buffer.length;

		/* 子要素を出力 */
		for (var name in this.children) {
			if (this.children[name].required && !object[name]) {
				throw new maskat.lang.Error("MISSING_CHILD_ELEMENT", {
					elementName: this.name, childName: name	});
			}
			this.writeChildElement(name, object, buffer);
		}

		/* 終了タグを出力 */
		if (buffer.length == length) {
			buffer[length - 1] = "/>";
		} else {
			buffer.push("</" + nodeName + ">");
		}
	},
	
	writeAttribute: function(name, object, buffer) {
		var binding = this.attributes[name];
		if (!binding) {
			throw new maskat.lang.Error("UNKNOWN_ATTRIBUTE",
				{ elementName: this.name, attributeName: name });
		}
		binding.write(object, buffer);
	},

	writeChildElement: function(name, object, buffer) {
		var binding = this.getChildBinding("", name);
		binding.write(object, buffer);
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.xml.TextBinding", {

	/**
	 * テキストノードに含まれる文字列を返します。
	 *
	 * @param object オブジェクト
	 * @param text テキストノード
	 */
	read: function(object, text) {
		return text.nodeValue;
	},
	
	/**
	 * オブジェクトをテキストノードの形式で文字列バッファに書き出します。
	 *
	 * @param object オブジェクト
	 * @param buffer 文字列バッファ
	 */
	write: function(object, buffer) {
		buffer.push(object);
	}

});
/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.xml.XMLObjectBinder", {

	initialize: function(config, factory) {
		this.document = new maskat.xml.DocumentBinding(this);
		this.bindings = {
			"": {
				"#document": this.document,
				"#text": new maskat.xml.TextBinding(),
				"#cdata-section": new maskat.xml.CDATASectionBinding()
			}
		};
		this.addBindingConfiguration("", config);
		this.factory = factory;
	},

	addBindingConfiguration: function(uri, config){
		if (!config) {
			return;
		}

		uri = uri || "";
		for (var name in config) {
			if (name == "#document") {
				for (var root in config[name].children) {
					this.setRootElement(uri, root);
				}
			} else {
				this.addElementBinding(uri, name, config[name]);
			}
		}
	},

	setRootElement: function(uri, name) {
		this.document.setRootElement(uri, name);
	},

	getPrefix: function(uri) {
		for (var prefix in this.namespaces) {
			if (this.namespaces[prefix] == uri) {
				return prefix;
			}
		}
		return undefined;
	},

	addPrefixMapping: function(prefix, uri) {
		if (!this.namespaces) {
			this.namespaces = {};
		}
		this.namespaces[prefix] = uri;
	},

	getElementBinding: function(uri, name) {
		if (typeof(uri) == "object") {
			var qname = uri;
			uri = qname.namespaceURI;
			name = qname.localName || qname.baseName || qname.nodeName;
		}

		uri = uri || "";
		if (!this.bindings[uri]) {
			throw new maskat.lang.Error("UNKNOWN_NS_URI", { uri: uri });
		}
		if (!this.bindings[uri][name]) {
			throw new maskat.lang.Error("UNKNOWN_ELEMENT", { elementName: name });
		}
		return this.bindings[uri][name];
	},

	addElementBinding: function(uri, name, config) {
		uri = uri || "";
		var binding = new maskat.xml.ElementBinding(this, uri, name, config);
		if (!this.bindings[uri]) {
			this.bindings[uri] = {};
		}
		this.bindings[uri][name] = binding;
		return binding;
	},

	/**
	 * HTTP GET メソッドで取得した XML 文書の情報を オブジェクトに読み込み、
	 * そのオブジェクトを返します。
	 *
	 * @param url XML 文書の URL
	 *
	 * @return XML 文書の情報を読み込んだオブジェクト
	 */
	load: function(url) {
		try {
			return this.read(maskat.util.CrossBrowser.getXMLDocumentFrom(url));
		} catch (e) {
			throw new maskat.lang.Error("XML_LOAD_ERROR", { url: url }, e);
		}
	},

	/**
	 * XML 文書の情報をオブジェクトに読み込み、そのオブジェクトを返します。
	 *
	 * @param doc XML 文書
	 *
	 * @return XML 文書の情報を読み込んだオブジェクト
	 */
	read: function(doc) {
		return this.document.read(doc);
	},

	createObject: function(element) {
		return this.factory ? this.factory.create(element) : {};
	},

	/**
	 * オブジェクトを XML 文書の形式で文字列に書き出します。
	 *
	 * @param object オブジェクト
	 * @return XML 文書形式の文字列
	 */
	write: function(object) {
		var buffer = [];
		this.document.write(object, buffer);

		/* ルート要素に名前空間宣言を出力する */
		if (this.namespaces && buffer.length > 2) {
			var attributes = [];
			for (var prefix in this.namespaces) {
				attributes.push(" xmlns");
				if (prefix) {
					attributes.push(":");
					attributes.push(prefix);
				}
				attributes.push("=\"");
				attributes.push(this.namespaces[prefix]);
				attributes.push("\"");
			}
			buffer.splice(2, 0, attributes.join(""));
		}

		return buffer.join("");
	}

});
