/**
 * @author CHX
 */
jatX.util.Parser = jatX.Class({
	version: "0.1",
	__init: function(opt) {
		this.style = {
			cmd_box: "jx_debug_cmd_box",

			lang_type: "jx_debug_lang_type",
			lang_null: "jx_debug_lang_null",
			lang_nan: "jx_debug_lang_nan",
			lang_finite: "jx_debug_lang_finite",
			lang_array: "jx_debug_lang_array",
			lang_function: "jx_debug_lang_function",
			lang_number: "jx_debug_lang_number",
			lang_object: "jx_debug_lang_object",
			lang_boolean: "jx_debug_lang_boolean",
			lang_string: "jx_debug_lang_string",
			lang_undefined: "jx_debug_lang_undefined",
			lang_html: "jx_debug_lang_html",
			lang_err_message: "jx_debug_lang_err_message",
			lang_err_line: "jx_debug_lang_err_line",
			lang_err_file: "jx_debug_lang_err_file",
			lang_err_name: "jx_debug_lang_err_name"
		};
		this.cmd_history = [];
		this.currentCmdIndex = 0;

		var owner = this;
		
		this._debugObj = {
			$: jatX.$,
			log: function(s) {
				owner.log(s);
			},
			list: function(o) {
				owner.list(o);
			},
			clear: function() {
				owner.clear();
			},
			version: owner.version
		};

		this._parseDepth = 0;
		this._parseMaxDepth = 2;
		this.$box = jatX.$E("<div>");
		this.$logArea = jatX.$E("<ol>");

		this.$cmd_box = jatX.$E("<input-text>");


		this.window = new jatX.UI.Window({
			subject: "Javascript Console",
			body: this.$box
		});
		this.$logArea.appendTo(this.$box);
		this.window.setSize(550, 140);
		this.$cmd_box.appendTo(jatX.$E("<div>").appendTo(this.window.body.parent()).className(this.style.cmd_box));
		
		this._bindEvents();
	},

	_bindEvents: function() {
		this.$cmd_box.addEvent("keydown", this._run, this);
		this.$cmd_box.addEvent("keydown", this.viewHistory, this);
	},

	_run: function(e, c) {
		if (e.key.enter) {
			e.stop();
			c = c || this.$cmd_box._element.value;
			
			if (c != this.cmd_history[this.cmd_history.length - 1]) {
				this.cmd_history.push(c);
				this.currentCmdIndex = this.cmd_history.length;
			}
			this.$cmd_box._element.value = "";
			this._logCmd(c);

			try {
				var f = function() {
					var e, f;
					return eval(c);
				};
				var res = f.call(this._debugObj);

				if (typeof res != "undefined") {
					this.log(res);
				}
//				f.call(this);
			} catch(e) {
//				this.log(e)
				this._logErr(e);
			}
		}
	},
	_logErr: function(oErr) {
		var name = oErr.name||"";
		var message = oErr.message||oErr.description||"";
		var lineNumber = oErr.lineNumber||0;
		var fileName = oErr.fileName||"";

		this._log(
			this._decoratVar("err_name", name+":")+
			this._decoratVar("err_message", message)+
			this._decoratVar("err_line", lineNumber)+
			this._decoratVar("err_file", fileName),
			
			"err"
		);
		this._parseDepth = 0;
	},
	_logCmd: function(s) {
		this._log(">>> "+s, "cmd");
		this._parseDepth = 0;
	},
	_log: function(s, type) {
		var el = jatX.$E("<li>");
		this.$logArea.appendChild(el.html(s));
		if(type&&typeof type == "string") {
			el.className(type);
		}
		el.scrollIntoView();
	},
	_HtmlEncode: function(s) {
		return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\r?\n/g, "<br />");
	},
	_decoratVar: function(varType, sLiteral) {
		return "<span class=\"" + this.style["lang_" + varType] + "\">" + sLiteral + "</span>";
	},
	parse: function(v, b, l) {
		var _literal = "";
		var _varName = "";
		l = l || 0;
//		if(v === this.window.box) return;
		var _varType = typeof v;
		switch (_varType) {
			case "object":
				this._parseDepth++;
				if (v === null) {
					_literal = "null";
					_varName = "null";
				} else if (v instanceof Array) {
					var _a = [];
					if (this._parseDepth < this._parseMaxDepth) {
						f:for (var i = 0; i < v.length; i++) {
							if (l > i) {
								_a.push(this.parse(v[i], true, l));
								
							} else {
								_a.push("...");
								break f;
							}
						}
						this._parseDepth--;
						
					} else {
						_a.push("...");
					}
					_literal = "[" + _a.join(", ") + "]" + (!b ? " length=" + v.length : "");
				} else if (jatX.Element.prototype.valid(v)) {
					_literal = "HTMLElement[" + v.tagName + "]";
					_varName = "html";
				} else {
					var _ao = [];
					var _i = 0;
					if (this._parseDepth < this._parseMaxDepth) {
						for (var p in v) {
							if (l > _i++) {
								_ao.push(p + ": " + this.parse(v[p], true, l));
							}
							if (_i == l) {
								_ao.push("...");
								break;
							}
						}
						this._parseDepth--;
					} else {
						_ao.push("...");
					}
					_literal = "{" + _ao.join(", ") + "}";
				}
				_varName = v ? v instanceof Array ? "array" : "object" : "null";
				break;
			case "number":
				_literal = v.toString();
				//				console.log(isFinite(v))
				_varName = isNaN(v) ? "nan" : !isFinite(v) ? "finite" : "number";
				break;
			case "function":
				_literal = "function";
				_varName = "function";
				break;
			case "string":
				_literal = this._HtmlEncode(v.toString());
				_varName = "string";
				break;
			case "boolean":
				_literal = v?"true":"false";
				_varName = "boolean";
				break;
			default:
				_literal = "undefined";
				_varName = "undefined";
		}
		return this._decoratVar(_varName, _literal) + (b ? "" : " " + this._decoratVar("type", Object.prototype.toString.apply(v)));
	},
	list: function(o) {
		for(var p in o) {
			this._log(p+": "+this.parse(o[p], false, 1));
			this._parseDepth = 0;
		}
	},
	viewHistory: function(e) {
		if(e.key.up&&this.currentCmdIndex>0) {
			this.$cmd_box._element.value = this.cmd_history[-- this.currentCmdIndex];
		}
		if(e.key.down&&this.currentCmdIndex<this.cmd_history.length-1) {
			this.$cmd_box._element.value = this.cmd_history[++ this.currentCmdIndex];
		}
	},
	clear: function() {
		this.$logArea.html("");
	},
	log: function() {
		var v = [];
		if(this._parseDepth > 0) return;

		for (var i = 0; i < arguments.length; i++) {
			v.push(this.parse(arguments[i], false, 5));
			this._parseDepth = 0;
		}
		this._log(v.join(", "));
	}
});

