/*
* info@fijiwebdesign.com 
* Generated: Wed, 08 Sep 2010 01:15:29 GMT
* Expires: Wed, 08 Sep 2010 02:15:29 GMT
*/

/**
* Fiji Web Design Common JS lib
* (c) http://www.fijiwebdesign.com
*/

/**
* Common lib obj
*/
function fwd_commonLib(log_id) {
    var ver = '0.1';
	this.included_files = [];
	this.log_id = (log_id ? log_id : 'fwd_error_log');
    return true;
};

/**
* General Log Function
*/
fwd_commonLib.prototype.logger = function(txt) {
	if (el = document.getElementById(this.log_id)) {
		el.value = txt+"\r\n"+el.value;
		
		// pop the last line off when over [this.maxlen] lines
		var arr = el.value.split("\r\n");
		if (arr.length > this.maxlen) {
			arr.pop();
			el.value = arr.concat("\r\n");
		}
	}
};

/**
* General Object Dump - only works for shallow objects
*/
fwd_commonLib.prototype.dump = function(obj, depth) {
	var txt = '';
	if (typeof(depth) == 'undefined') { 
		depth = 0;
	} else {
		txt += "\r\n";
		depth++;
	}
	if (typeof(obj) == 'object' || typeof(obj) == 'array') {
		for(var x in obj) {
			txt += "".pad(depth, "\t", 0);
			if (typeof(obj[x]) == 'object' || typeof(obj[x]) == 'array') {
				txt += x+': '+this.dump(obj[x], depth)+"\r\n";
			} else {
				txt += x+': '+obj[x]+"\r\n";
			}
		}
	}
	return txt;
};

/**
* Array pop method for older browsers
*/
if (typeof(Array.prototype.pop) == 'undefined') {
	Array.prototype.pop = function() {
		var response = this[this.length - 1];
		this.length--;
		return response;
	};
}

/**
* Add events
* @param string element name to attach event to
* @param string name of trigger
* @param string name of function to trigger
* @param bool capture event bubbling?
*/
fwd_commonLib.prototype.addEvent = function(el, evType, fn, useCapture, overWrite) {
	if (overWrite) el['on' + evType] = false;
	if (el.addEventListener) {
		el.addEventListener(evType, fn, useCapture);
		return true;
	}
	else if (el.attachEvent) {
		var r = el.attachEvent('on' + evType, fn);
		return r;
	}
	else {
		el['on' + evType] = fn;
	}
};

/**
* Get elements by Class Name
* @param string className
* @param string parent node to search within, otherwise the whole document is searched
* @param string name of tag to limit search to, otherwise all tags are returned
*/
fwd_commonLib.prototype.getElementsByClass = function(searchClass,node,tag) {
	var classElements = new Array();
	if (!node) node = document;
	if (!tag) tag = '*';
	var els = node.getElementsByTagName(tag);
	var elsLen = els.length;
	var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
	for (var i = 0, j = 0; i < elsLen; i++) {
		if ( pattern.test(els[i].className) || pattern.test(els[i].getAttribute('class')) ) {
			classElements[j] = els[i];
			j++;
		}
	}
	return classElements;
};

/**
* Toggle the original property of an element with a new property value
* @param object htmlElement or the htmlElement id
* @param string property/attribute name
* @param string property/attribute value
*/
fwd_commonLib.prototype.toggleProperty = function(obj, property, value) {
	var el = typeof(obj) == 'object' ? obj : this.el(obj);
	var orig_value = this.style(el)['orig_' + property];
	if ( !orig_value ) {
		this.style(el)['orig_' + property] = value;
        this.style(el)[property] = value;
	} else {
		this.style(el)[property] = orig_value;
		this.style(el)['orig_' + property] = null;
	}
};

/**
* Insert an element after and element the dom withought parent node reference
* @param string element object node to insert after
* @param string element object to insert
*/
fwd_commonLib.prototype.insertAfter = function(nPrevious, nInsert) {
    var nParent = nPrevious.parentNode;
    if (nPrevious.nextSibling) {
        nParent.insertBefore(nInsert, nPrevious.nextSibling);
    } else {
        nParent.appendChild(nInsert);
    }
};

/**
* Check if a value exists in the Array and returns the key if exists or -1 otherwise.
* @param string array value
*/
fwd_commonLib.prototype.in_array = function(value, arr) {
	for (var x in arr) { 
		if (arr[x] == value) {
           return x;
		}
	}
	return -1;
};

/**
* Get a cookie value
* @param string cookie name
*/
fwd_commonLib.prototype.getCookie = function( name ) {
	var start = document.cookie.indexOf( name + "=" );
	var len = start + name.length + 1;
	if ( ( !start ) && ( name != document.cookie.substring( 0, name.length ) ) ) {
		return null;
	}
	if ( start == -1 ) return null;
	var end = document.cookie.indexOf( ";", len );
	if ( end == -1 ) end = document.cookie.length;
	return unescape( document.cookie.substring( len, end ) );
};

/**
* Set a cookie
* @param string cookie name
* @param string cookie value
* @param string cookie expiration counter in days
* @param string cookie path
* @param string cookie domain
* @param bool secure?
*/
fwd_commonLib.prototype.setCookie = function( name, value, expires, path, domain, secure ) {
	var today = new Date();
	today.setTime( today.getTime() );
	if ( expires ) {
		expires = expires * 1000 * 60 * 60 * 24;
	}
	var expires_date = new Date( today.getTime() + (expires) );
	document.cookie = name+"="+escape( value ) +
		( ( expires ) ? ";expires="+expires_date.toGMTString() : "" ) +
		( ( path ) ? ";path=" + path : "" ) +
		( ( domain ) ? ";domain=" + domain : "" ) +
		( ( secure ) ? ";secure" : "" );
};

/**
* Remove a cookie
* @param string cookie name
* @param string cookie value
* @param string cookie path
* @param string cookie domain
*/
fwd_commonLib.prototype.deleteCookie = function( name, path, domain ) {
	if ( getCookie( name ) ) document.cookie = name + "=" +
			( ( path ) ? ";path=" + path : "") +
			( ( domain ) ? ";domain=" + domain : "" ) +
			";expires=Thu, 01-Jan-1970 00:00:01 GMT";
};

/**
* Return a list of elements objects by their id's
* @param string element id or list of element id's
* @note js is loosely typed, so a function can have any number of parameters/arguments
*/
fwd_commonLib.prototype.els = function() {
	var els = new Array();
	for (var i = 0; i < arguments.length; i++) {
		var id = arguments[i];
		if (typeof id == 'string') {
			el = this.el(id);
		} if (el.length == 1) {
			return el;
		}
		els.push(element);
	}
	return els;
};

/**
* Element to Object by Id.
* @param string element id
*/
fwd_commonLib.prototype.el = function(id) {
    if (document.getElementById) {
        return document.getElementById(id);
    } else if (document.all) {
        return document.all[id];
    } else if (document.layers) {
        return document.layers[id];
    } else {
        return false;
    }
};

/**
* HTML Element Style Property
* @param obj HTML Element
*/
fwd_commonLib.prototype.style = function(obj) {
    if (document.getElementById || document.all) {
        return obj.style;
    } else if (document.layers) {
        return obj;
    } else {
        return obj.style; // for now
    }
};

/**
* HTML Element Object Width and Height
* @param obj HTML Element
*/
fwd_commonLib.prototype.objDim = function(obj) {
	if (obj.offsetHeight) {
		this.h = obj.offsetHeight;
		this.w = obj.offsetWidth;
		this.mode = 'offsetHeight';
	} else if (obj.style && obj.style.pixelHeight) {
		this.h = obj.style.pixelHeight;
		this.w = obj.style.pixelWidth;
		this.mode = 'style.pixelHeight';
	} else if (obj.clip) {
		this.h = obj.clip.height;
		this.w = obj.clip.width;
		this.mode = 'clip';
	} else if (this.currStyle) {
		var c = new fwd_commonLib;
		this.h = c.currStyle(obj, 'height');
		this.w = c.currStyle(obj, 'width');
		c = null;
		this.mode = 'currStyle';
	} 
};

/**
* Window width and height
* @param bool account for horizontal scroll
* @param bool account for vertical scroll
*/
fwd_commonLib.prototype.winDim = function(scrollX, scrollY, parent) {
	var win = parent ? parent.window : window;
	var doc = parent ? parent.document : document;
	this.w = 0;
	this.h = 0;
	if (doc.documentElement && doc.documentElement.clientWidth) { /* FF/IE quirks mode */
		this.w = doc.documentElement.clientWidth;
		this.h = doc.documentElement.clientHeight;
	} else if (win && win.innerWidth) { /* NN/other */
		this.w = (scrollX) ? win.innerWidth - scrollX : win.innerWidth;
		this.h = (scrollY) ? win.innerHeight - scrollY : win.innerHeight;
	} else { /* IE non-quirks mode */
		var c = new fwd_commonLib();
		var Dim = new c.bodyDim();
		this.w = Dim.w;
		this.h = Dim.h;
		c = null;
	}
};

/**
* Document Body width and height
* @param bool account for horizontal scroll
* @param bool account for vertical scroll
*/
fwd_commonLib.prototype.bodyDim = function(scrollX, scrollY, parent) {
	var doc = parent ? parent.document : document;
	this.w = 0;
	this.h = 0;
	if (doc.body && doc.body.clientWidth) {
		this.w = (scrollX) ? doc.body.clientWidth - scrollX : doc.body.clientWidth;
		this.h = (scrollY) ? doc.body.clientHeight - scrollY : doc.body.clientHeight;
	} else if (doc.body && doc.body.offsetWidth) {
		this.w = (scrollX) ? doc.body.offsetWidth - scrollX : doc.body.offsetWidth;
		this.h = (scrollY) ? doc.body.offsetHeight - scrollY: doc.body.offsetHeight;
	}
};

/**
* Objects Style Attribute value through Current Style applied by the document
* @param obj HTML Element
* @param string HTML Element Style Attribute
*/
fwd_commonLib.prototype.currStyle = function(obj, attribute) {
	if (obj.currentStyle) {
		return obj.currentStyle[attribute];
	} else if (window.getComputedStyle) {
		return document.defaultView.getComputedStyle(obj,null).getPropertyValue(attribute);
	}
};

/**
* HTML Elements top and left offset relative to the docuemnt
* @param object htmlElement
*/
fwd_commonLib.prototype.xyOffset = function(obj){
	this.x = 0;
	this.y = 0;
	this.levels = 0;
	if (obj.offsetParent) {
		while (obj.offsetParent) {
			this.x += parseInt(obj.offsetLeft);
			this.y += parseInt(obj.offsetTop);
			obj = obj.offsetParent;
			this.levels++;
		}
	} else if (obj.x) {
		this.x += obj.x;
		this.y += obj.y;
	}
};

/**
* Current x/y scroll offset of the window
*/
fwd_commonLib.prototype.winScroll = function(parent) {
	this.x = 0;
	this.y = 0;
	var doc = parent ? parent.document : document;
	var win = parent ? parent.window : window;
	
	if (doc.documentElement && doc.documentElement.scrollTop) {
		this.y = doc.documentElement.scrollTop; 
		this.x = doc.documentElement.scrollLeft; 
	} else if (doc.body) {
		  this.y =  doc.body.scrollTop; 
		  this.x = doc.body.scrollLeft; 
	} else if (win.innerHeight) {
		  this.y = win.pageYOffset; 
		  this.x = win.pageYOffset; 
	}
};

/**
* Image Preloading, takes any number of arguments
* @params string img src
*/
fwd_commonLib.prototype.preloadimages = function(){
    var imgs = new Array();
    var n = arguments.length;
	for (i = 0; i < n; i++){
    	imgs[i] = new Image();
    	imgs[i].src = arguments[i];
	}
	return imgs;
};

/**
* General Form Validation
* attachment of a method called js_valid to a form element to validate it on form submit
* @param object form element
*/
fwd_commonLib.prototype.js_validate = function(form, method) {
	if (!method) { method = 'js_valid'; }
	var els = form.elements;
	var n = els.length;
	for(var i = 0; i < n; i++) {
		var el = els[i];
		if (el[method]) {
			if (!el[method](el)) {
				return false;
			}
		}
	}
	return true;
};

/**
* Dynamic Loading of JavaScript
*/
fwd_commonLib.prototype.include_js = function(script_filename) {
	if (document.getElementsByTagName) {
		var html_doc = document.getElementsByTagName('head').item(0);
		var js = document.createElement('script');
		js.setAttribute('language', 'javascript');
		js.setAttribute('type', 'text/javascript');
		js.setAttribute('src', script_filename);
		html_doc.appendChild(js);
    	return true;
	}
	return false;
};

/**
* check if a file has already been loaded before loading
*/
fwd_commonLib.prototype.include_js_once = function(script_filename) {
    if (this.in_array(script_filename, this.included_files) == -1) {
        this.included_files[this.included_files.length] = script_filename;
        return this.include_js(script_filename);
    }
	return false;
};

/**************************************
 Jonas Raoni Soares Silva
 http://www.joninhas.ath.cx
**************************************/
/**
* Pads a string to a specific length
* @param int length of string
* @param string padding
* @param int type of padding (0: left, 1: right, 2: both sides)
*/
String.prototype.pad = function(l, s, t){
	return s || (s = " "), (l -= this.length) > 0 ? (s = new Array(Math.ceil(l / s.length)
		+ 1).join(s)).substr(0, t = !t ? l : t == 1 ? 0 : Math.ceil(l / 2))
		+ this + s.substr(0, l - t) : this;
};

/**
* Creates new Event
* Example Usage: 
*	var Evt = new fwd_commonLib('id').Event();
*	Evt.attachEventListerner(function() { alert('hi im the listerner'); });
*	Evt.fireEventListerners();												
*/
fwd_commonLib.Event = function(name) {
	// private event handlers
	var _handlers = []; 
	return {
		// event name
		name: name,
		/** 
		* Attach Event Handlers
		* @param Function The function to run when event is triggered
		*/
		attachEventListerner: function(fn) {
			_handlers.push(fn);
		},
		
		/** 
		* Fire event Handlers
		*/
		fireEventListerners: function() {
			var n = _handlers.length;
			for (var i = 0; i < n; i++) {
				if (_handlers.hasOwnProperty(i)) {
					try {
						(_handlers[i])(arguments);
					} catch(e) {
						/* ignore */
					}
				}
			}
		}
	}
};



/**
* Fiji Web Design AJAX lib
* @copyright (c) http://www.fijiwebdesign.com
* @email fwd_ajax.class@fijiwebdesign.com
* @package Testing 
*/

fwd_XHR = function() {
	ver = '0.5';
	this.xmlhttp = this.createXMLHTTPRequest();
};

// static global properties
fwd_XHR._XMLHTTP_VER = false; // MSIE
fwd_XHR.ERR_NO_XMLHTTP = 'Your Browser does not support XMLHttpRequest!';
fwd_XHR.XML_HTTP_SUPORT_NATIVE = 'XMLHttpRequest Support: Native';
fwd_XHR.XML_HTTP_SUPORT_ACTIVEX = 'XMLHttpRequest Support: ';
fwd_XHR.ERR_CALLBACK = 'xmlHTTPRequest Callback Exception: ';
fwd_XHR.RESP_STATUS = 'Response Status: ';
fwd_XHR.RESP_STATE = 'Response State: ';
fwd_XHR.CACHED = 'Version Number Cached';

// dynamic properties
fwd_XHR.prototype.url; // url of request
fwd_XHR.prototype.method; // request method (GET, POST, HEAD)
fwd_XHR.prototype.callback; // callback function
fwd_XHR.prototype.data; // data to send in HTTP Request
fwd_XHR.prototype.async; // perform HTTP Request Asynchronous or not
fwd_XHR.prototype.user; // domain username (BasicAuth)
fwd_XHR.prototype.pass; // domain password

/**
* Get a Reference to the xmlHTTPRequest Object
*/
fwd_XHR.prototype.createXMLHTTPRequest = function() {
	if (window.XMLHttpRequest) {
		fwd_XHR.logger(fwd_XHR.XML_HTTP_SUPORT_NATIVE);
		return (new XMLHttpRequest());
    } else if (window.ActiveXObject) {
		// check cached msxml version
		if (fwd_XHR._XMLHTTP_VER) {
			fwd_XHR.logger(fwd_XHR._XMLHTTP_VER + ' ('+fwd_XHR.CACHED+')');
			return (new ActiveXObject(fwd_XHR._XMLHTTP_VER));	
		}
		// find latest XMLHTTP implementation on IE
		var versions = [
		"Msxml2.XMLHTTP.7.0", 
		"Msxml2.XMLHTTP.6.0", 
		"Msxml2.XMLHTTP.5.0", 
		"Msxml2.XMLHTTP.4.0", 
		"MSXML2.XMLHTTP.3.0", 
		"MSXML2.XMLHTTP",
		"Microsoft.XMLHTTP"];
		var n = versions.length;
		for (var i = 0; i <  n; i++) {
			try {
				fwd_XHR._XMLHTTP_VER = versions[i];
				if (new ActiveXObject(fwd_XHR._XMLHTTP_VER)) {
					fwd_XHR.logger(fwd_XHR.XML_HTTP_SUPORT_ACTIVEX+fwd_XHR._XMLHTTP_VER);
					return (new ActiveXObject(fwd_XHR._XMLHTTP_VER));
				}
			} catch (e) {
				fwd_XHR._XMLHTTP_VER = false;
			}
		}
		fwd_XHR.noXHRSupport();
    }
	return false;
};

/**
* A HTTP GET
*/
fwd_XHR.prototype.get = function(url, callback, async, user, pass) {
	return this.request(url, 'GET', callback, null, async, user, pass);
};

/**
* A HTTP POST
*/
fwd_XHR.prototype.post = function(url, callback, async, user, pass) {
	return this.request(url, 'POST', callback, null, async, user, pass);
};


/**
* Makes an xmlHTTPRequest ready for sending
*/
fwd_XHR.prototype.request = function(url, method, callback, data, async, user, pass) {
	
	var self = this;
	this.url = url;
	this.method = method;
	this.callback = callback;
	this.data = data;
	this.async = async;
	this.user = user;
	this.pass = pass;
	
	async = (typeof(async) != 'undefined' && !async) ? false : true;
	method = method.toUpperCase();
	
	this.xmlhttp.onreadystatechange = function() {
		try {
			callback(self);
			if (self.xmlhttp.readyState == 4) {
				self = null; // remove closure
			}
		} catch(e) { 
			fwd_XHR.logger(fwd_XHR.ERR_CALLBACK+e);
		}
	}
	
	this.xmlhttp.open(method, url, async, user, pass);
	if (method == 'POST') {
		this.setPostHeaders('1.1');
	}
	
	return this.xmlhttp;
};

/**
* Set HTTP POST Headers / URL-ENCODED
*/
fwd_XHR.prototype.setPostHeaders = function(http_ver) {
	http_ver = http_ver ? 'HTTP/'+http_ver : 'HTTP/1.1';
	this.xmlhttp.setRequestHeader("Method", "POST "+this.url+" "+http_ver);
    this.xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	return this.xmlhttp;
};

/**
* Execute the JSON text
*/
fwd_XHR.prototype.execJSON = function() {
	if (this.readyState()) { //alert(this.xmlhttp.responseText);
		return eval('('+this.xmlhttp.responseText+')');
	}
};

/**
* Check readystate and status
*/
fwd_XHR.prototype.readyState = function(readyState, status) {
	readyState = readyState || 4;
	status = status || 200;
	var xmlhttp = this.xmlhttp;
	if (xmlhttp.readyState == readyState) {
		//fwd_XHR.logger(fwd_XHR.RESP_STATUS+xmlhttp.status);
		//fwd_XHR.logger(fwd_XHR.RESP_STATE+xmlhttp.readyState);
		if (xmlhttp.status == status) {
			return true;
		} else {
			try {
				this.statusError(xmlhttp.status);
			} catch(e) { /* no status error set */ }
		}
	}
};

/**
* encode passed http vars
*/
fwd_XHR.prototype.encode = function(uri) {
    if (encodeURIComponent) {
        return encodeURIComponent(uri);
    }
    if (escape) {
        return escape(uri);
    }
};

/**
* dencode passed http vars
*/
fwd_XHR.prototype.decode = function(uri) {
    uri = uri.replace(/\+/g, ' ');

    if (decodeURIComponent) {
        return decodeURIComponent(uri);
    }
    if (unescape) {
        return unescape(uri);
    }
    return uri;
};

/** static function */

/**
* Set the id of the element to write logs to
*/
fwd_XHR.setLogger = function(id) {
	fwd_XHR.log_id = id;
};

/**
* Simple Logging utility
*/
fwd_XHR.logger = function(txt) {
	if (!fwd_XHR.log_id) return;
	var logger = document.getElementById(fwd_XHR.log_id);
	if (logger) {
		logger.value = txt  + "\r\n" + logger.value;
	}
};

/**
* Function to run when a browser does not support XHR
*/
fwd_XHR.noXHRSupport = function() {
	alert(fwd_XHR.ERR_NO_XMLHTTP);
};

/**
 * Tag Component JS Lib
 * @author gabe@fijiwebdesign.com
 * @copyright (c) fijiwebdesign.com
 * @license http://www.fijiwebdesign.com/
 * @dependancy fwd_XHR
 */
fwd_Tag = function(cid) {
	// allow us to have a single global namespace
	// http://fijiwebdesign.com/content/view/97/77/
	if (this instanceof fwd_Tag) {
		this.cid = cid;
		fwd_Tag.i[cid] = this;
	} else {
		return fwd_Tag.i[cid] || new fwd_Tag(cid);
	}
};

/**
* Static Methods and Properties
*/
fwd_Tag.i = {}; // instances
fwd_Tag.sep= ', '; // tags seperator regex
fwd_Tag.sep_pattern = /\s*,\s*/; // tags seperator regex

/**
* Extend the prototype with the methods in obj
* Note: This overwrites any existing prototypes with the same index
*/
fwd_Tag.extendProto = function(obj) {
	for(var x in obj) {
		if (obj.hasOwnProperty(x)) {
			fwd_Tag.prototype[x] = obj[x];
		}
	}
},

/**
* Prototype Methods
*/
fwd_Tag.prototype = {
	
	/**
	* Controls adding of tags to UI and Backend
	*/
	addTags: function(cid) {
		if (!fwd_Tag.config.user_id) {
			alert('Sorry, You have to log in to add tags');
			return;
		}
		this.ui.getTagsFromUser(cid);
	},
	
	// user interface
	ui: {
		/**
		* Shows the Input UI for adding Tags
		*/
		getTagsFromUser: function(cid) {
			
			// fire the event listerner for this method
			fwd_Tag.on.getTagsFromUser.fireEventListerners(cid);
			
			var tagForm = document.getElementById('tagform_'+cid);
			if (tagForm.childNodes && tagForm.childNodes.length > 1) {
				if (tagForm.style.display == 'block') {
					tagForm.style.display = 'none';	
				} else {
					tagForm.style.display = 'block';
				}
			} else {
				var input = document.createElement('input');
				input.id = 'tag_input_'+cid;
				input.name = 'tags';
				input.className = 'inputbox';
				// listen for enter key
				input.onkeypress = function(e) {
					e = (!e) ? window.event : e;
					if (e.keyCode == 13) {
						btn.onclick();	
					}
				};
				var btn = document.createElement('input');
				btn.type = 'button';
				btn.value = fwd_Tag.config.add_btn_txt ? fwd_Tag.config.add_btn_txt : 'Save';
				btn.id = 'tag_add_btn_'+cid;
				btn.className = 'button';
				// listen for btn click
				btn.onclick = function() {
					var cid = this.id.replace('tag_add_btn_', '');
					var input = document.getElementById('tag_input_'+cid);
					var tags = input.value;
					input.value = '';
					var tagForm = document.getElementById('tagform_'+cid);
					tagForm.style.display = 'none';
					fwd_Tag(cid).ui.handleTagsFromUser(cid, tags);
				};
				tagForm.appendChild(input);
				tagForm.appendChild(btn);
				tagForm.style.display = 'block';
				input.focus();
			}
		},
		/**
		* Handle the tags added by user
		*/
		handleTagsFromUser: function(cid, tags) {
			if (tags) {
				tags = tags.split(fwd_Tag.sep_pattern); // 4now
				fwd_Tag(cid).ui.addTags(tags, cid); // add ui instantly, remove if ss fails
				fwd_Tag(cid).ss.saveTags(tags, cid);
			}
		},
		/**
		* Adds the Tags to the UI
		*/
		addTags: function(tags, cid) {
			var tagList = document.getElementById('taglist_'+cid);
			if (tagList) {
				var sep = '';
				var addTagBtn = tagList.lastChild;
				var nodeName = tagList.childNodes[0].nodeName;
				if (tagList.childNodes.length > 1) {
					sep = fwd_Tag.sep;
				}
				for(var i = 0; i < tags.length; i++) {
					// create Nodes to add to 
					var tagEl = document.createElement(nodeName);
					var tagLink = document.createElement('a');
					var tagTxt = document.createTextNode(tags[i]);
					var sepEl = document.createElement('span');
					var sepTxt = document.createTextNode(sep);
					sepEl.appendChild(sepTxt);
					tagEl.appendChild(sepEl);
					tagLink.appendChild(tagTxt);
					tagLink.href = 'index.php?option=com_tag&tag='+tags[i];
					tagEl.appendChild(tagLink);					
					tagList.insertBefore(tagEl, addTagBtn);
					sep = fwd_Tag.sep;
				}
			} else {
				alert('no taglist:  taglist_'+this.cid);	
			}
		},
		/**
		* Removes Tags from the UI
		*/
		removeTags: function(cid, tags) {
			var tagList = document.getElementById('taglist_'+cid);
			if (tagList) {
				var items = tagList.getElementsByTagName('li');
				for(var i = 0; i < tags.length; i++) {
					// remove DOM Nodes
					for(var j = 0; j < items.length; j++) {
						// remove DOM Nodes
						var tagLink = items[j].getElementsByTagName('a')[0];
						if (tagLink) {
							if (tagLink.innerHTML == tags[i]) {
								tagList.removeChild(items[j]);
								break;
							}
						}
					}				
				}
			} else {
				alert('no taglist:  taglist_'+this.cid);	
			}
		}
	},
	
	// sever side
	ss: {
	
		/**
		* Makes an XMLHTTPRequest to the server, posting the tags to add
		*/
		saveTags: function(tags, cid) {
			var xhr = new fwd_XHR();
			var data = 'option=com_tag&task=author&act=add&cid='+cid+'&tags='+xhr.encode(tags)+'&f=json&no_html=1';
			if (xhr) {
				var url = 'index2.php';
				xhr.cid = cid;
				xhr.tags = tags;
				xhr.post(url, fwd_Tag(cid).ss.handle_saveTags).send(data);
				return true;
			} else {
				var url = 'index.php';
				window.location = url+'?'+data;	
			}
		},
		/**
		* Handles the Response from the Server when adding tags
		*/
		handle_saveTags: function(xhr) {
			if (xhr.xmlhttp.readyState == 4) {
				if (xhr.xmlhttp.status == 200) {
					var ui = fwd_Tag(xhr.cid).ui;
					var resp;
					try {
						resp = xhr.execJSON();
						if (resp.cid != xhr.cid) {
							ui.removeTags(xhr.cid, xhr.tags);
							if (resp.err_msg) {
								alert(resp.err_msg);
							} else {
								alert('An error occurred. Your Tags Could not be saved');
							}
						}
					} catch(e) { /* Invalid JSON */ }
					if (!resp) {
						ui.removeTags(xhr.cid, xhr.tags);
						alert('An Invalid Response occurred. Your Tags Could not be saved');	
					} else {
						// 
					}
				} else {
					alert('An HTTP Error occurred');
				}
			}
		}
	
	}
};

/** 
* Add Events to the existing UI methods
*/
fwd_Tag.on = {};
for (var x in fwd_Tag.prototype.ui) {
	// instantiate new Event Object
	fwd_Tag.on[x] = new fwd_commonLib.Event(x);
	/**
	* todo: fix problem with arguments passing
	fwd_Tag.on[x].attachEventListerner(
		(function() {
			var name = x;
			return function() {
				alert(name);
			}
		})()
	);
	(function() {
		//var x = x;
		var Event = fwd_Tag.on[x];
		var old = fwd_Tag.prototype.ui[x];
		fwd_Tag.prototype.ui[x] = function() {
			alert(x+' event fired with args: '+arguments);
			Event.fireEventListerners(arguments);
			//old(arguments);
		}
	})();
	*/
}

fwd_Tag.config = {"add_btn_txt":"Save","add_link_txt":"Add Tags","tags_sep":", ","default_act":"cloud","cloud_tags_limit":120,"user_id":0,"Itemid":0,"live_site":"http:\/\/www.opening.com.tw"};

/**
 * Tag Component JS Lib
 * @author gabe@fijiwebdesign.com
 * @copyright (c) fijiwebdesign.com
 * @license http://www.fijiwebdesign.com/
 * @dependancy fwd_XHR
 */

/**
* Tag Cloud Tooltip Functions
* Retrieves tag clouds (related tags) for a tag, caches, and displays as tooltip
*/
fwd_Tag.prototype.reltags = ({
							 
	/**
	* Static Properties
	*/
	timeout: [],
	
	/**
	* Adds the event handlers
	*/
	addEventHandlers: function() {
		var el = document.getElementById('com_tag_cloud');
		if (!el) {
			return false;	
		}
		var taglinks = el.getElementsByTagName('a');
		for(var i = taglinks.length-1; i >= 0 ; i--) {
			var taglink = taglinks[i];
			taglink.onmouseover = function(e) {
				var tag = this.firstChild.innerHTML;
				fwd_Tag('rel').reltags.ui.handleMouseOver(tag, e);
			};
			taglink.onmouseout = function(e) {
				var tag = this.firstChild.innerHTML;
				fwd_Tag('rel').reltags.ui.handleMouseOut(tag, e);
			};
		}
	},
	/**
	* Server Side functions
	*/
	ss: {
		getTagCloud: function(tag) {
			var xhr = new fwd_XHR();
			var data = 'option=com_tag&task=view&act=tagged&tag='+tag+'&f=xhtml&no_html=1&Itemid='+fwd_Tag.config.Itemid+'&limit=10';
			if (xhr) {
				var url = 'index2.php';
				xhr.tag = tag;
				xhr.post(url, fwd_Tag('rel').reltags.ss.handleTagCloud).send(data);
				return true;
			} else {
				var url = 'index.php';
				window.location = url+'?'+data;	
			}
		},
		handleTagCloud: function(xhr) {
			if (xhr.xmlhttp.readyState == 4) {
				if (xhr.xmlhttp.status == 200) {
					var resp = xhr.xmlhttp.responseText;
					fwd_Tag('rel').reltags.ui.saveToCache(xhr.tag, resp);
					fwd_Tag('rel').reltags.ui.displayRelTags(resp);
				} else {
					alert('An HTTP Error occurred');
				}
			}
		}
	},
	/**
	* User Interface functions
	*/
	ui: {
		cache: {},
		saveToCache: function(id, value) {
			fwd_Tag('rel').reltags.ui.cache[id] = value;
		},
		getFromCache: function(id) {
			return fwd_Tag('rel').reltags.ui.cache[id];
		},
		handleMouseOver: function(tag, e) {
			clearTimeout(fwd_Tag('rel').reltags.timeout['ui.remove']);
			fwd_Tag('rel').reltags.ui.displayTooltip(e);
			var str_cloud = fwd_Tag('rel').reltags.ui.getFromCache(tag);
			if (str_cloud) {
				fwd_Tag('rel').reltags.ui.displayRelTags(str_cloud);
			} else {
				(function(tag) {
					fwd_Tag('rel').reltags.timeout['ss.get'] = setTimeout(
						function() {
							fwd_Tag('rel').reltags.ss.getTagCloud(tag);
						}, 500
					);
				})(tag);
			}
		},
		handleMouseOut: function(tag, e) {
				clearTimeout(fwd_Tag('rel').reltags.timeout['ss.get']);
				fwd_Tag('rel').reltags.ui.setRemoveTooltipTimer();
		},
		displayTooltip: function(e) {
			fwd_Tag('rel').reltags.ui.removeTooltip();
			var el = document.createElement('div');
			el.id = 'rel_tooltip';
			el.style.position = 'absolute';
			el.style.display = 'block';
			//el.style.backgroundColor = '#fff';
			el.style.width = '250px';
			el.style.height = 'auto';
			var pos = fwd_Tag('rel').reltags.ui.getMousePos(e);
			el.style.left = pos.x+'px';
			el.style.top = pos.y+'px';
			el.onmouseover = function() {
				clearTimeout(fwd_Tag('rel').reltags.timeout['ui.remove']);
			};
			el.onmouseout = function() {
				fwd_Tag('rel').reltags.ui.setRemoveTooltipTimer();
			};
			el.innerHTML = '<b>loading...</b>';
			document.body.appendChild(el);
		},
		setRemoveTooltipTimer: function() {
			fwd_Tag('rel').reltags.timeout['ui.remove'] = setTimeout(
				function() {
					fwd_Tag('rel').reltags.ui.removeTooltip();
				}, 500
			);
		},
		removeTooltip: function() {
			var el = document.getElementById('rel_tooltip');
			if (el) {
				document.body.removeChild(el);
			}
		},
		displayRelTags: function(str) {
			var el = document.getElementById('rel_tooltip');
			if (el) {
				el.innerHTML = str;	
			}
		},
		getMousePos: function(e) {
			var x = 0;
			var y = 0;
			if (!e) var e = window.event;
			if (e.pageX || e.pageY) {
				x = e.pageX;
				y = e.pageY;
			} else if (e.clientX || e.clientY) 	{
				x = e.clientX + document.body.scrollLeft
					+ document.documentElement.scrollLeft;
				y = e.clientY + document.body.scrollTop
					+ document.documentElement.scrollTop;
			}
			return {x:x, y:y};
		}
	}
});

/* 
* Inherit commonLib prototype
*/
fwd_Tag.extendProto(
	fwd_commonLib.prototype
);
// add event handlers when window loads
fwd_Tag('rel').addEvent(window, 'load', 
	function() {
		fwd_Tag('rel').reltags.addEventHandlers();
		// add event handler to sanitize user input
		fwd_Tag.on.getTagsFromUser.attachEventListerner(
			function(args) {
				var cid = args[0];
				//alert(cid);
			}
		);
																 
	}
);
						   
						   
