if(typeof base2 !== "undefined"){
	new function(_){
		var twootr = new base2.Package(this, {
			name: "Twootr",
			version: "0.1",
			imports: "PrettyDate,JavaScript",
			exports: "Inputs,Updater,Ajax"
		});
		
		// evaluate the imported namespace
		eval(this.imports);
		
		function myBind(obj, fn) {
			if (typeof fn === "function") {
				return function (args) {
					fn.apply(obj, args && args.callee ? args : arguments);
				};
			} else {
				throw "Need a function to bind to.";
			}
		}
		
		var Inputs = Base.extend({
			constructor: function(/*HTMLElement*/element, /*RegExp*/validator, /*String*/defaultClass) {
				this.element = element;
				this.validator = validator||/.*/;
				this.defaultClass = defaultClass||"default";
				
				this.initialValue = this.getValue();
				if(base2.DOM.HTMLElement.hasClass(this.element, this.defaultClass)){		
					base2.DOM.Element.addEventListener(this.element, "click", myBind(this, this.onClick), false);
					base2.DOM.Element.addEventListener(this.element, "blur", myBind(this, this.onBlur), false);
				}
			},
			getValue: function() {
				return this.element.value;
			},
			setValue: function(/*String*/value) {
				this.element.value = value || "";
			},
			isValid: function(){
				return this.getValue().match(this.validator) !== null;
			},
			onClick: function() {
				if(this.getValue() == this.initialValue) {
					this.setValue();
					base2.DOM.HTMLElement.removeClass(this.element, this.defaultClass);
				}
			},
			onBlur: function() {
				if(this.getValue() === "") {
					this.setValue(this.initialValue);
					base2.DOM.HTMLElement.addClass(this.element, this.defaultClass);
				}
			}
		});
		
		var Ajax = Base.extend({
			oReadyStates : {
				0: "onNotInitialized",
				1: "onSetUp",
				2: "onSent",
				3: "onInProcess"
			//	4: "onComplete" (use onSuccess and onFailure)
			},
			constructor: function(/*String*/sMethod, /*String*/sUrl, /*Hash*/oOptions, /* Object */ oBind) {
				this.sMethod = sMethod.toUpperCase()||"GET";
				this.sUrl = sUrl;
				this.oOptions = oOptions||{};
				this.oBind = oBind||this; // leak?
				this.bAborted = false;
				this.nTimeout = 0;
				
				if(!sUrl){
					throw "Method appears to be empty.";
				}
				
				if(!"body" in this.oOptions) {
					this.oOptions.body = null;
				} else {
					if(this.sMethod === "GET") {
						sUrl += "?"+encodeURIComponent(this.oOptions.body);
					}
				}
				
				this.oXhr = this.newXhr();
				if(this.oXhr) { 
					this.oXhr.onreadystatechange = myBind(this, this.onReadyStateChange);
					
					if("onProgress" in this.oOptions)
						this.oXhr.onprogress = myBind(this.oBind, this.oOptions.onProgress);
					if("onLoad" in this.oOptions)
						this.oXhr.onload = myBind(this.oBind, this.oOptions.onLoad);
					if("onError" in this.oOptions)
						this.oXhr.onerror = myBind(this.oBind, this.oOptions.onError);
					
					this.oXhr.open(this.sMethod, sUrl, true);
					
					if(this.sMethod === "POST") {
						this.oXhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
					//} else if("header" in this.oOptions) {
					//	for(var sHeader in this.oOptions.header) {
					//		this.oXhr.serRequestHeader(sHeader, this.oOptions.header);
					//	}
					}
					
					if("timeout" in this.oOptions) {
						this.nTimeout = setTimeout(myBind(this, this.onTimeIsUp), this.oOptions.timeout);
					}
					
					this.oXhr.send(this.oOptions.body);
				} else {
					throw "Unable to create a XHR instance.";
				}
			},
			newXhr: function() {
				var aAjaxes = new Array2();
				if(typeof XMLHttpRequest !== "undefined") {
					 aAjaxes.push({cls:XMLHttpRequest, arg:undefined});
				}
				if(typeof ActiveXObject !== "undefined") {
					var oCls = ActiveXObject;
					aAjaxes.unshift({cls:oCls, arg:"Microsoft.XMLHTTP"},
						{cls:oCls, arg:"Msxml2.XMLHTTP"},
						{cls:oCls, arg:"Msxml2.XMLHTTP.3.0"});
				}
				
				for(var i=aAjaxes.length; i--; ) {
					try{
						var oXhr = new aAjaxes[i].cls(aAjaxes[i].arg);
						if(oXhr) {
							return oXhr;
						}
					} catch(e) {}
				}
				return null;
			},
			onReadyStateChange:function(){
				if(!this.bAborted) {
					var nState = this.oXhr.readyState;
					if(nState in this.oReadyStates){
						var sName = this.oReadyStates[nState];
						if(sName in this.oOptions && typeof this.oOptions[sName] === "function") {
							myBind(this.oBind, this.oOptions[sName])(this.oXhr);
						}
					} else if(nState == 4) {
						this.onComplete();
					} else {
						throw "State: "+nState+" not supported";
					}
				}
			},
			onComplete: function() {
				var status = this.oXhr.status;
				var sStatus = (status/100 == 2) ?
					"onSuccess" :
					"onFailure";
				
				if(sStatus in this.oOptions) {
					myBind(this.oBind||this, this.oOptions[sStatus])(this.oXhr);
				}
				
				this.cleanUp();
			},
			onTimeIsUp: function() {
				this.bAborted = true;
				this.oXhr.abort();
				
				var sStatus = "onTimeout";
				if(sStatus in this.oOptions) {
					myBind(this.oBind||this, this.oOptions[sStatus])();
				}
				this.cleanUp();
				delete this.oXhr;
			},
			cleanUp: function() {
				if(this.nTimeout) {
					clearTimeout(this.nTimeout);
				}
				// fix a memory leak in IE.
				this.oXhr.onreadystatechange = function(){};
			}
		});
		
		var Updater = Base.extend({
			constructor:function(oElement){
				this.oElement = oElement;
				this.nIntervalSeconds = 60;
				this.nFailures = 0;
				
				if(!this.sUser) {
					var match = oElement.className.match(/\buser([^\b\s]+)\b/);
					if (match) {
						this.sUser = match[1];
					}
				}
				
				if(!this.nLastTwootId) {
					match = oElement.className.match(/\bt(\d+)\b/);
					if (match) {
						this.nLastTwootId = parseInt(match[1], 10);
					}
				}
				
				// Usual Ajax method
				//if(this.nLastTwootId) {
				//	this.nInterval = setInterval(myBind(this, this.onRefresh), this.nIntervalSeconds * 1000);
				//}
				
				// Let's do it the Comet way
				this.onRefreshLongPolling();
			},
			onRefresh: function() {
				var sBody = "id="+(this.nLastTwootId);
				if(this.sUser) {
					sBody += "&user="+this.sUser;
				}
				if(!("oAjax" in this && this.oAjax)) {
					this.oAjax = new Ajax("POST", "/ajax/", {
							body: sBody,
							onSuccess: function(oXhr) {
								this.onUpdate(eval("("+oXhr.responseText+")"));
								// update the times.
								updateElements("abbr.updated");
							}
						}, this);
				}
			},
			onRefreshLongPolling: function() {
				var sBody = "id="+(this.nLastTwootId);
				sBody += "&long_polling="+(this.nIntervalSeconds * 1000);
				
				if(this.sUser) {
					sBody += "&user="+this.sUser;
				}
				
				if(this.nFailures > 4) {
					// the server may be in a bad shape, let's taking care of it.
					return;
				}
				
				if(!("oAjax" in this && this.oAjax)) {
					this.oAjax = new Ajax("POST", "/ajax/", {
							body: sBody,
							timeout: (this.nIntervalSeconds * 1.2) * 1000,
							onSuccess: function(oXhr) {
								this.onUpdate(eval("("+oXhr.responseText+")"));
								// update the times.
								updateElements("abbr.updated");
								
								setTimeout(myBind(this, this.onRefreshLongPolling), 1000);
								
								this.nFailures = 0;
								delete this.oAjax;
							},
							onFailure: function(oXhr) {
								setTimeout(myBind(this, this.onRefreshLongPolling), 1000);
								
								this.nFailures+=1;
								delete this.oAjax;
							},
							onTimeout: function() {
								setTimeout(myBind(this, this.onRefreshLongPolling), 1000);
								
								this.nFailures+=1;
								delete this.oAjax;
							}
						}, this);
				}
				
				// update the times.
				updateElements("abbr.updated");
			},
			onUpdate: function(oData) {
				if(oData.length) {
					var oLi = document.createElement("li");
					var dNow = new Date();
					var aLis = [];
					for(var i=oData.length; i--;) {
						var oEntry = oData[i];
						var newLi = oLi.cloneNode(false);
						newLi.id = "t"+oEntry.id;
						newLi.className = "entry";
						newLi.style.borderColor = oData[i].color;
						var aHtml = ['<a href="/',
							oEntry.nick,
							'/" class="author vcard">',
							oEntry.nick,
							'</a> <q class="entry-title entry-content">',
							oEntry.text,
							'</q> <span class="meta">'];
						if("reply" in oEntry && oData[i].reply !== null) {
							aHtml.push('in reply to <a href="/',
								oEntry.reply.nick,
								'/',
								oEntry.reply.id,
								'/">',
								oEntry.reply.nick,
								'</a>, ');
						}
						var dDate = parseDate(oEntry.created);
						var sText = diffToString((dNow - dDate)/1000);
						aHtml.push('<a href="/',
							oEntry.nick,
							'/',
							oEntry.id,
							'/" title="permalink" rel="bookmark"><abbr title="',
							oEntry.created,
							'" class="updated">',
							oEntry.created_human,
							'</abbr></a>.</span>');
						newLi.innerHTML = aHtml.join("");
						
						aLis.push(newLi); // MSIE 5 will collapse here.
					}
					for(i=0, l=aLis.length; i<l;i++) {
						this.oElement.insertBefore(aLis[i], this.oElement.firstChild);
					}
					
					base2.DOM.HTMLElement.removeClass(this.oElement, "t"+this.nLastTwootId);
					this.nLastTwootId = oData[oData.length-1].id;
					base2.DOM.HTMLElement.addClass(this.oElement, "t"+this.nLastTwootId);
				}
			}
		});
		
		eval(this.exports);
	} // end main closure
	
	new function() {
		var aInputs = base2.DOM.Document.querySelectorAll(document, "input.text");
		for (var i = 0; i < aInputs.length; i++) {
			new base2.Twootr.Inputs(aInputs.item(i));
		}
		
		var aFeeds = base2.DOM.Document.querySelectorAll(document, ".hfeed.autorefresh");
		for(var i = 0; i < aFeeds.length; i++) {
			new base2.Twootr.Updater(aFeeds.item(i));
		}
	}
} // endif
