/**
 * Panel Implement
 *
 */

uutuu.Require("uutuu.util");
uutuu.Require("uutuu.Resource");

uutuu.Namespace("uutuu.UI");

uutuu.UI.Export("Panel", "Dock");

/**
 * Generic ui panel implements.
 *
 * This panel implements support dock and automatic resize.
 *
 * Supportted options including:
 * element: HTML element represents the panel, create a new element
 *			if not specified;
 * cssClass:Class attribute of element.
 * innerElement:
 			HTML element represents the panel viewport, reuse element if not specified;
 * innerClass:
 			Class attribute of innerElement, new viewport element will be created
 			if innerClass specified and not equals to cssClass;
 * parent:	Parent "Panel" object;
 * dock:	Dock settings, default to be dock to top, with lock none;
 */
uutuu.UI.Panel = uutuu.Class({
name: "uutuu.UI.Panel",
construct:
	function(name, options) {
		if (!name)
			return;

		this.client;	// Outline element that decides the size of panel.
		this.viewport;	// Inner element in which layout displays.
		this.layout;	// Acture element that contains contents.
		this.dock;		// Dock setting the panel applies.
		this.parent;	// Parent panel
		this.scrollers = {length:0};

		this.getName = function() { return name; };

		this.initialize(options);
		if (this.parent)
			this.parent.addPanel(this);
	},
methods: {
	initialize: function(options) {
		if (!options)
			options = {};

		this.parent = options.parent ? options.parent : null;

		// client settings
		if (!options.element)
		{
			options.element = document.createElement("div");
			if (!this.parent)
				$(options.element).appendTo(document.body);
		}
		this.client = options.element;
		var jClient = $(this.client);
		if (options.cssClass)
			jClient.attr("class", options.cssClass);
		jClient.css("position", "absolute");

		// dock settings
		this.dock = options.dock ? options.dock : new uutuu.UI.Dock();
		this.dock.width = this.getWidth();
		if (!this.dock.width)
			this.dock.width = this.client.offsetWidth;
		this.dock.height = this.getHeight();
		if (!this.dock.height)
			this.dock.height = this.client.offsetHeight;

		// layout settings
		if (options.innerElement)
		{
			this.viewport = this.layout = options.innerElement;
			if (options.innerClass)
				this.layout.className = options.innerClass;
			if (!this.layout.parentNode || this.layout.parentNode != this.client)
				$(this.layout).appendTo(this.client);
			$(this.layout).css("position", "absolute");
		}
		else if (options.innerClass && options.innerClass != jClient.attr("class"))
		{
			// create a layout element;
			this.viewport = this.layout = document.createElement("div");
			$(this.layout).css("position", "absolute").appendTo(this.client);
		}
		else
			this.viewport = this.layout = this.client;

		var obj = this;
		this.onResize(function(event){
			obj.resizeHandler(event);
		});
		this.onViewportResize(function(event){
			obj.innerResizeHandler(event);
		});
		this.onLayoutResize(function(event){
			obj.innerResizeHandler(event);
		});
	},
	setHeight: function(height) {
		uutuu.util.height(this.client, height);
	},
	setWidth: function(width) {
		uutuu.util.width(this.client, width);
	},
	getHeight: function() {
		return uutuu.util.height(this.client);
	},
	getWidth: function() {
		return uutuu.util.width(this.client);
	},
	getScrollWidth: function() {
		if (this.layout === this.viewport)
			return 0;
		return uutuu.util.width(this.layout) - this.viewport.clientWidth;
	},
	getScrollHeight: function() {
		if (this.layout === this.viewport)
			return 0;
		return uutuu.util.height(this.layout) - this.viewport.clientHeight;
	},
	addScroller: function(type, vertical, options) {
		if (!type)
			return null;
		// ensure viewport and layout separated;
		this._generateViewport();

		this.scrollers[this.scrollers.length++] = new type(this, vertical, options);
		return this.scrollers[this.scrollers.length - 1];
	},
	scrollTo: function(pos, vertical) {
		var max = vertical ? this.getScrollHeight() : this.getScrollWidth();

		pos = pos > max ? max : pos;
		pos = pos < 0 ? 0 : pos;		// place here to avoid max itself < 0;
		$(this.layout).css("position", "absolute")
			.css(vertical ? "top" : "left", -pos)
			.trigger("scroll", [pos, vertical]);
	},
	addPanel: function(child) {},
	// events
	onScroll: function(func) {
		$(this.layout).bind("scroll",func);
		if (!this.eventHandlers)
			this.eventHandlers = new Array();
		this.eventHandlers.push(["layout", ["scroll", func]]);
	},
	onResize: function(func) {
		$(this.client).bind("panelResize", func);
		if (!this.eventHandlers)
			this.eventHandlers = new Array();
		this.eventHandlers.push(["client", ["panelResize", func]]);
	},
	// privates
	onViewportResize: function(func) {
		$(this.viewport).bind("panelResize", func);
		if (!this.eventHandlers)
			this.eventHandlers = new Array();
		this.eventHandlers.push(["viewport", ["panelResize", func]]);
	},
	onLayoutResize: function(func) {
		$(this.layout).bind("panelResize", func);
		if (!this.eventHandlers)
			this.eventHandlers = new Array();
		this.eventHandlers.push(["layout", ["panelResize", func]]);
	},
	resizeHandler: function(event) {
		if (this.viewport !== this.client) {
			uutuu.util.width(this.viewport, this.client.clientWidth);
			uutuu.util.height(this.viewport, this.client.clientHeight);
			$(this.viewport).trigger("panelResize");
		}
	},
	innerResizeHandler: function(event) {
		if (this.layout !== this.viewport) {
			// reset layout
			$(this.layout).css("width", "auto").css("height", "auto");
			// set layout to fit viewport
			if (uutuu.util.width(this.layout) < this.viewport.clientWidth)
				uutuu.util.width(this.layout, this.viewport.offsetWidth);
			if (uutuu.util.height(this.layout) < this.viewport.clientHeight)
				uutuu.util.height(this.layout, this.viewport.offsetHeight);
			for (var i = 0; i < this.scrollers.length; i++)
				this.scrollers[i].layoutResizeHandler();
		}
	},
	// privates
	_generateViewport: function() {
		if (this.layout !== this.viewport)
			return;

		// generate layout block
		this.viewport = document.createElement("div");
		// move event handler
		if (this.eventHandlers) {
			for (var i = 0; i < this.eventHandlers.length; i++) {
				if (this.eventHandlers[i][0] == "viewport" ) {
					jQuery.prototype.unbind.apply($(this.layout), this.eventHandlers[i][1]);
					jQuery.prototype.bind.apply($(this.viewport), this.eventHandlers[i][1]);
				}
			}
		}
		$(this.viewport).css("position", "absolute").css("overflow", "hidden")
			.width(uutuu.util.width(this.layout))
			.height(uutuu.util.height(this.layout));
		$(this.layout).appendTo(this.viewport);
		$(this.viewport).appendTo(this.client);
	}
},
statics: {
	// window size monitor
	windowSizeMonitor: {timeoutId:0, lastWidth:0, lastHeight:0},
	enableWindowSizeMonitor: function() {
		if (this.windowSizeMonitor.timeoutId == 0) {
			this.windowSizeMonitor.timeoutId = -1;
			this.windowSizeChangedHandler();
		}
	},
	disableWindowSizeMonitor: function() {
		if (this.windowSizeMonitor.timeoutId > 0) {
			window.clearTimeout(this.windowSizeMonitor.timeoutId);
		}
		this.windowSizeMonitor.timeoutId = 0;
	},
	windowSizeChangedHandler: function() {
		if (this.windowSizeMonitor.timeoutId == 0)
			return;

		var util = uutuu.util;
		if (util.getInnerWidth() != this.windowSizeMonitor.lastWidth ||
			util.getInnerHeight() != this.windowSizeMonitor.lastHeight)
		{
			this.windowSizeMonitor.lastWidth = util.getInnerWidth();
			this.windowSizeMonitor.lastHeight = util.getInnerHeight();
			$(document.body).trigger("windowResize", [{
				width:this.windowSizeMonitor.lastWidth,
				height:this.windowSizeMonitor.lastHeight}]);
		}
		this.windowSizeMonitor.timeoutId =
				window.setTimeout(function() {
					uutuu.UI.Panel.windowSizeChangedHandler();
				}, 500);
	},
	// dragMonitor;
	dragMonitor: {
		debugLog:false,
		mousedown:false,
		dragging:false,
		dragClass:"",
		x:0, y:0
	},
	initializeDragMonitor: function(debug) {
		var obj = this;
		if (debug)
		{
			this.dragMonitor.debugLog = $(document.createElement("div"));
			this.dragMonitor.debugLog.css("position", "absolute")
				.css("background-color", "white")
				.css("border", "1px black solid")
				.css("top", 0).css("left", 0)
				.width(500).height(20).appendTo(document.body);
		}

		$(document.body).mousedown(function(event) {
			obj.mousedownHandler(event);
		}).mousemove(function(event) {
			obj.mousemoveHandler(event);
		}).mouseup(function(event) {
			obj.mouseupHandler(event);
		})
	},
	debugLog: function() {
		if (!this.dragMonitor.debugLog)
			return;
		var html = "";
		for (key in this.dragMonitor)
			if (key != "debugLog")
				html += " " + key + ":" + this.dragMonitor[key];
		this.dragMonitor.debugLog.html(html);
	},
	mousedownHandler: function(event) {
		this.dragMonitor.mousedown = true;
		this.dragMonitor.x = event.clientX;
		this.dragMonitor.y = event.clientY;
		this.debugLog();
	},
	mousemoveHandler: function(event, x, y) {
		this.dragMonitor.dragging = this.dragMonitor.mousedown;
		this.dragMonitor.x = x ? x : event.clientX;
		this.dragMonitor.y = y ? y : event.clientY;
		this.debugLog();
	},
	mouseupHandler: function(event) {
		this.dragMonitor.dragging = this.dragMonitor.mousedown = false;
		this.dragMonitor.x = event.clientX;
		this.dragMonitor.y = event.clientY;
		this.debugLog();
	},
	// message box
	messageBox: {
		TYPE_OKCANCEL: "MESSAGEBOX_TYPE_OKCANCEL",
		TYPE_YESNO: "MESSAGEBOX_TYPE_YESNO",
		TYPE_YESNOCANCEL: "MESSAGEBOX_TYPE_YESNOCANCEL",
		DEFAULT_TIMEOUT: 60000,
		sequence:0,
		timeoutId:0,
		element:null,
		message:null,
		buttonOk:null,
		buttonDeny:null,
		buttonCancel:null,
		initialize: function(elem) {
			if (this.element)
				return;

			var jElement;
			if (elem) {
				jElement = $(elem);
			} else {
				jElement = $(document.createElement("div"));
				jElement.html("<div id=\"mb_message\"></div>" +
					"<div style=\"text-align:center;padding:5px 0px;\">" +
					"<input id=\"mb_ok\" type=\"button\" value=\"\"/>" +
					"<input id=\"mb_deny\" type=\"button\" value=\"\"/>" +
					"<input id=\"mb_cancel\" type=\"button\" value=\"\"/>" +
					"</div>")
			}
			jElement.attr("id", "mb_box").css("visibility","hidden");

			this.element = jElement[0];
			this.message = $("#mb_message", jElement)[0];
			this.buttonOk = $("#mb_ok", jElement)[0];
			this.buttonDeny = $("#mb_deny", jElement)[0];
			this.buttonCancel = $("#mb_cancel", jElement)[0];

			var obj = this;
			jQuery.each(["ok", "deny", "cancel"], function(i, val){
				$("#mb_" + val).click(function(event) {
					sequence = obj.sequence;
					$(this).trigger(val);
					// use sequence to ensure closing the messageBox opened by this procedure.
					if (sequence == obj.sequence)
						obj.close();
				});
			});
		},
		resetTimeout: function(timeout, timeoutCallback) {
			if (!this.timeoutId) {
				return;
			}

			// clear old timeout
			window.clearTimeout(this.timeoutId);
			this.timeoutId = 0;

			// reset timeout
			if (!timeout) {
				timeout = this.DEFAULT_TIMEOUT;
			}
			else if (timeout.constructor == Function) {
				timeoutCallback = timeout;
				timeout = this.DEFAULT_TIMEOUT;
			}

			// set callback
			if (!timeoutCallback)
				timeoutCallback = function() {
					uutuu.UI.Panel.alert(uutuu.UI.Panel.prototype.resource.entry(uutuu.UI.Panel.prototype.classname, "INFO_MESSAGEBOX_TIMEOUT")); };

			// set timeout
			if (timeout != -1)
				this.timeoutId = window.setTimeout(timeoutCallback, timeout);
		},
		show: function(msg) {
			if (this.lastMsg)
			{
				$(this.lastMsg).append($(this.message).children());
				this.lastMsg = undefined;
			}
			else {
				$(this.message).html("");
			}

			if (msg && msg instanceof Object)
			{
				$(this.message).append($(msg).children());
				this.lastMsg = msg;
			}
			else
			{
				if (!msg || msg == "")
					msg = " ";
				$(this.message).html(msg);
			}

			$(this.message).css("position", "absolute");
			var width = Math.max(uutuu.util.width(this.message), 200);
			$(this.message).css("position", "static");
			var height = uutuu.util.height(this.message) +
				uutuu.util.height(this.buttonOk.parentNode) + 8;

			// launch
			var elem = tb_show(null, "#TB_inline?height=" + height + "&width=" +
				width + "&inlineId=mb_box&modal=true", false);
			return elem;
		},
		close: function() {
			// reset timeout;
			if (this.timeoutId) {
				window.clearTimeout(this.timeoutId);
				this.timeoutId = 0;
			}
			if (this.lastMsg)
			{
				$(this.lastMsg).append($(this.message).children());
				this.lastMsg = undefined;
			}
			else {
				$(this.message).html("");
			}
			tb_remove();
		}
	},
	message: function(msg, timeout, timeoutCallback) {
		this.messageBox.initialize();
		// reset timeout;
		if (this.messageBox.timeoutId) {
			window.clearTimeout(this.messageBox.timeoutId);
			this.messageBox.timeoutId = 0;
		}

		// set ui status;
		$(this.messageBox.buttonOk).css("display", "none");
		$(this.messageBox.buttonDeny).css("display", "none");
		$(this.messageBox.buttonCancel).css("display", "none");

		// set timeout
		if (!timeout) {
			timeout = this.messageBox.DEFAULT_TIMEOUT;
		}
		else if (timeout.constructor == Function) {
			timeoutCallback = timeout;
			timeout = this.messageBox.DEFAULT_TIMEOUT;
		}

		// set callback
		if (!timeoutCallback)
			timeoutCallback = function() {
				uutuu.UI.Panel.alert(uutuu.UI.Panel.prototype.resource.entry(uutuu.UI.Panel.prototype.classname, "INFO_MESSAGEBOX_TIMEOUT")); };

		// set timeout
		if (timeout != -1)
			this.messageBox.timeoutId = window.setTimeout(timeoutCallback, timeout);

		var sequence = ++this.messageBox.sequence;
		this.messageBox.show(msg);
	},
	alert: function(msg, okCallback) {
		this.messageBox.initialize();
		// reset timeout;
		if (this.messageBox.timeoutId) {
			window.clearTimeout(this.messageBox.timeoutId);
			this.messageBox.timeoutId = 0;
		}

		// set ui status
		$(this.messageBox.buttonOk).css("display", "inline").unbind("ok")
			.val(this.prototype.resource.entry(this.prototype.classname, "MESSAGEBOX_LABEL_OK"));
		$(this.messageBox.buttonDeny).css("display", "none");
		$(this.messageBox.buttonCancel).css("display", "none");
		if (okCallback)
			$(this.messageBox.buttonOk).bind("ok", okCallback);

		var sequence = ++this.messageBox.sequence;
		var handle = this.messageBox.show(msg);

//		// register event to generated message box
//		var obj = this;
//		$("#mb_ok", handle).unbind("click").click(function() {
//			$(obj.messageBox.buttonOk).trigger("ok");
//			// use sequence to ensure closing the messageBox opened by this procedure.
//			if (sequence == obj.messageBox.sequence)
//				obj.messageBox.close();
//		});
		return handle;
	},
	confirm: function(msg, type, callbacks) {
		this.messageBox.initialize();
		// reset timeout;
		if (this.messageBox.timeoutId) {
			window.clearTimeout(this.messageBox.timeoutId);
			this.messageBox.timeoutId = 0;
		}

		// callback start index
		var diagtype = type;
		var cbstart = 2;
		if (!type || type.constructor == Function) {
			diagtype = this.messageBox.TYPE_OKCANCEL;
			cbstart = 1;
		}
		var labels = this.prototype.resource.entry(this.prototype.classname, diagtype);
		// no resource available? use diagtype as labels.
		if (!labels || labels.length == 0)
			labels = diagtype;
		labels = labels.split(",");

		var buttons = [this.messageBox.buttonOk,
			this.messageBox.buttonDeny,
			this.messageBox.buttonCancel];
		var events = ["ok", "deny", "cancel"];

		// set ui status
		for (var i = 0; i < buttons.length; i++) {
			if (labels[i] == "") {
				$(buttons[i]).css("display", "none");
				continue;
			}

			$(buttons[i]).css("display", "inline")
				.unbind(events[i]).val(labels[i]);
			if (arguments[cbstart])
				$(buttons[i]).bind(events[i], arguments[cbstart]);
			cbstart++;
		}

		var sequence = ++this.messageBox.sequence;
		var handle = this.messageBox.show(msg);

//		// register event to generated message box
//		var obj = this;
//		for (var i = 0; i < buttons.length; i++) {
//			if (labels[i] == "")
//				continue;

//			$("#mb_" + events[i], handle).unbind("click").bind("click",
//				{button:buttons[i], event:events[i]}, function(event) {
//				$(event.data.button).trigger(event.data.event);
//				// use sequence to ensure closing the messageBox opened by this procedure.
//				if (sequence == obj.messageBox.sequence)
//					obj.messageBox.close();
//			});
//		}
		return handle;
	}
}
});

uutuu.UI.Dock = function(side, lock, offsetX, offsetY)
{
	// Side to Dock
	this.side = side ? side : uutuu.UI.Dock.DOCK_TOP;
	// Indicate which dimension to be holding on parent resizing.
	this.lock = lock ? lock : uutuu.UI.Dock.LOCK_NONE;
	// Offset on x axis, the base value of positive offset is X of parent's
	// topleft corner, while negative offset is X of parents's topright corner.
	this.offsetX = offsetX ? offsetX : 0;
	// Offset on y axis, the base value of positive offset is Y of parent's
	// topleft corner, while negative offset is Y of parents's leftbottom corner.
	this.offsetY = offsetY ? offsetY : 0;
	// predefined dock width;
	this.width = -1;
	// predefined dock height;
	this.height = -1;
}
uutuu.UI.Dock.LOCK_NONE = 0;
uutuu.UI.Dock.LOCK_WIDTH = 1;
uutuu.UI.Dock.LOCK_HEIGHT = 2;
uutuu.UI.Dock.LOCK_BOTH = 3;
uutuu.UI.Dock.DOCK_TOP = 0;
uutuu.UI.Dock.DOCK_BOTTOM = 1;
uutuu.UI.Dock.DOCK_LEFT = 2;
uutuu.UI.Dock.DOCK_RIGHT = 3;
