/*
 * 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;
		}
	}

});
