var lf = {
	
	version: 1.1,
	
	/**
	 * Reploads an array of image urls
	 *
	 * @param array imageUrls
	 */
	preloadImages: function(imageUrls) {
		var p = new Image();
		imageUrls.each(function(url) {
			p.src = url;
		});
	},
	
	/**
	 * Little hack to get PNG's transprent in IE 6
	 */
	correctIePngs: function() {
		var rslt = navigator.appVersion.match(/MSIE (\d+\.\d+)/, '');
		var itsAllGood = (rslt !== null && Number(rslt[1]) >= 5.5);
		for (var i = document.images.length - 1, img = null; (img = document.images[i]); i--) {
			if (itsAllGood && img.src.match(/\.png$/i) !== null) {
				var src = img.src;
				var div = document.createElement("DIV");
				div.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + src + "', sizing='scale')";
				div.style.width = img.width + "px";
				div.style.height = img.height + "px";
				img.replaceNode(div);
			}
			img.style.visibility = "visible";
		}
	},
	
	/*
	 * Basic alert, override this to get alerts to do fancier things, like popup divs
	 *
	 * @param string text
	 */
	alert: function(text) {
		alert(text);
	},
	
	/**
	 * returns you a timestamp
	 *
	 * @returns float
	 */
	timestamp: function() {
		var d = new Date();
		return d.getMilliseconds();
	},
	
	/**
	 * returns or gives you the html to display a nice progress bar
	 *
	 *	arguments = array (
			barStyle - int - [1,2]
			element - string or boject - element to fill with progress content
	 )
	 *
	 * @param array args
	 *
	 * @returns string
	 */
	progressBarDiv: function(args) {
		
		//set any defaults propties for args
		args = this.defaultObjectProperties(args,{
			style: 		1,
			element: 	false
		});
		
		var image = '';
		switch(args.style) {
			case 0:
				break;
			case 2:
				image = 'progress_main.gif';
				break;
			case 3:
				break;
			case 4:
				break;
			default:
				image = 'progress.gif';
				break;
		}
		
		var image		= (image) ? "<img src='/images/" + image + "' />" : '';
		var progress 	= "<div class='wrapper-progress-bar'>" + image + "</div>";
		
		if(args.element) {
			lf.element.get(args.element).innerHTML = progress;
		}
		
		return progress;
	},
	
	/**
	 * used to setup the default properties on any object
	 * which is helpfull when you are passing an object to a method
	 * and you need some default values
	 *
	 * the first object will have all properties the second object does
	 * by the time it is returned
	 *
	 * @param object obj
	 * @param object args - essentially an assoc array with the propeties you want the first object to have
	 *
	 * @returns object
	 */
	defaultObjectProperties: function(obj, args) {
		
		//if obj is not an object, make it one
		if(!this.isObject(obj)) {
			obj = {};
		}
		
		for(var prop in args) {
			if(this.isUndefined(obj[prop])) {
				obj[prop] = args[prop];
			}
		}
		
		return obj;
		
	},
	
	/**
	 * used with firebug, outputs a string to the console (works in safari as well)
	 *
	 * @param string string
	 */
	trace:function(string) {
		if(console && console.log) {
			console.log(string);
		}
	},
	
	/**
	 * Convenience method to mimic the functionality of foreach in php
	 *
	 * @param array arr - array or object you are passing
	 * @param function fnc - the function that is called each iteration, it must accept an arg that is the value of the current iteration
	 * @param scop object - option - if instance of object, the function will be called from this scope
	 */
	foreach:function(arr, fnc, scope) {
		if(lf.isArray(arr)) {
			for(var c=0;c<arr.length;c++) {
				if(scope) {
					fnc.call(scope, arr[c]);
				} else {
					fnc(arr[c]);
				}
			}
		} else if(arr) {
			for(var prop in arr) {
				if(scope) {
					fnc.call(scope, arr[prop]);
				} else {
					fnc(arr[prop]);
				}
			}
		}
	},
	
	/**
	 * Basic async request (ajax)
	 *
	 * @param string url - the url to post/get to
	 * @param object callback - callback.success is called when the call is done, it can accept the xmlhttprequest object
	 * @param string postData - additional query string of information to be submitted as well
	 * @param string method - "GET" || "POST" (default is POST)
	 */
	asyncRequest: function(url, callback, postData, method) {
		return YAHOO.util.Connect.asyncRequest(method || "POST", url, callback || {}, postData || '');
	},
	
	/**
	 * creates a query string from the passed form and then calls asyncrequest
	 * @param string url - where to post the form to
	 * @param domelement form - the form you want to submit
	 * @param object callback - any function that will accept the xmlhttprequest object.
	 * @param string method - "GET" || "POST" (default is same as asynRequest)
	 */
	submitForm:function(url, form, callback, method) {
		YAHOO.util.Connect.setForm(form);
		callback.form = form;
		this.asyncRequest(url,callback,'',method);
	},
	
	/**
	 * Takes any form and creates a query string of data from it
	 *
	 * @param domelement form - the form you want the data from
	 *
	 * @returns string
	 */
	getFormQueryString: function(form) {
		var queryString = YAHOO.util.Connect.setForm(form);
		YAHOO.util.Connect.resetFormState();
		
		return queryString;
	},
	
	/**
	 * Updates the contents of a div with the results of a call
	 *
	 * @param string or object - reference to the element that will be populated
	 * @param string url - url that is going to be called
	 * @param object callbackFunction - callback.success is called when everything is done
	 * @param string method - "POST" || "GET" (default POST)
	 */
	asyncUpdate: function(container, url, callbackFunction, postData, method) {
	
		var thisCallback = {
			callback: 	callbackFunction,
			container:	container,
			success: 	function(r) {
								
				lf.element.get(this.container).innerHTML = r.responseText;
				
				if(this.callback) {
					var scope = this.callback.scope;
					if(scope) {
						this.callback.success.call(scope,r);
					} else {
						this.callback.success(r);
					}
				}
			}
		};
		
		this.asyncRequest(url,thisCallback,postData,method);
	},
	
	isArray: function(obj) {
		return YAHOO.lang.isArray(obj);
	},
	
	isObject: function(obj) {
		return YAHOO.lang.isObject(obj);	
	},
	
	isBoolean: function(obj) {
		return YAHOO.lang.isBoolean(obj);
	},
	
	isUndefined: function(obj) {
		return YAHOO.lang.isUndefined(obj);
	},
	
	isString: function(obj) {
		return YAHOO.lang.isString(obj);	
	},
	
	/**
	 * fills a string that has {{key}} with all the values passed
	 *
	 * @param string string
	 * @param object values - an object where the keys are mapped to the keys in the template
	 *
	 * @return string
	 */
	populateTemplate: function(string, values) {
		for(var prop in values) {
			if(values.prop) {
				string.replace('{{'+prop+'}}', values.prop);
			}
		}
		
		return string;
	},
	
	/**
	 * returns a valid xml object regardless of browser
	 *
	 * @return object
	 */
	xmlParser: function(xml) {
	
		//log courtesy: http://www.w3schools.com/Xml/tryit.asp?filename=tryxml_parsertest2
		var xmlDoc = false;
		
		if(typeof ActiveXObject != "undefined") {
			xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
			xmlDoc.async="false";
			
			if(xml) {
				xmlDoc.loadXML(xml);
			}
			
			return xmlDoc;
		}
		
		var parser = new DOMParser();
		
		if(xml) {
			xmlDoc = parser.parseFromString(xml,"text/xml");
		}
		
		return xmlDoc;
		
	},
	
	formatCurrency: function(amount) {
		
		var i = parseFloat(amount);
		if(isNaN(i)) { i = 0.00; }
		var minus = '';
		if(i < 0) { minus = '-'; }
		i = Math.abs(i);
		i = parseInt((i + 0.005) * 100,10);
		i = i / 100;
		s = String(i);
		if(s.indexOf('.') < 0) { s += '.00'; }
		if(s.indexOf('.') == (s.length - 2)) { s += '0'; }
		s = minus + s;
	
		return this.formatComma(s);
	
	},
	    
	formatComma: function(amount) {
		var delimiter = ","; // replace comma if desired
		var a = amount.split('.',2);
		var d = a[1];
		var i = parseInt(a[0],10);
		if(isNaN(i)) { return ''; }
		var minus = '';
		if(i < 0) { minus = '-'; }
		i = Math.abs(i);
		var n = String(i);
		a = [];
		while(n.length > 3)
		{
			var nn = n.substr(n.length-3);
			a.unshift(nn);
			n = n.substr(0,n.length-3);
		}
		if(n.length > 0) { a.unshift(n); }
		n = a.join(delimiter);
		if(d.length < 1) { amount = n; }
		else { amount = n + '.' + d; }
		amount = minus + amount;
		return amount;
	},
	
	fireEvent: function(element,event){
		if (document.createEventObject){
			// dispatch for IE
			var evt = document.createEventObject();
			return element.fireEvent('on'+event,evt)
		}
		else{
			// dispatch for firefox + others
			var evt = document.createEvent("HTMLEvents");
			evt.initEvent(event, true, true ); // event type,bubbling,cancelable
			return !element.dispatchEvent(evt);
		}
	},
	
	/* Trim a string */
	trim: function(string) {
		this.replace(/^\s*/, "").replace(/\s*$/, "");
	},
	
	preloadImages: function(imageUrls) {
		var p = new Image();
		lf.foreach(imageUrls,function(url) {
			p.src = url;
		});
	},
	
	
	initMessagesMask: function() {
		var mask = lf.element.get('messages-mask');
		if(mask) {
			lf.element.setStyle(mask,'position','absolute');
			lf.element.setStyle(mask,'left','0px');
			lf.element.setStyle(mask,'top','0px');
			
			lf.element.setStyle(mask,'right','0px');
			lf.element.setStyle(mask,'background-color','#000');
			lf.element.setStyle(mask,'opacity','.5');
			
			var height = lf.element.getDocumentHeight();
			lf.element.setStyle(mask,'height',height + 'px');
			
			lf.element.setStyle(mask,'z-index','10');
		}
	},
	
	hideMessages: function() {
		lf.element.hide('messages-mask');
		lf.element.hide('messages');
	}

};

lf.userAgent = {
	isWebKit: function() {
		return new RegExp(navigator.userAgent).match("/Konqueror|Safari|KHTML/");
	},
	
	isIe: function() {
		return new RegExp(navigator.userAgent).match("/MSIE/");
	},
	
	isOpera: function() {
		return new RegExp(navigator.userAgent).match("/Opera/");
	},
	
	isFirefox: function() {
		return new RegExp(navigator.userAgent).match("/Firefox/");
	}
};