/*
*  AWUtilities
*  Dan Lynn et al.
*  September 2006 --
*
*  Provides a set of functions to assist in ajax web development.  Requires
*  the Prototype library version 1.5+
*/

// check for prototype  (thanks script.aculo.us)
if((typeof Prototype=='undefined') ||
  parseFloat(Prototype.Version.split(".")[0] + "." +
			 Prototype.Version.split(".")[1]) < 1.5)
  throw("AWUtilities requires the Prototype JavaScript framework >= 1.5.0");

var AWUtilities = {
	version: 0.5,

	Graphics: {},
	DOM: {},
	URL: {},
	Test: {}
};


// 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) {
		a = Number(a); //If this Breaks your shit. Talk to nick. It was screwing with the String to Date function.
		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.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];
	},

	getMonthFrom3: function(month){
		year = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
		return year.indexOf(month);
	},

	strToDate: function(string, format){
		format = format.toArray();

		var place = 0;
		var date = new Date();
		var year = '';
		var month = '';
		var day = '';
		var hour = '';
		var minute = '';
		var sec = '';
		var am = '';

		for(i=0; i<format.length; i++){
			switch(format[i]){
				case "y":
					year += string.substr(place,1);
					place++;
					break;
				case "m":
					month += string.substr(place,1);
					place++;
					break;
				case "d":
					if(string.substr(place,1) != ' '){
						day += string.substr(place,1);
						place++;
					}
					break;
				case "h":
					hour += string.substr(place,1);
					place++;
					break;
				case "i":
					minute += string.substr(place,1);
					place++;
					break;
				case "s":
					sec += string.substr(place,1);
					place++;
					break;
				case 'a':
					am += string.substr(place,2);
					place += 2;
					break;
				default:
					place++;
			}
		}
		if(minute != '')
			date.setMinutes(minute);
		if(sec != '')
			date.setSeconds(sec);

		if(am == 'pm' || am == 'PM')
			date.setHours(hour+12);
		else if (am == 'am' || am == 'AM')
			date.setHours(hour);
		else
			date.setHours(hour);
			
		if(month != ''){
			if(AWUtilities.Test.isNumber(month)){
				date.setMonth(Number(month) -1);
			} else {
				date.setMonth(AWUtilities.date.getMonthFrom3(month));
			}
		}
		
		if(day != '')
			date.setDate(day);
			
		if(year != '')
			date.setYear(year);
			
		return date;
	}
};

//Created by: tigra @ http://www.softcomplex.com/forum/viewthread_2775/
Number.prototype.toCurrency = function(decimal_places){
	if (decimal_places == null) decimal_places = 2;
	
	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 ? (decimal_places > 0 ? '.' + s_result.substring(0,decimal_places) : '')  : ',' + 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;
}

Number.prototype.precisionRound = function(precision) {
	if (precision==null) precision = 2;
	
	var factor = Math.pow(10,precision);
	return Math.round(this * factor) / factor
};


String.prototype.toProperCase = function(){
     return this.toLowerCase().replace(/\w+/g,function(s){
          return s.charAt(0).toUpperCase() + s.substr(1);
     })
}

String.prototype.toDate = function(format){
     return AWUtilities.date.strToDate(this, format);
}

String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,"");
}
String.prototype.ltrim = function() {
	return this.replace(/^\s+/,"");
}
String.prototype.rtrim = function() {
	return this.replace(/\s+$/,"");
}

Array.prototype.ksort = function() {
	var nArr = new Array();
	var tArr = new Array();
	for(i in this){
		tArr.push(i);
	}
	tArr = tArr.sort();
	for(i in tArr){
		nArr[tArr[i]] = this[tArr[i]];
	}
	
	return nArr;
}

/**
 * StringBuilder Class
 * 
 * Assemables a string faster
 * 
 * From K. Collins http://www.codeproject.com/KB/scripting/stringbuilder.aspx
 * 
 * @author K. Collins
 * @since 6/13/2008
 * @param {Object} value
 */
function StringBuilder(value){this.strings = new Array("");this.append(value);}
StringBuilder.prototype.append = function (value){if (value){this.strings.push(value);}}
StringBuilder.prototype.clear = function (){this.strings.length = 1;}
StringBuilder.prototype.toString = function (){return this.strings.join("");}

$URL = function(hash){
	URL = '';
	$H(hash).each(
		function(pair){
			URL += '/'+ pair.key +'/'+ pair.value;
		}
	);
	return URL;
}

$WKT = function(collection){
	collection = $A(collection);
	if(collection.length > 1){
		WKT = 'POLYGON((';
	} else {
		WKT = 'POINT(';
	}
	count = false;
	collection.each(
		function(iter){
			if(count){
				WKT += ','+ iter.Longitude +' '+ iter.Latitude;
			} else {
				WKT += iter.Longitude +' '+ iter.Latitude;
				count = true;
			}
		}
	);
	if(collection.length > 1){
		WKT += ','+ collection[0].Longitude +' '+ collection[0].Latitude;
	}
	
	if(collection.length > 1){
		WKT += '))';
	} else {
		WKT += ')';
	}
	return WKT;
}

$RWKT = function(wkt){
	//var testPattern = /^(POINT|LINESTRING|LINEARRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)[ACEGIMLONPSRUTY\d,\.\-\(\) ]+$/; //Test Pattern
	var getPattern = '^(POINT|POLYGON)[\(]+([^\)]+)[\)]+$'; //Get Points Pattern
	var reg = new RegExp(getPattern, 'g');
	reg.compile(getPattern, 'g');
	var matches = reg.exec(wkt);
	try{
		if(matches[2]){
			var points = matches[2].split(',');
			var shape = new Array();
			for(var i = 0; i<points.length; i++){
				var temp = points[i].split(' ');
				shape.push({
					Latitude: temp[1],
					Longitude: temp[0]
				});
			}
			return shape;
		} else {
			return false;
		}
	} catch(e){
		return false;
	}
}