/**
 * es_net package
 * This package is mainly forfor opening a standard (w3c) http request. This
 * method may not always work, depending on the pecularities of any given HTTP
 * request implementation.
 */
es_net = new es_lang.Package(true,
	"generic network functions",
	"-- none --",
	function() {
		// Imports
		// -------
		var LANG = es_lang;
		var Class = LANG.Class;
		var Enum = LANG.Enum;
		var extend = Class.extend;
		var implement = Class.implement;

		var StringBuilder = LANG.StringBuilder;

		var URLContainer = function() {
			var _callback;
			var _iframe;
			var _timeoutId = -1;
			var _checkCount = 0;
			var _locked = false
			var _waiting = false;
			var _logger = es_util_logging.Logger.getLogger('es.net.URLContainer');
			
			var isLocked = function() {
				return _locked;
			};
			var isWaiting = function() {
				return _waiting;
			};
			var lock = function() {
				_callback = null;
				_locked = true;
			};
			var notify = function(frme) {
				var doc;
				var win;

				if (_waiting) {
					window.clearTimeout(_timeoutId);
					_waiting = false;
					_locked = false;
					try {
						if (frme.contentDocument) {
							win = frme;
							doc = frme.contentDocument;
						} else {
							win = frme.contentWindow;
							doc = win.document;
						}
						if (_callback) _callback(doc, win);
					} catch (e) {
						_logger.warning(e.message);
					}
				}
			};
			var unlock = function() {
				_locked = false;
				_callback = null;
			};
			var setFrame = function(frme) {
				_iframe = frme;
			};

			var wait = function(callback, maxWaitTime) {
				if (maxWaitTime && maxWaitTime > 0) {
					_timeoutId = window.setTimeout("es_net.URLContainer.containers['" + _iframe.id + "'].notify()", maxWaitTime);
				}
				_waiting = true;
				_callback = callback;
			};
			var getDocument = function() {
				return _iframe.contentDocument || _iframe.contentWindow.document;
			};

			this.isLocked = isLocked;
			this.isWaiting = isWaiting;
			this.lock = lock;
			this.unlock = unlock;
			this.wait = wait;
			this.notify = notify;
			this.getDocument = getDocument;
			this.setFrame = setFrame;
		}
		URLContainer.containers = {};
		URLContainer.block;
		URLContainer.incubator;
		URLContainer.touchContainer = function() {
			var node;
			var onload;
			var name;
			var length;
			var container = null;
			var doc = window.top.document;
			var block = URLContainer.block;
			var incubator = URLContainer.incubator;
			var arr = URLContainer.containers;
			var logger = es_util_logging.Logger.getLogger('es.net.URLContainer');

			length = 0;
			for (var n in arr) {
				length++;
				if (container == null && !arr[n].isLocked()) {
					container = arr[n];
				}
			}

			if (!container) {
				name = 'es.net.url-container.' + length;
				logger.info('Adding URL container: ' + name);

				if (!block) {
					block = document.getElementById('es-net-urlcontainer-block');
					if (!block) {
						block = doc.createElement('div');
						block.id = 'es-net-urlcontainer-block';
					}
						
					incubator = document.getElementById('es-net-urlcontainer-incubator');
					if (!incubator) {
						incubator = doc.createElement('div');
						incubator.id = 'es-net-urlcontainer-incubator';
					}
					block.appendChild(incubator);

					doc.body.appendChild(block);
					block.appendChild(incubator);
					URLContainer.block = block;
					URLContainer.incubator = incubator;
				}

				container = new URLContainer();
				URLContainer.containers[name] = container;

				incubator.innerHTML = '<iframe frameborder="none" id="' + name + '" src="about:blank" onload="es_net.URLContainer.containers[\'' + name + '\'].notify(this)"></iframe>';
				node = document.getElementById(name);
				container.setFrame(node);
				block.appendChild(node);
			}

			container.lock();

			return container;
		}

		// URLConnection
		URLConnection = function(url, method, target) {
			var _container;
			var _url = url;
			var _container = URLContainer.touchContainer();
			var _logger = es_util_logging.Logger.getLogger('es.net.URLConnection');
			var _method = (method) ? method : "post";
			var _output = new StringBuilder();

			var makeField = function(name, value) {
				var encvalue = new String(value);

				encvalue = encvalue.replace(/\"/g, '&quot;');
				_output.append('\r\n  <input autocomplete="off" name="' + name + '" value="' + encvalue + '"/>');
			};
			this.open = function(callback, timeout) {
				var doc = _container.getDocument();
				var buf = new StringBuilder();

				buf.append('<html><body>');
				buf.append('\r\n<form method="' + _method + '" action="' + _url  + '"' + ((target) ? ' target="' + target + '"' : '' ) + '>');
				buf.append(_output.toString());
				buf.append('\r\n</form>');
				buf.append('\r\n</body></html>');

				doc.open();
				doc.write(buf.toString());
				doc.close();
				doc.forms[0].submit();

				_container.wait(callback, timeout);
			};
			this.outputParameter = function(name, value) {
				makeField(name, value);
				return this;
			};
			this.outputMap = function(map, prefix) {
				var name;
				var value;

				if (map) {
					for (var p in map) {
						if (map.hasOwnProperty(p)) {
							value = map[p];
							if (value.constructor != Function) {
								name = ((prefix) ? prefix + p : p);
								makeField(name, value);
							}
						}
					}
				}
				return this;
			};
			this.outputForm = function(frm, /*String ...*/ fields) {
				var name;
				var value;
				var elm;
				var elms;
				var frmId;
				var type;

				if (frm) {
					if (frm.constructor == String) {
						frmId = frm;
						frm = document.getElementById(frmId);
						if (!frm) {
							throw new Error("Form ID: " + frmId + " does not exist");
						}
					} else {
						frmId = frm.id;
					}

					elms = frm.elements;
					if (elms) {
						if (arguments.length > 1) {
							if (fields && fields.constructor == Array) {
								start = 0;
							} else {
								start = 1;
								fields = arguments;
							}
							for (var i = start; i < fields.length; i++) {
								elm = frm[fields[i]];
								if (elm && elm.name) {
									type = (elm.type || '').toLowerCase();
									if ((type != 'radio' && type != 'checkbox') || elm.checked) {
										name = (frm.name) ? frm.name + "." + elm.name : elm.name;
										value = elm.value;
										makeField(name, elm.value);
									}
								}
					    }
						} else {
							for (var i = 0; i < elms.length; i++) {
								elm = elms[i];
								if (elm.name) {
									type = (elm.type || '').toLowerCase();
									if ((type != 'radio' && type != 'checkbox') || elm.checked) {
										name = (frm.name) ? frm.name + "." + elm.name : elm.name;
										value = elm.value;
										makeField(name, elm.value);
									}
								}
							}
						}
					} else {
						throw new Error("The supplied form: " + frmId + " was empty, or is not a form");
					}
				} else {
					throw new Error("No form was supplied");
				}

				return this;
			};
			this.output = function(str) {
				_output.append(str);
				return this;
			};
			this.close = function() {
				_output.clear();
				_container.unlock();
			};
		}
		/**
		 * this is an array of all the names of all allowed callback frames in this document.
		 */
		URLConnection.containers = [];			// TODO: deprecated -- remove this
			
		// URI
		// ---
		var URI = implement({
				scheme:			/*String*/ undefined,
				username:		/*String*/ undefined,
				password:		/*String*/ undefined,
				server:			/*String*/ undefined,
				directory:	/*String*/ undefined,
				filename:		/*String*/ undefined,
				extension:	/*String*/ undefined,
				fragment:		/*String*/ undefined,
				query:			/*String*/ undefined,
				path:       /*String*/ undefined
			}, 
			function(href) {
				var str;

				function nonEmpty(value) {
					if (value == undefined || value == null) return false;

					if (value.constructor == String) {
						return value.length > 0 && value.replace(/\s*/g, '').length > 0;
					} else {
						return nonEmpty(new String(value));
					}
				}

				// Clean up the inputs
				if (href) {
					var pos;

					str = href.replace(/^\s*/, '').replace(/\s*$/, '');

					if (str && str.length > 0) {
						// Split off the query string
						if ((pos = str.indexOf('?')) >= 0) {
							this.query = str.substring(pos + 1)
							str = str.substring(0, pos);
						}

						// Split off the fragment
						if ((pos = str.indexOf('#')) >= 0) {
							this.fragment = str.substring(pos + 1);
							str = str.substring(0, pos);
						}
						// Get the scheme (from the left):
						if ((pos = str.indexOf(':')) < str.indexOf('/') && pos > 0) {
							this.scheme = str.substring(0, pos);
							str = str.substring(pos + 1);
						}

						// Get the username:password@server component
						if (str.indexOf('//') == 0) {
							str = str.substring(2);

							if ((pos = str.indexOf('/')) < 0) {
								pos = str.length;
							}

							if (str.lastIndexOf('@', pos - 1) > 0) {
								this.username = str.substring(0, str.lastIndexOf('@'));
								if (this.username.length < pos - 1) {
									this.server = str.substring(str.lastIndexOf('@'), pos);
								}
								if (this.username.indexOf(':') > 0) {
									this.password = this.username.substring(this.username.indexOf(':') + 1);
									this.username = this.username.substring(0, this.username.indexOf(':'));
								} else {
								}
							} else {
								this.server = str.substring(0, pos);
							}
							
							if (str.length > pos) {
								str = str.substring(pos);
							} else {
								str = '/';
							}
						}

						// Get the directory path
						if (str.length > 0) {
							// Strip off any extension
							if ((pos = str.lastIndexOf('.')) > 0 && pos > str.lastIndexOf('/')) {
								if (pos < str.length - 1) {
									this.extension = str.substring(pos + 1);
								}
								str = str.substring(0, pos);
							}

							// Get the filename
							if (this.extension || this.fragment) {
								pos = str.lastIndexOf('/') + 1;
								if (pos < str.length) {
									this.filename = str.substring(pos);
									str = str.substring(0, pos);
								} else {
									this.filename = '';
								}
							}

							// Get the directory
							if (str.length > 0) {
								if (str.charAt(str.length - 1) != '/') {
									this.directory = str + '/';
								} else {
									this.directory = str;
								}
							}
						}
					}
				}

				// Public
				// ------
				// Relativize
				this.relativize = /*URI*/ function(/*String|URI*/ uri) {
					var thisdirs;
					var uridirs;
					var thisparts;
					var uriparts;
					var str;
					var char;
					var lastpos;
					var parencount;
					var result;

					if (!(uri instanceof URI)) {
						uri = new URI(uri);
					}

					// The scheme, server, username and password must match
					if ((uri.scheme && uri.scheme != this.scheme)
							|| uri.username != this.username
							|| uri.password != this.password
							|| (uri.server && uri.server != this.server)) {

						return uri;
					}

					result = new URI();
					result.directory = uri.directory;
					result.filename = uri.filename;
					result.extension = uri.extension;
					result.fragment = uri.fragment;
					result.query = uri.query;

					// Check the directories
					if (this.directory && uri.directory) {
						thisdirs = this.directory.split(/[\/\\]/g);
						uridirs = uri.directory.split(/[\/\\]/g);

						for (var i = 0; i < thisdirs.length; i++) {
							if (uridirs.length <= i || thisdirs[i] != uridirs[i]) {
								return result;
							}
						}
						if (i < uridirs.length) {
							str = '';
							for (i = i; i < uridirs.length; i++) {
								str += uridirs[i] + '/';
							}
							result.directory = str;
							return result;
						}
					} else if (uri.directory) {
						return result;
					}

					result.directory = undefined;
					if (this.filename == uri.filename && this.extension == uri.extension) {
						result.filename = undefined;
						result.extension = undefined;
					}

					return result;
				}

				// Resolve
				this.resolve = /*URI*/ function(/*String|URI*/ uri) {
					var pos;
					var endpos;
					var result;
					var remaining;

					if (!(uri instanceof URI)) {
						uri = new URI(uri);
					}

					// The scheme, server, username and password must match
					if (uri.scheme || uri.username || uri.password || uri.server) {
						return uri;
					}

					result = new URI();
					result.scheme = this.scheme;
					result.username = this.username;
					result.password = this.password;
					result.server = this.server;
					result.directory = uri.directory;
					result.filename = uri.filename;
					result.extension = uri.extension;
					result.fragment = uri.fragment;
					result.query = uri.query;

					if (this.directory) {
						if (!uri.directory) {
							result.directory = this.directory;
						} else if (uri.directory.charAt(0) != '/') {
							result.directory = this.directory;

							for (pos = 0; uri.directory.substring(pos, pos + 3) == '../'; pos += 3) {
								if (result.directory == '/') {
									throw new Error("Cannot resolve: " + uri.toString() + " against " + this.toString());
								}
								endpos = result.directory.lastIndexOf('/', result.directory.length - 2);
								result.directory = result.directory.substring(0, endpos + 1);
							}

							if (pos < uri.directory.length) {
								result.directory += uri.directory.substring(pos);
							}

							return result;
						}
					}

					if (!uri.filename) {
						result.filename = this.filename;
						result.extension = this.extension;
					}

					return result;
				}

				// Remainder
				this.remainder = function(/*URI|String*/ uri) {
					var pos;
					var reluri;

					if (!uri || uri == '') {
						return new URI();
					} else {
						reluri = this.relativize(uri);

						if (this.filename) {
							if (!reluri.extension && !reluri.filename && !reluri.directory) {
								if (this.fragment && reluri.fragment) {
									if (reluri.fragment.indexOf(this.fragment) == 0) {
										reluri.fragment = reluri.fragment.substring(this.fragment.length);
									} else {
										return null;
									}
								} else if (this.fragment) {
									return null;
								}
								return reluri;
							}
						
						} else if (this.directory) {
							if (!reluri.directory || reluri.directory.charAt(0) != '/') {
								return reluri;
							}
						}
						return null;
					}
				}

				this.clone = function() {
					var clone = new URI();
					
					clone.scheme = this.scheme;
					clone.username = this.username;
					clone.password = this.password;
					clone.server = this.server;
					clone.directory = this.directory;
					clone.filename = this.filename;
					clone.extension = this.extension;
					clone.fragment = this.fragment;
					clone.query = this.query;

					return clone;
				}
				this.equals = function(/*URI*/ other) {
					if (other != null
							&& ((!this.scheme && !other.scheme) || (this.scheme == other.scheme))
							&& ((!this.username && !other.username) || (this.username == other.username))
							&& ((!this.password && !other.password) || (this.password == other.password))
							&& ((!this.server && !other.server) || (this.server == other.server))
							&& ((!this.directory && !other.directory) || (this.directory == other.directory))
							&& ((!this.filename && !other.filename) || (this.filename == other.filename))
							&& ((!this.extension && !other.extension) || (this.extension == other.extension))
							&& ((!this.fragment && !other.fragment) || (this.fragment == other.fragment))
							&& ((!this.query && !other.query) || (this.query == other.query))) {
						return true;
					} else {
						return false;
					}
				}
				this.toString = function() {
					href = '';
					if (this.scheme) href += this.scheme + '://';
					if (this.username) {
						if (this.password) {
							href += this.username + ':' + this.password + '@';
						} else {
							href += this.username + '@';
						}
					}
					if (this.server) href += this.server;
					if (this.directory) href += this.directory;
					if (this.filename) href += this.filename;
					if (this.extension) href += '.' + this.extension;
					if (this.fragment) href += '#' + this.fragment;
					if (this.query) href += '?' + this.query;

					return href;
				}

				if (nonEmpty(this.filename) && nonEmpty(this.directory)) {
					this.path = this.directory + this.filename;
					if (this.extension) {
						this.path += '.' + this.extension;
					}
				} else if (nonEmpty(this.filename)) {
					this.path = this.filename;
					if (this.extension) {
						this.path += '.' + this.extension;
					}
				} else if (nonEmpty(this.directory)) {
					this.path = this.directory;
				} else {
					this.path = null;
				}
			}
		);

		// === PACKAGE PUBLIC ===
		this.URLContainer = URLContainer;
		this.URLConnection = URLConnection;
		this.URI = URI;
		// === PACKAGE PUBLIC ===
	}
);

