var webslinger;
(function() {
	(function() {
		var mutators = [];
		jQuery.extend({
			addMutator: function(f) {
				mutators[mutators.length] = f;
			},
			applyMutators: function(ctx, widgetName, href) {
				if (!ctx) ctx = document;
				for (var i in mutators) {
					mutators[i](ctx, widgetName, href);
				}
			}
		});
		jQuery.fn.applyMutators = function(widgetName, href) {
			this.each(function() {
				jQuery.applyMutators(this, widgetName, href);
			});
		};
		jQuery(function() {
			jQuery.applyMutators();
			jQuery.addMutator = function(f) {
				mutators[mutators.length] = f;
				f(document);
			};
		});
	})();

	var url = document.URL.replace(/^([^:\/]+):\/\/([^:\/]+)((:[0-9]+))?/, "");
	var base;
	if (url.charAt(url.length - 1) == "/") {
		base = url;
	} else {
		//alert("stripping");
		var slash = url.lastIndexOf('/');
		base = url.substring(0, slash); 
	}
/*
	Object.prototype.super = function(name) {
		var args = [];
		for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
	};
*/
	webslinger = function(path) {
		if (window == this) return new webslinger(path);
		if (path && path[path.length - 1] != '/') path += '/';
		this._path = path;
	};

	webslinger.makeAbsoluteUrl = function(href, tryBase) {
		href = href.replace(/^([^:\/]+):\/\/([^:\/]+)((:[0-9]+))?/, "");
		if (href.charAt(0) != '/') href = (tryBase || base) + href;
		return href;
	};

	// http://www.howtocreate.co.uk/tutorials/javascript/eventinfo
	webslinger.fixMouseEvent = function(e) {
		if( !e ) {
			if( window.event ) {
				//Internet Explorer
				e = window.event;
			} else {
				//total failure, we have no way of referencing the event
				return;
			}
		}
		if( typeof( e.pageX ) == 'number' ) {
			//most browsers
			var xcoord = e.pageX;
			var ycoord = e.pageY;
		} else if( typeof( e.clientX ) == 'number' ) {
			//Internet Explorer and older browsers
			//other browsers provide this, but follow the pageX/Y branch
			var xcoord = e.clientX;
			var ycoord = e.clientY;
			var badOldBrowser = ( window.navigator.userAgent.indexOf( 'Opera' ) + 1 ) ||
			( window.ScriptEngine && ScriptEngine().indexOf( 'InScript' ) + 1 ) ||
			( navigator.vendor == 'KDE' );
			if( !badOldBrowser ) {
				if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
					//IE 4, 5 & 6 (in non-standards compliant mode)
					xcoord += document.body.scrollLeft;
					ycoord += document.body.scrollTop;
				} else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
					//IE 6 (in standards compliant mode)
					xcoord += document.documentElement.scrollLeft;
					ycoord += document.documentElement.scrollTop;
				}
			}
		} else {
			//total failure, we have no way of obtaining the mouse coordinates
			return;
		}
		return [xcoord, ycoord];
	};

	function indentingString(doSpace, doNewline) {
		var parts = []
		if (doSpace == null) doSpace = true;
		if (doNewline == null) doNewline = true;
		var lastWasNewline = false;
		var indent = '';
	
		this.newline = function() {
			lastWasNewline = true;
			if (doNewline) parts.push('\n');
			return this;
		};

		checkAfterNewline = function() {
			if (!lastWasNewline) return;
			if (doSpace) {
				parts.push(doNewline ? indent : ' ');
			}
			lastWasNewline = false;
		};

		this.push = function() {
			indent += ' ';
			return this;
		};

		this.pop = function() {
			indent = indent.substring(0, indent.length - 1);
			return this;
		};

		this.space = function() {
			checkAfterNewline();
			if (doSpace) parts.push(' ');
			return this;
		};

		this.write = function(s) {
			var i;
			var offset;
			checkAfterNewline();
			for (i = 0, offset = 0; i < s.length; i++) {
				var c = s.charAt(i);
				parts.push(c);
				if (s.charCodeAt(i) == '\n') {
					checkAfterNewline();
					lastWasNewline = true;
				}
			}
			return this;
		};

		this.toString = function() {
			return parts.join('');
		};
	};


	var writeString = function(o, s) {
		s.write('"');
		for (var i = 0; i < o.length; i++) {
			var c = o.substring(i, i + 1);
			switch (c) {
				case "\\": s.write("\\\\"); continue;
				case "/": s.write("\\/"); continue;
				case "\"": s.write("\\\""); continue;
				case "\b": s.write("\\b"); continue;
				case "\f": s.write("\\f"); continue;
				case "\n": s.write("\\n"); continue;
				case "\r": s.write("\\r"); continue;
				case "\t": s.write("\\t"); continue;
			}
			var code = o.charCodeAt(i);
			if (32 <= code && code >= 256) {
				s.write("\\u");
				var n = Integer.toString(code, 16);
				for (var j = 4 - n.length; j > 0; j--) s.write("0");
				s.write(n);
			} else {
				s.write(c);
			}
  		}
		s.write('"');
	};

	var writeArray = function(o, s) {
		s.write('[').push();
		if (o.length) s.newline();
		for (var i = 0; i < o.length; i++) {
			writeObject(o[i], s);
			if (i != o.length - 1) s.write(',');
			s.newline();
		}
		s.pop().write(']');
	};

	var writeMap = function(o, s) {
		s.write('{').push();
		var i = 0;
		for (var n in o) {
			if (i == 0) {
				s.newline();
			} else {
				s.write(',').newline();
			}
			writeObject(n, s);
			s.write(':').space();
			writeObject(o[n], s);
			i++;
		}
		if (i != 0) s.write(',').newline();
		s.pop().write('}');
	};

	var writeObject = function(o, s) {
		if (o == null) {
			s.write("null");
		} else if (typeof o == 'string') {
			writeString(o, s);
		} else if (o.constructor == Array) {
			writeArray(o, s);
		} else if (typeof o == 'object') {
			writeMap(o, s);
		} else {
			s.write("" + o);
		}
	};

	webslinger.toJSON = function(o) {
		var s = new indentingString();
		writeObject(o, s);
		return s.toString();
	};

	webslinger.event = function(path, payload, context, callback) {
		var args = [];
		for (var i = 0; i < arguments.length; i++) args.push(arguments[i]);
		path = args.shift();
		callback = args.pop();
		if (args.length == 2) {
			if (args[0] instanceof String) {
				payload = args.shift();
				context = args.shift();
			} else if (args[0] instanceof Object) {
				context = args.shift();
				payload = args.shift();
			} else {
				payload = null;
				context = null;
			}
		} else if (args.length == 1) {
			if (args[0] instanceof String) {
				payload = args.shift();
				context = null;
			} else if (args[0] instanceof Object) {
				context = args.shift();
				payload = null;
			} else {
				payload = null;
				context = null;
			}
		} else {
			payload = null;
			context = null;
		}
		path = webslinger.makeAbsoluteUrl(path, this._path);
		if (!context) context = {};
		var data = {
			payload: payload,
			context: context
		};
		var encodedData = webslinger.toJSON(data);
		jQuery.ajax({
			async:		true,
			contentType:	"text/x-json",
			data:		encodedData,
			dataType:	"json",
			error:		function(req, type, exc) {
				alert("error(" + path + ")[" + type + "][" + exc + "]");
				callback(null, {type: "request", ajax: {req: req, type: type, exc: exc}});
				throw exc;
			},
			processData:	false,
			success:	function(data) {
				//alert("event data=" + webslinger.toJSON(data));
				if (data.hub) {
					for (var i = 0; i < data.hub.length; i++) {
						var item = data.hub[i];
						OpenAjax.hub.publish(item.topic, item.data);
					}
				}
				if (data.result) {
					try {
						callback(data.result);
					} catch (e) {
						alert("client error(" + e + ")");
						callback(null, {type: "client", exc: e});
					}
				} else {
					alert("server error");
					callback(null, {type: "server", error: data.error});
				}
			},
			type:		"post",
			url:		path
		});
		return this;
	};

	webslinger.prototype.event = webslinger.event;

	(function() {
		function sendWidgetMessage(jThis, msg, widgetName, context) {
			if (!(widgetName instanceof String) && !context) {
				context = widgetName;
				widgetName = null;
			}
			return jThis.each(function() {
				var possibleName = widgetName;
				if (!possibleName) possibleName = this.getAttribute("wsWidgetName");
				if (!possibleName) return;
				OpenAjax.hub.publish("widget." + possibleName + "." + msg, context);
			});
		}
		jQuery.fn.WidgetClear = function(widgetName) { return sendWidgetMessage(this, "clear", widgetName); };
		jQuery.fn.WidgetFill = function(widgetName) { return sendWidgetMessage(this, "fill", widgetName); };
		jQuery.fn.WidgetRefresh = function(widgetName, context) { return sendWidgetMessage(this, "refresh", widgetName, context); };
		jQuery.fn.WidgetSetName = function(widgetName) {
			return this.attr("wsWidgetName", widgetName);
		};
		jQuery.fn.WidgetSendResizeEvent = function() {
			this.each(function() {
				var ptr = this.parentNode;
				var widget;
				while (ptr != null) {
					if (!ptr.getAttribute) break;
					var name = ptr.getAttribute("wsWidgetName");
					if (name != null) {
						OpenAjax.hub.publish("widget." + name + ".resize");
						break;
					}
					ptr = ptr.parentNode;
				}
			});
		}
	})();

	jQuery.fn.CommunicationPane = function() {
		return this.each(function() {
			var jThis = jQuery(this);
			var widgetName = jThis.attr("wsWidgetName");
			var urlBase = jThis.attr("communicationsBase");
			var listUrl = jThis.attr("communicationsList");
			var messageUrl = jThis.attr("communicationsMessage");
			var editUrl = jThis.attr("communicationsEdit");
			var messagePane = jThis.find(".Communications-Message").WidgetSetName(widgetName + ":Message");
			var listContainer = jThis.find(".Communications-List").WidgetSetName(widgetName + ":List");
			var processor = new webslinger(urlBase);
			var messagePaneHide = function(callback) {
				callback();
			};
			OpenAjax.hub.subscribe(
				"widget." + widgetName + ":List.refresh",
				function(name, context) {
					processor.event(
						listUrl,
						context,
						function(result) {
							listContainer.WidgetClear().empty().append(result).WidgetFill();
						}
					);
				}
			);
			OpenAjax.hub.subscribe("widget." + widgetName + ":List.clear", function() {
				if (messageUrl && messagePane.length) {
					messagePaneHide(function() {
						messagePane.WidgetClear().empty();
					});
				}
			});
			OpenAjax.hub.subscribe("widget." + widgetName + ":List.fill", function() {
				listContainer.find("[@listSort]").css("cursor", "pointer").click(function() {
					listContainer.WidgetRefresh({sort: this.getAttribute("listSort"), sortOrder: this.getAttribute("listSortOrder")});
				});
				var lastCommChosen;
				var listRows = listContainer.find("[@listCommId][@listCommType]");
				if (messageUrl && messagePane.length) {
					listRows.css("cursor", "pointer").click(function() {
						if (lastCommChosen) lastCommChosen.removeClass("CommListMessageSelected");
						lastCommChosen = jQuery("[@listCommId='" + this.getAttribute("listCommId") + "']", this.parentNode).addClass("CommListMessageSelected");
						var commId = this.getAttribute("listCommId");
						var messageResult;
						//alert("row clicked: " + alertId);
						var latch = webslinger.Latch(
							2,
							function() {
								//alert("trigger called: loadResult=" + loadResult);
								messagePane.empty();
								messagePane.append(messageResult);
								/*
								messagePane.find("*[@lprCommId][@lprActionType]").click(function() {
									var commId = this.getAttribute("lprCommId");
									var type = this.getAttribute("lprActionType");

								});
								*/
								messagePane.show(500);
								messagePane.WidgetFill();
								messagePaneHide = function(callback) {
									if (messagePane.is(":visible")) {
										messagePane.hide(500, callback);
									} else {
										callback();
									}
								};
							}
						);
						messagePaneHide(latch);
						processor.event(
							messageUrl,
							{
								commId: commId
							},
							function(result) {
								messageResult = result;
								latch();
							}
						);
					});
					messagePane.empty();
				}
				if (editUrl) {
					listRows.css("cursor", "pointer").dblclick(function() {
						if (lastCommChosen) lastCommChosen.removeClass("CommListMessageSelected");
						lastCommChosen = jQuery("[@listCommId='" + this.getAttribute("listCommId") + "']", this.parentNode).addClass("CommListMessageSelected");
						var commId = this.getAttribute("listCommId");
						jQuery(this).openDialog(urlBase + "/" + editUrl + "/" + commId, "EditShowing", "Edit"); 
					});
				}
			});
			listContainer.WidgetFill();
			jThis.WidgetFill();
		});
	};

	webslinger.remotePane = function(id, path) {
		OpenAjax.hub.subscribe(
			"widget." + id + ".refresh",
			function(name, context) {
				webslinger.event(
					path,
					context,
					function(result) {
						var container = jQuery("#" + id);
						OpenAjax.hub.publish("widget." + id + ".clear", container);
						container.empty().append(result);
						OpenAjax.hub.publish("widget." + id + ".fill", container);
					}
				);
			}
		);
		jQuery(
			function() {
				OpenAjax.hub.publish("widget." + id + ".fill", jQuery("#" + id));
			}
		);
	};

	webslinger.Latch = function(count, trigger) {
		return function() {
			count--;
			if (count == 0) trigger();
		};
	};

	OpenAjax.hub.subscribe(
		"mailto",
		function(name, data) {
			alert("mailto[" + webslinger.toJSON(data) + "]");
		}
	);
})();

