/*
*  AWUtilities
*  Dan Lynn et al.
*  September 2006 -- 
*  
*  Provides a set of functions to assist in ajax web development.  Requires
*  the Prototype library version 1.4+
*/

// check for prototype  (thanks script.aculo.us)
if((typeof Prototype=='undefined') ||
  parseFloat(Prototype.Version.split(".")[0] + "." +
			 Prototype.Version.split(".")[1]) < 1.4)
  throw("AWUtilities requires the Prototype JavaScript framework >= 1.4.0");

var AWUtilities = {
	version: 0.4,
	
	Graphics: {},
	DOM: {},
	URL: {},
	Test: {},
	Validation: {}
};


// various tests
AWUtilities.Test = {

	isAlien: function(a) {
	   return this.isObject(a) && typeof a.constructor != 'function';
	},
	
	isArray: function(a) {
		return this.isObject(a) && a.constructor == Array;
	},
	
	isBoolean: function(a) {
		return typeof a == 'boolean';
	},
	
	isEmpty: function(o) {
		var i, v;
		if (this.isObject(o)) {
			for (i in o) {
				v = o[i];
				if (this.isUndefined(v) && this.isFunction(v)) {
					return false;
				}
			}
		}
		return true;
	},
	
	isFunction: function(a) {
		return typeof a == 'function';
	},
	
	isNull: function(a) {
		return a === null;
	},
	
	isNumber: function(a) {
		return typeof a == 'number' && this.isFinite(a);
	},
	
	isObject: function(a) {
		return (a && typeof a == 'object') || this.isFunction(a);
	},
	
	isString: function(a) {
		return typeof a == 'string';
	},
	
	isUndefined: function(a) {
		return typeof a == 'undefined';
	},
	
	isEmail: function(a) {
		var tester = new RegExp("^[\\w-_\.]*[\\w-_\.]\@[\\w]\.+[\\w]+[\\w]$");
		return tester.test(a);
	}
};

// DOM utilities
AWUtilities.DOM = {
	getElementsByAttribute: function(attribute, attributeValue) {
		var elementArray = new Array();
		var matchedArray = new Array();
		
		if (document.all) {
			elementArray = document.all;
		} else {
			elementArray = document.getElementsByTagName("*");
		}
		
		for (var i = 0; i < elementArray.length; i++) {
			if (attribute == "class") {
				var pattern = new RegExp("(^| )" + attributeValue + "( |$)");
		
				if (pattern.test(elementArray[i].className)) {
					matchedArray[matchedArray.length] = elementArray[i];
				}
			} else if (attribute == "for") {
				if (elementArray[i].getAttribute("htmlFor") || elementArray[i].getAttribute("for")) {
					if (elementArray[i].htmlFor == attributeValue) {
						matchedArray[matchedArray.length] = elementArray[i];
					}
				}
			} else if (elementArray[i].getAttribute(attribute) == attributeValue) {
				matchedArray[matchedArray.length] = elementArray[i];
			}
		}
		
		return matchedArray;
	}
};

// graphics and positioning functions
AWUtilities.Graphics = {
	// retunrs available screen size
	getAvailableSize: function() {
		var myWidth = 0, myHeight = 0;
		if( typeof( window.innerWidth ) == 'number' ) {
			//Non-IE
			myWidth = window.innerWidth;
			myHeight = window.innerHeight;
		} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
			//IE 6+ in 'standards compliant mode'
			myWidth = document.documentElement.clientWidth;
			myHeight = document.documentElement.clientHeight;
		} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
			//IE 4 compatible
			myWidth = document.body.clientWidth;
			myHeight = document.body.clientHeight;
		}
		return {
			x: myWidth,
			y: myHeight
		};
	},
	
	// finds the position of el
	getAbsolutePosition: function(el) {
		var SL = 0, ST = 0;
		var is_div = /^div$/i.test(el.tagName);
		if (is_div && el.scrollLeft)
			SL = el.scrollLeft;
			
		if (is_div && el.scrollTop)
			ST = el.scrollTop;
			
		var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST };
		if (el.offsetParent) {
			var tmp = AWUtilities.Graphics.getAbsolutePosition(el.offsetParent);
			r.x += tmp.x;
			r.y += tmp.y;
		}
		return r;
	},
	
	//finds the amount scrolled
	getScrollSize: function() {
		var scrOfX = 0, scrOfY = 0;
		if( typeof( window.pageYOffset ) == 'number' ) {
			//Netscape compliant
			scrOfY = window.pageYOffset;
			scrOfX = window.pageXOffset;
		} else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
			//DOM compliant
			scrOfY = document.body.scrollTop;
			scrOfX = document.body.scrollLeft;
		} else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
			//IE6 standards compliant mode
			scrOfY = document.documentElement.scrollTop;
			scrOfX = document.documentElement.scrollLeft;
		}
		
		return [ scrOfX, scrOfY ];
	}
};


// url parsing and formatting functions
AWUtilities.URL = {
	buildQueryString: function(paramsObject){
		var query = "";
		for(par in paramsObject){
			if(paramsObject[par] || paramsObject[par] == 0){
				query += (query.length > 0 ? "&" : "") + escape(par) + "=" + escape(paramsObject[par]);
			}		
		}
		return query;
	},
	ParameterCollection: {}
};

// Provides a wrapper class for building and parsing querystrings
// accepts data like this: { parameter: value, parameter2: "value2", ..... }
// or like this:  "parameter=value&parameter2=value2......"
AWUtilities.URL.ParameterCollection = Class.create();
AWUtilities.URL.ParameterCollection.prototype =  {
	initialize: function(params) {
		this.params = {};
		if (params) {
			
			// accept a parameter object
			if (typeof(params) == "object") {
				this.params = params;
			}
			
			// accept a querystring
			else if (typeof(params) == "string") {
				var vars = params.split("&");
				for (var i=0;i<vars.length;i++) {
					 var pair = vars[i].split("=");
					 this.params[pair[0]] = pair[1] ? pair[1] : null;
				}				
			}
		}
	},
	add: function(name, value) {
		this.params[name] = value;
		return this.params;
	},
	remove: function(name) {
		this.params[name] = null;
		delete this.params[name];
		return this.params;
	},
	toString: function() {
		return AWUtilities.URL.buildQueryString(this.params);
	}
};

AWUtilities.Validation.ValidatorField = Class.create();
AWUtilities.Validation.ValidatorField.prototype = {
	initialize: function(domField, validationFunction) {
		this.field 				= domField;
		this.validationFunction	= validationFunction;
		this.valid				= null;
	},
	
	validate: function() {
		this.valid = this.validationFunction($F(this.field));
		return this.valid;
	}
};

AWUtilities.Validation.Validator = Class.create();
AWUtilities.Validation.Validator.prototype = {
	initialize: function() {
		this.fields = new Array();
		this.valid  = null;
		this.errors = new Array();
	},
	
	addField: function(fieldObj, validationFunction) {
		this.fields.push(new AWUtilities.Validation.ValidatorField( fieldObj, validationFunction ));
	},
	
	validate: function() {
		this.valid  = true;
		this.fields.each( function(field) {
			var isValid = field.validate();
			if (!isValid) {
				this.errors.push(field);
			}
			
			this.valid &= isValid;
		}.bind(this));
		
		return !(this.valid==0);
	}
};

AWUtilities.date = {
	returnDate: function(stringFormat, date){
		stringFormat = stringFormat.toArray();
		
		if(AWUtilities.Test.isUndefined(date))
			date = new Date();
		
		returnStr = "";
		
		for(i=0; i<stringFormat.length; i++){
			str = stringFormat[i];
			
			switch(str){
				case "H":
					returnStr += AWUtilities.date.addLeading(date.getHours());
					break;
				case "h":
					returnStr += AWUtilities.date.addLeading(AWUtilities.date.get12Hour(date.getHours()));
					break;
				case "g":
					returnStr += AWUtilities.date.get12Hour(date.getHours());
					break;
				case "G":
					returnStr += date.getHours();
					break;
				case "a":
					returnStr += AWUtilities.date.getMeridiem(date.getHours());
					break;
				case "A":
					returnStr += String(AWUtilities.date.getMeridiem(date.getHours())).toUpperCase();
					break;
				case "i":
					returnStr += AWUtilities.date.addLeading(date.getMinutes());
					break;
				case "Y":
					returnStr += date.getFullYear();
					break;
				case "d":
					returnStr += AWUtilities.date.addLeading(date.getDate());
					break;
				case "D":
					returnStr += AWUtilities.date.get3Day(date.getDay());
					break;
				case "m":
					returnStr += AWUtilities.date.addLeading((date.getMonth()+1));
					break;
				case "M":
					returnStr += AWUtilities.date.get3Month(date.getMonth());
					break;
				case "n":
					returnStr += (date.getMonth()+1);
					break;
				default:
					returnStr += str;
			}
		}
		
		return String(returnStr);
	},
	
	addLeading: function(time){
		if(String(time).length <= 1)
			time = "0"+ time;
			
		return time;
	},
	
	get12Hour: function(hour){
		if(hour == 0)
			hour = 12;
			
		if(hour > 12)
			hour = hour-12;
			
		return hour;
	},
	
	getMeridiem: function(hour){
		mer = "";
		
		if(hour >= 0 && hour <= 11)
			mer = "am";
		else
			mer = "pm";
		
		return mer;
	},
	
	get3Day: function(day){
		week = new Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
		return week[day];
	},
	
	get3Month: function(month){
		year = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
		return year[month];
	}
};

//Created by: tigra @ http://www.softcomplex.com/forum/viewthread_2775/
Number.prototype.toCurrency = function(){
	var n_value = this;
	
	// validate input
	if (isNaN(Number(n_value)))
		return 'ERROR';
	
	// save the sign
	var b_negative = Boolean(n_value < 0);
	n_value = Math.abs(n_value);
	
	// round to 1/100 precision, add ending zeroes if needed
	var s_result = String(Math.round(n_value*1e2)%1e2 + '00').substring(0,2);
	
	// separate all orders
	var b_first = true;
	var s_subresult;
	while (n_value > 1) {
		s_subresult = (n_value >= 1e3 ? '00' : '') + Math.floor(n_value%1e3);
		s_result = s_subresult.slice(-3) + (b_first ? '.' : ',') + s_result;
		b_first = false;
		n_value = n_value/1e3;
	}
	// add at least one integer digit
	if (b_first)
		s_result = '0.' + s_result;
	
	// apply formatting and return
	return b_negative ? '($' + s_result + ')' : '$' + s_result;
}

Number.prototype.addCommas = function(){
	nStr = this;
	nStr += '';
	x = nStr.split('.');
	x1 = x[0];
	x2 = x.length > 1 ? '.' + x[1] : '';
	var rgx = /(\d+)(\d{3})/;
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}
	return x1 + x2;
}