// used by makeClass
var _loaded = false;
try { 
	if(this.Confex && this.Confex.loaded && this.Confex.loaded[0]) { 
		_loaded = true;
	}
} catch(e) {}

if(!_loaded) { 
	var Confex = new Function();
	Confex.loaded = ['domcore'];


	var global = this;

	global.Confex = Confex;


	/* Parts from prototype.js */
	Function.prototype.bind = function() {
		var __method = this, args = Array.from(arguments), object = args.shift();
		return function() {
			return __method.apply(object, args.concat(Array.from(arguments)));
		}
	};

	Array.from = function(iterable) {
		if (!iterable) return [];
		if (iterable.toArray) {
			return iterable.toArray();
		} else {
			var results = [];
			for (var i = 0; i < iterable.length; i++)
				results.push(iterable[i]);
			return results;
		}
	}

	/* End parts from prototype.js */





	function gi(id) { return document.getElementById(id) }

	function addEvent(el, evname, func, capture) {
		/* this code from Mishoo's DHTML Calendar 0.9.6. (LGPL Licensed, see http://www.fsf.org/licenses/lgpl.html) 
		 */
		if(arguments.length == 3) { capture = true; };
		if (el.attachEvent) { // IE
			el.attachEvent("on" + evname, func);
		} else if (el.addEventListener) { // Gecko / W3C
			el.addEventListener(evname, func, capture);
		} else {
			el["on" + evname] = func;
		}
	}

	/*
         * Creating named inputs via DOM functions is complicated by being unable to use setAttribute for 'name'
         *   in Internet Explorer.  However, createElement in IE can handle the full html for a given tag, while
         *   all other browsers return an error when trying to use this behavior.  If we catch that error, we can
         *   revert to using setAttribute, and both cases are handled gracefully.
	 */
	function hinput(nodename, attr) {
		var newinput;
		try { // IE
			var tag = nodename;
			if (attr) {
				for (var a in attr) {
					tag += ' '+a+'="'+attr[a]+'"';
				}
			}
			newinput = document.createElement('<'+tag+'>');

		} catch (e) { // normal browsers
			newinput = document.createElement(nodename);
			if (attr) {
				for (var a in attr) {
					newinput.setAttribute(a, attr[a]);
				}
			}
		}
                return newinput;
        }
        
	function htree (nodename, attr, childs) { 
		var n = document.createElement(nodename);
		if(attr) { 
			for(var i in attr) { 
				n[i] = attr[i];
			}
		}
		if(childs) { 
			for(var i in childs) { 
				try { 
					n.appendChild(childs[i]);
				} catch(e) {
					//debugger;
					throw("DOM Exception: '" + e.message + "' while appending a " + childs[i] + " to a " + n);
				}
			}
		}
		return n;
	}
	function t(text) { return document.createTextNode(String(text)) }

	function ascendGrep(matcher, node) { 
		
		while(node != null &&
				!matcher(node)) { 
			node = node.parentNode;
		}

		return node;
	}

	function domBreadthDescend (node, func) {
		func(node);
		for (var i = 0; i < node.childNodes.length; i++ ) { 
			if(domBreadthDescend(node.childNodes[i],func)) break;
		}
	}

	function domDepthDescend (node, func) {
		for (var i = 0; i < node.childNodes.length; i++) { 
			if(domDepthDescend(node.childNodes[i],func)) break;
		}

		func(node);
	}




	/** makeClass
		
		This function should be used to declare classes.  This handles all the dirty work
		of building the base class, inheritence, and what not.
	  */
	function makeClass(name,data,init,scope) {

		if(!scope) { scope = global; }
		if(name.match(/\./)) { 
			var parts = name.split(/\./);
			for(var i = 0; i < parts.length - 1; i++)  { 
				if(!scope[parts[i]]) { 
					scope[parts[i]] = {};
				}
				scope = scope[parts[i]];
			}
			name = parts[parts.length - 1];
		}

		var constructor;
		if(data.constructor && data.constructor.prototype != Object.prototype) {
			constructor = scope[name] = data.constructor;
			delete data.constructor;
		} else {
			constructor = scope[name] = new Function();
		}

		if(data.prototype) {
			for(var i in data.prototype)  {
				constructor.prototype[i] = data.prototype[i];
			}
			delete data.prototype;
		}
		if(data.isa) {
			var isa = data.isa;
			delete data.isa;

			for(var i in isa)  {
				for(var field in isa[i].prototype) { 
					constructor.prototype[field] = isa[i].prototype[field];
				}
			}
		}

		for(var i in data)
			constructor.prototype[i] = data[i];

		if(init) { init(constructor); }

		return constructor;
	}


	/**
		analagous to perl's bless.

		Instanciates a new object, and copies given data into the
		new object.
	  
	  */
	function bless(data,obj) { 
		var self = new obj();

		for(var i in data) self[i] = data[i];	
		
		if(self.onblessed) { self.onblessed(data,obj); }

		return self;
	}




	function toJSON(arg) { 
		var i, outputBuf, value;
		switch (typeof arg) {
			case 'object':
				if (arg) {
					if (arg.constructor == Array) {
						outputBuf = '[';
						for (i = 0; i < arg.length; ++i) {
							value = toJSON(arg[i]);
							if (value != 'function' && typeof value !== 'undefined') {
								outputBuf += (outputBuf != '[' ? ',' : '') + value;
							} else {
								outputBuf += ',';
							}
						}
						return outputBuf + ']';
					} else if (typeof arg.toString != 'undefined') {
						outputBuf = '{';
						for (i in arg) {
							value = toJSON(arg[i]);
							if (value != 'function' && typeof value !== 'undefined') {
								outputBuf += (outputBuf != '{' ? ',' : '') +
									toJSON(i) + ':' + value;
							}
						}
						return outputBuf + '}';
					} else {
						return;
					}
				}
				return 'null';
			case 'unknown':
			case 'undefined':
				return 'undefined';
			case 'string':
				var s = arg.replace(/\\/g,'\\\\');
				s = s.replace(/"/g,'\\"');
				return '"' + s + '"';
			case 'function':
				return 'function';
			default:
				return String(arg);
		}
	}




	/* sprintf

	Tries really hard to be like the unix function by the same name.  Note, snprintf is unnesscary due to js's memory management.

	Conversion specifiers currently supportd: 
	 s - string ( no flags, just field width ) 
	 i,d - integer/decimal (same thing) (padding and field width flags)

	flags supported: 
	 '0' - zero pad
	 ' ' - space pad



	   
	*/
	function sprintf() {
		var format = arguments[0];
		
		// stores position of next argument to consume.	
		var argCounter = 1;
		
		/*
		 this works by regex'ing up to the next format string,
		 contacenating the previous part to the buffer, performing the
		 conversion described in the format string, and placing the rest back into
		 the 'formatRest' string to repeat again.
		 once the formatRest string contains no match, no more format strings exist,
		 and the contents of formatRest are appeneded to the rest of the output buffer.
		*/
		
		// the rest of the format string.
		var formatRest = new String(format);
		var buffer = '';
		while(formatRest.length > 0) { 	
			if(res = formatRest.match(/^([^%]*?)%(.*?)([idpfFs%])(.*?)$/)) { 
				buffer+=res[1]; // append the before-string to the end of the buffer.
				
				// this is what we really care about to execute the format string.
				var flagStr = res[2];
				var conversion = res[3];
				formatRest = res[4];

				var flags = {width: '',radix: '',pad: ' ',leftAlign: true,alwaysSign: false};
				var arg = argCounter++;
				for(var i = 0; i < flagStr.length; i++) { 
					var singleChar = flagStr.charAt(i);
					switch(singleChar) { 
						case '0':
							flags.pad = '0'; break;
						case ' ':
							flags.pad = ' '; break;
						case '+': 
							flags.alwaysSign = true; break;
						case '-': 
							flags.leftAlign = false; break;

						case "'":
							flags.groupThousandths = true; break;

						case '.': // enter read-radix mode.
							flags.readRadix = true; break;

						case '$': //we really just read a positional flag.
							// convert width to the arg position, and reset the width.
							arg = Number(flags.width);
							flags.width = '';
							
							argCounter--; // unadavnace the pointer, this means we don't consume the argument.

							break;
							
						case '#':
						case 'I':
							//legal according to GNU, but ignored.
							break;
						default:
							if(Number(singleChar) > 0) { 
								//these are intentionally string contatenations.
								if(flags.readRadix) { 
									flags.radix+=singleChar;
								}  else { 
									flags.width+=singleChar;
								}
							}
					}
				}
				if(flags.width != '') { flags.width = Number(flags.width); } else { flags.width = false; }
				if(flags.radix != '') { flags.radix = Number(flags.radix); } else { flags.radix = false; }
				

				var asString;
				//NOTE: Any case you add here has to be added to the regex above.
				switch(conversion) {
					case '%': 
						asString = '%'; break;
					case 'p':
						var value = Number(arguments[arg]);
						if(value != 1) { 
							asString = 's';
						} else { 
							asString = '';
						}
						break;
					case 's':
						asString = String(arguments[arg]);
						if(flags.radix) { 
							asString = asString.substr(0,flags.radix);
						}
						if(flags.width && asString.length < flags.width) {
							while(asString.length < flags.width) { 
								if(flags.leftAlign) { 
									asString = flags.pad + asString
								} else { 
									asString = asString + flags.pad;
								}
							}
						}
						break;
					case 'f':
					case 'F':
						asString = String(arguments[arg]);
						break;
					case 'i':
					case 'd':
						var value = Number(arguments[arg]);
						var abs = Math.floor(Math.abs(value));
						var asString = String(abs);
						var leftIsPad = false;
						if(flags.width && asString.length < flags.width) {
							while(asString.length < flags.width) { 
								if(flags.leftAlign) { 
									asString = flags.pad + asString
								} else { 
									asString = asString + flags.pad;
								}
							}
						}
						if(value < 0 || flags.alwaysSign) { 
							var sign = (value < 0 ? '-' : '+' );
							if(asString.charAt(0) == '0') { 
								asString = sign + asString.substr(1);
							}  else if (asString.charAt(0) == ' ') { 
								var spaceIndex = -1;
								while(asString.charAt(++spaceIndex) == ' ');

								asString = asString.substr(0,spaceIndex - 1) 
									+ sign 
									+ asString.substr(spaceIndex);
							} else { 
								asString = sign + asString;
							}
						}
						break;
					default: 
						asString = String(arguments[arg]);
				};

				buffer+=asString;

			} else { 
				// happens on last match.
				buffer+= formatRest;
				formatRest = '';
			}
		}
		return buffer;
		
	}




	/**
	  Analagous to perl's map, but note argument are reversed.
	  
	  */
	function map(list, func) { 
		var newlist = [];
		for(var i = 0; i < list.length; i++) { 
			newlist.push(func(list[i]));
		}
		return newlist;
	}

	/**
		grepobj,grep	
		  
		Similar to perl's grep, but this version understands objects.

		passed 2 arguments, list, func
		
		if you use grep(): 
		you will always get a list back.  List has to be a JS array, or another object that supports
		the .length property, and bracket-indexing.

		if you use grepobj():

		if list is an object then a new object will be returned where func evaluates to true.

		if list is an array, then a new array will be returned where func evaluats to true.

		func is a function object that takes 2 arguments a value, and a key/index into the object/array.

		

	  */
	function grepobj(list, func) { 
		var newlist = [];
		if ( typeof list == 'object' ) {
			newlist = {};
		}  
		
		for(var i in list) {
			if(func(list[i],i)) { 
				if (newlist.push){
					newlist.push(list[i]);
				} else {
					newlist[i] = list[i];
				}
			}
		}
		return newlist;
	}

	function grep(list, func) { 
		var newlist = [];
		for(var i = 0; i < list.length; i++) {
			if(func(list[i],i)) { 
				newlist.push(list[i]);
			}
		}
		return newlist;
	}


	/* Timeout lib.  Provides a cleaner interface over setTImeout */
	if(!window._timeouts) { window._timeouts = {}; }

	window._handleTimeout = function (index) { 
	    if(window._timeouts[index]) {
		window._timeouts[index].obj.fireEvent(index);
	    } else {
		// event is lost in time!
		gridAlert("lost track of event index " + index);
	    }
	}

	makeClass('Timeout',{
	    constructor: function(timems, code) {
		    this.key = 0;
		    this.code = code;
		    this.timems = timems;
	    },
	    setTimeout: function() {

		    // search for a random key slot to assign this timeout into.
		    while(window._timeouts[this.key])
			this.key = Math.round(Math.random() * 1000);

		    window._timeouts[this.key] = { obj: this }

		    //save the timeout id.
		    this.timeoutSet = window.setTimeout("window._handleTimeout(" + this.key + ")", this.timems);
	    },
	    fireEvent:  function(index) {
		    this.clearTimeout();
		    // eventually i may be able to figure out to change the 'scope' of this call
		    // so passing 'this' isn't redunant '
		    return this.code(this);
	    },
	    clearTimeout:  function() { 
		if(this.timeoutSet) { 
		    window.clearTimeout(this.timeoutSet);
		    delete(window._timeouts[this.key]);
		    this.timeoutSet = false;
		}
	    },
	    reset: function() { this.clearTimeout(); this.setTimeout(); }
	});

	/**
	  yieldThenRun takes a function as an argument.  This yields time to the
	  browser's UI thread to updates can be drawn to the screen, then runs 
	  the given function.  This is the only way to let the browser redraw
	  after you make an update to the DOM (if you'd like to keep running javascript)
	  */
	function yieldThenRun(func) { 
		(new Timeout(1,func,true)).setTimeout();
	}

	function yieldForLoop(indexStart, indexEnd, bodyCode,doneCode) { 

		(function(body, start, end, done) { 
			var index = start;
			var nextItem;
			var skip = Math.ceil((end - start) / 100);
			nextItem = function() { 
				(new Timeout(0,
				     function() { 
						var skipstart = skip;
						while( (index < end) && (skipstart > 0)) { 
							skipstart--;
							body(index++);
						}
						if(index < end) {
							// This appears recursive, but all it really does is
							// install a timer for the window thread to pickup on and invoke the code again.
							nextItem();
						} else { 
							done();
						}
					}
				     ,true)).setTimeout();
			};
			nextItem();
		})(bodyCode,indexStart,indexEnd,doneCode);
	}


	/** 
	  applyBehavior - appplies behaviors in global var 'behaviors' to the given
	  node and all children of that node. behaviors should be an object, w/ properties that name
	  either a class name, or a node id.  example:

	   { 
	      popuplink: function(n) { }
	      '#record123': function(n) { }
	   }
	   
	   You can install events (using addEvent) or transform the nodes if you'd like.
	  */


	function applyBehaviors(node) { 
		domDepthDescend(node,function(n) { 
			if(n.className != '') { 
				var className = String(n.className);
				for(var i in behaviors) {
					if(className.match(i)) { 
						behaviors[i](n);
					}
				}

			} 
			// if the node has an ID, then 
			// attach that behavior
			if(n.id && behaviors['#' + n.id]) { 
				behaviors['#' + n.id](n);
			}
		});

	}


	function scrollOffset(theWindow) { 
		if(!theWindow) theWindow = window;

		var x,y;
		if (theWindow.self.pageYOffset) { // all except Explorer
		
			x = theWindow.self.pageXOffset;
			y = theWindow.self.pageYOffset;
		} else if (theWindow.document.documentElement && theWindow.document.documentElement.scrollTop) {
			// Explorer 6 Strict
		
			x = theWindow.document.documentElement.scrollLeft;
			y = theWindow.document.documentElement.scrollTop;
		} else if (theWindow.document.body) { // all other Explorers
		
			x = theWindow.document.body.scrollLeft;
			y = theWindow.document.body.scrollTop;
		}

		return {x: x, y: y}
	}

}
