/**
*  ### CHILDSCRIPT OF PROTOTYPE.js USING bsn NAMEPSPACE
 *  author:		Timothy Groves - http://www.brandspankingnew.net
 *	version:	2.1.3 - 2007-07-19
 * ### MODIFIED FOR PLDH.net
 */
if (typeof(bsn) == "undefined")
	_b = bsn = {};
if (typeof(_b.Autosuggest) == "undefined")
	_b.Autosuggest = {};
else
	alert("Autosuggest is already set!");
_b.AutoSuggest = function (id, param) {
  /* NO DOM = FAIL */
	if (!document.getElementById)
		return 0;
  /* DOM GETS FIELD */
	this.fld = _b.DOM.gE(id);
	if (!this.fld)
		return 0;
  /* INIT VARS */
	this.sInp 	= "";
	this.nInpC 	= 0;
	this.aSug 	= [];
	this.iHigh 	= 0;
  /* PARAMETERS OBJECT */
	this.oP = param ? param : {};
  /* SETS DEFAULTS */
	var k, def = {minchars:1, meth:"get", varname:"input", className:"autosuggest", timeout:2500, delay:500, offsety:-5, shownoresults: true, noresults: "No results!", maxheight: 250, cache: true, maxentries: 10};
	for (k in def) {
		if (typeof(this.oP[k]) != typeof(def[k]))
			this.oP[k] = def[k];
	}
  /* SET KEYUP HANDLER FOR FIELD AND PREVENT CLIENT AUTOSUGGEST */
	var p = this;
  /**
	 NOTE: not using addEventListener because UpArrow fired twice in Safari
	_b.DOM.addEvent( this.fld, 'keyup', function(ev){ return pointer.onKeyPress(ev); } );
  */
	this.fld.onkeypress 	= function(ev){ return p.onKeyPress(ev); };
	this.fld.onkeyup 		= function(ev){ return p.onKeyUp(ev); };
	this.fld.setAttribute("autocomplete","off");
};
_b.AutoSuggest.prototype.onKeyPress = function(ev) {
	var key = (window.event) ? window.event.keyCode : ev.keyCode;
	/** set responses to keydown events in the field
	  this allows the user to use the arrow keys to scroll through the results
	  ESCAPE clears the list
	  TAB sets the current highlighted value
	*/
	var RETURN = 13;
	var TAB = 9;
	var ESC = 27;
	var bubble = 1;
	switch(key) {
		case RETURN:
			this.setHighlightedValue();
			bubble = 0;
			break;
		case ESC:
			this.clearSuggestions();
			break;
	}
	return bubble;
};
_b.AutoSuggest.prototype.onKeyUp = function(ev) {
	var key = (window.event) ? window.event.keyCode : ev.keyCode;
	/** set responses to keydown events in the field
	  this allows the user to use the arrow keys to scroll through the results
	  ESCAPE clears the list
	  TAB sets the current highlighted value
	*/
	var ARRUP = 38;
	var ARRDN = 40;
	var bubble = 1;
	switch(key) {
		case ARRUP:
			this.changeHighlight(key);
			bubble = 0;
			break;
		case ARRDN:
			this.changeHighlight(key);
			bubble = 0;
			break;	
		default:
			this.getSuggestions(this.fld.value);
	}
	return bubble;
};
_b.AutoSuggest.prototype.getSuggestions = function (val) {
	/* IF INPUT IS UNCHANGED, DO NOTHING */
	if (val == this.sInp)
		return 0;
	/* KILL LIST */
	_b.DOM.remE(this.idAs);
	this.sInp = val;
  /* IF INPUT LEN IS < SET LEN, DO NOTHING */
	if (val.length < this.oP.minchars) {
		this.aSug = [];
		this.nInpC = val.length;
		return 0;
	}
	var ol = this.nInpC; // old length
	this.nInpC = val.length ? val.length : 0;
	/**
	  if caching enabled, and user is typing (ie. length of input is increasing)
	  filter results out of aSuggestions from last request
	*/
	var l = this.aSug.length;
	if (this.nInpC > ol && l && l<this.oP.maxentries && this.oP.cache) {
		var arr = [];
		for (var i=0;i<l;i++) {
			if (this.aSug[i].value.substr(0,val.length).toLowerCase() == val.toLowerCase())
				arr.push( this.aSug[i] );
		}
		this.aSug = arr;
		this.createList(this.aSug);
		return false;
	} else {
	  /* DO NEW REQUEST */
		var pointer = this;
		var input = this.sInp;
		clearTimeout(this.ajID);
		this.ajID = setTimeout( function() { pointer.doAjaxRequest(input) }, this.oP.delay );
	}
	return false;
};
_b.AutoSuggest.prototype.doAjaxRequest = function (input) {
  /* CHECK IF THE INPUT STILL EXISTS */
	if (input != this.fld.value)
		return false;	
	var pointer = this;
  /* CREATE THE AJAX REQUEST */
	if (typeof(this.oP.script) == "function")
		var url = this.oP.script(encodeURIComponent(this.sInp));
	else
		var url = this.oP.script+this.oP.varname+"="+encodeURIComponent(this.sInp);
	if (!url)
		return false;
	var meth = this.oP.meth;
	var input = this.sInp;
	var onSuccessFunc = function (req) { pointer.setSuggestions(req, input) };
	var onErrorFunc = function (status) { alert("AJAX error: "+status); };
	var myAjax = new _b.Ajax();
	myAjax.makeRequest( url, meth, onSuccessFunc, onErrorFunc );
};
_b.AutoSuggest.prototype.setSuggestions = function (req, input) {
	/* IF ENTRY IS CHANGED DROP THE EXISTING LIST */
	if (input != this.fld.value)
		return false;
	this.aSug = [];
	if (this.oP.json) {
		var jsondata = eval('(' + req.responseText + ')');
		for (var i=0;i<jsondata.results.length;i++) {
			this.aSug.push(  { 'id':jsondata.results[i].id, 'value':jsondata.results[i].value }  );
		}
	} else {
		var xml = req.responseXML;
	/* TRAVERSE THE XML */
		var results = xml.getElementsByTagName('results')[0].childNodes;
		for (var i=0;i<results.length;i++) {
			if (results[i].hasChildNodes())
				this.aSug.push(  { 'id':results[i].getAttribute('id'), 'value':results[i].childNodes[0].nodeValue }  );
		}
	
	}
	this.idAs = "as_"+this.fld.id;
	this.createList(this.aSug);
};
_b.AutoSuggest.prototype.createList = function(arr) {
	var pointer = this;
  /* GETS RID OF OLD LIST AND CLEAR REMOVAL TIMEOUT */
	_b.DOM.remE(this.idAs);
	this.killTimeout();
  /* IF NO RESULTS, AND shownoresults FALSE, DO NOTHING */
	if (arr.length == 0 && !this.oP.shownoresults)
		return false;
  /* CREATES PARENT DIV */
	var div = _b.DOM.cE("div", {id:this.idAs, className:this.oP.className});
	var hcorner = _b.DOM.cE("div", {className:"as_corner"});
	var hbar = _b.DOM.cE("div", {className:"as_bar"});
	var header = _b.DOM.cE("div", {className:"as_header"});
	header.appendChild(hcorner);
	header.appendChild(hbar);
	div.appendChild(header);
  /* CREATES AND POPULATES THE UL */
	var ul = _b.DOM.cE("ul", {id:"as_ul"});
  /* LOOPS THROUGH arr SUGGESTIONS CREATING LI's FOREACH */
	for (var i=0;i<arr.length;i++) {
	  /* FORMATS OUTPUT WITHIN AN EM ELEMENT (as HTML, not DOM) */
		var val = arr[i].value;
		var st = val.toLowerCase().indexOf( this.sInp.toLowerCase() );
		var output = val.substring(0,st) + "<em>" + val.substring(st, st+this.sInp.length) + "</em>" + val.substring(st+this.sInp.length);
		var span 		= _b.DOM.cE("span", {}, output, true);
		var a 			= _b.DOM.cE("a", { href:"#" });
		var tl 		= _b.DOM.cE("span", {className:"tl"}, " ");
		var tr 		= _b.DOM.cE("span", {className:"tr"}, " ");
		a.appendChild(tl);
		a.appendChild(tr);
		a.appendChild(span);
		a.name = i+1;
		a.onclick = function () { pointer.setHighlightedValue(); return false; };
		a.onmouseover = function () { pointer.setHighlight(this.name); };
		var li = _b.DOM.cE(  "li", {}, a  );
		ul.appendChild( li );
	}
  /* NO RESULTS */
	if (arr.length == 0 && this.oP.shownoresults) {
		var li = _b.DOM.cE(  "li", {className:"as_warning"}, this.oP.noresults  );
		ul.appendChild( li );
	}
	div.appendChild( ul );	
	var fcorner = _b.DOM.cE("div", {className:"as_corner"});
	var fbar = _b.DOM.cE("div", {className:"as_bar"});
	var footer = _b.DOM.cE("div", {className:"as_footer"});
	footer.appendChild(fcorner);
	footer.appendChild(fbar);
	div.appendChild(footer);
  /**
	get position of target textfield
	position holding div below it
	set width of holding div to width of field
  */
	var pos = _b.DOM.getPos(this.fld);
	div.style.left 		= pos.x + "px";
	div.style.top 		= ( pos.y + this.fld.offsetHeight + this.oP.offsety ) + "px";
	div.style.width 	= this.fld.offsetWidth + "px";	
  /**
	set mouseover functions for div
	when mouse pointer leaves div, set a timeout to remove the list after an interval
	when mouse enters div, kill the timeout so the list won't be removed 
  */
	div.onmouseover 	= function(){ pointer.killTimeout() };
	div.onmouseout 		= function(){ pointer.resetTimeout() };
  /* ADDS DIV TO THE DOCUMENT */
	document.getElementsByTagName("body")[0].appendChild(div);
  /* WHEN NO ITEM IS HIGHLIGHTED */
	this.iHigh = 0;
  /* STOP LIST DISPLAY AFTER x TIME INVERVAL */
	var pointer = this;
	this.toID = setTimeout(function () { pointer.clearSuggestions() }, this.oP.timeout);
};
_b.AutoSuggest.prototype.changeHighlight = function(key) {	
	var list = _b.DOM.gE("as_ul");
	if (!list)
		return false;
	var n;
	if (key == 40)
		n = this.iHigh + 1;
	else if (key == 38)
		n = this.iHigh - 1;
	if (n > list.childNodes.length)
		n = list.childNodes.length;
	if (n < 1)
		n = 1;
	this.setHighlight(n);
};
_b.AutoSuggest.prototype.setHighlight = function(n) {
	var list = _b.DOM.gE("as_ul");
	if (!list)
		return false;
	if (this.iHigh > 0)
		this.clearHighlight();
	this.iHigh = Number(n);
	list.childNodes[this.iHigh-1].className = "as_highlight";
	this.killTimeout();
};
_b.AutoSuggest.prototype.clearHighlight = function() {
	var list = _b.DOM.gE("as_ul");
	if (!list)
		return false;
	if (this.iHigh > 0) {
		list.childNodes[this.iHigh-1].className = "";
		this.iHigh = 0;
	}
};
_b.AutoSuggest.prototype.setHighlightedValue = function () {
	if (this.iHigh) {
		this.sInp = this.fld.value = this.aSug[ this.iHigh-1 ].value;
	/* PUSHES CURSOR TO END AS SAFARI FIX */ 
		this.fld.focus();
		if (this.fld.selectionStart)
			this.fld.setSelectionRange(this.sInp.length, this.sInp.length);
		this.clearSuggestions();	
		/* PASS OBJECT TO CALLBACK IF EXISTS */
		if (typeof(this.oP.callback) == "function")
			this.oP.callback( this.aSug[this.iHigh-1] );
	}
};
_b.AutoSuggest.prototype.killTimeout = function() {
	clearTimeout(this.toID);
};
_b.AutoSuggest.prototype.resetTimeout = function() {
	clearTimeout(this.toID);
	var pointer = this;
	this.toID = setTimeout(function () { pointer.clearSuggestions() }, 1000);
};
_b.AutoSuggest.prototype.clearSuggestions = function () {
	this.killTimeout();
	var ele = _b.DOM.gE(this.idAs);
	var pointer = this;
	if (ele) {
		var fade = new _b.Fader(ele,1,0,250,function () { _b.DOM.remE(pointer.idAs) });
	}
};
// #### AJAXIAN PROTOTYPE
if (typeof(_b.Ajax) == "undefined")
	_b.Ajax = {};
_b.Ajax = function () {
	this.req = {};
	this.isIE = false;
};
_b.Ajax.prototype.makeRequest = function (url, meth, onComp, onErr) {
	if (meth != "POST")
		meth = "GET";
	this.onComplete = onComp;
	this.onError = onErr;
	var pointer = this;
  // ### HANDLES XMLHttpRequest
	if (window.XMLHttpRequest) {
		this.req = new XMLHttpRequest();
		this.req.onreadystatechange = function () { pointer.processReqChange() };
		this.req.open("GET", url, true); //
		this.req.send(null);
  // ### HANDLES IE/Windows ActiveX
	} else if (window.ActiveXObject) {
		this.req = new ActiveXObject("Microsoft.XMLHTTP");
		if (this.req) {
			this.req.onreadystatechange = function () { pointer.processReqChange() };
			this.req.open(meth, url, true);
			this.req.send();
		}
	}
};
_b.Ajax.prototype.processReqChange = function() {
  // ### IF STATUS LOADED
	if (this.req.readyState == 4) {
	  // IF STATUS OK
		if (this.req.status == 200) {
			this.onComplete( this.req );
		} else {
			this.onError( this.req.status );
		}
	}
};
// ### HANDLE FOR DOM PROTOTYPE
if (typeof(_b.DOM) == "undefined")
	_b.DOM = {};
/* CREATES DOM ELEMENT */
_b.DOM.cE = function ( type, attr, cont, html ) {
	var ne = document.createElement( type );
	if (!ne)
		return 0;
	for (var a in attr)
		ne[a] = attr[a];
	var t = typeof(cont);
	if (t == "string" && !html)
		ne.appendChild( document.createTextNode(cont) );
	else if (t == "string" && html)
		ne.innerHTML = cont;
	else if (t == "object")
		ne.appendChild( cont );
	return ne;
};
/* get element */
_b.DOM.gE = function ( e ) {
	var t=typeof(e);
	if (t == "undefined")
		return 0;
	else if (t == "string") {
		var re = document.getElementById( e );
		if (!re)
			return 0;
		else if (typeof(re.appendChild) != "undefined" )
			return re;
		else
			return 0;
	} else 
	  if (typeof(e.appendChild) != "undefined")
		return e;
	else
		return 0;
};
/* remove element */
_b.DOM.remE = function ( ele )
{
	var e = this.gE(ele);
	
	if (!e)
		return 0;
	else if (e.parentNode.removeChild(e))
		return true;
	else
		return 0;
};
/* get position */
_b.DOM.getPos = function ( e ) {
	var e = this.gE(e);
	var obj = e;
	var curleft = 0;
	if (obj.offsetParent) {
		while (obj.offsetParent) {
			curleft += obj.offsetLeft;
			obj = obj.offsetParent;
		}
	} else if (obj.x)
		curleft += obj.x;
	var obj = e;
	var curtop = 0;
	if (obj.offsetParent) {
		while (obj.offsetParent) {
			curtop += obj.offsetTop;
			obj = obj.offsetParent;
		}
	} else if (obj.y)
		curtop += obj.y;
	return {x:curleft, y:curtop};
};
// ### LIST FADER
if (typeof(_b.Fader) == "undefined")
	_b.Fader = {};
_b.Fader = function (ele, from, to, fadetime, callback) {
	if (!ele)
		return 0;
	this.e = ele;
	this.from = from;
	this.to = to;
	this.cb = callback;
	this.nDur = fadetime;
	this.nInt = 50;
	this.nTime = 0;
	var p = this;
	this.nID = setInterval(function() { p._fade() }, this.nInt);
};
_b.Fader.prototype._fade = function() {
	this.nTime += this.nInt;
	var ieop = Math.round( this._tween(this.nTime, this.from, this.to, this.nDur) * 100 );
	var op = ieop / 100;
	if (this.e.filters) {
	  // ### IE
		try {
			this.e.filters.item("DXImageTransform.Microsoft.Alpha").opacity = ieop;
		} catch (e) { 
			// If it is not set initially, the browser will throw an error.  This will set it if it is not set yet.
			this.e.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity='+ieop+')';
		}
	} else {
	  // ### OTHER BROWSERS
		this.e.style.opacity = op;
	}
	if (this.nTime == this.nDur) {
		clearInterval( this.nID );
		if (this.cb != undefined)
			this.cb();
	}
};
_b.Fader.prototype._tween = function(t,b,c,d) {
	return b + ( (c-b) * (t/d) );
};