/*

GEM Products Inc.

Custom extensions to the Prototype.js lib and HTML DOM.

Requires the protoype.js script lib.

		Revision History:
		v1.0.1
		------------------------
		> Added watch, unwatch, setDynamicProperty, and unsetDynamicProperty methods to Object.prototype
*/

if (!GEM) var GEM = { };

/// DEFINE ELEMENT CLASS METHODS
Element.FindDescendantsWithAttributeValue = function(element, attrName, value) {
	var descendants = element.descendants();
	var list = [];
	
	for (var i = 0; i < descendants.length; ++i) {
		if (descendants[i].getAttribute(attrName) == value)
			list.push(descendants[i]);
	}
	
	return list;
};
Element.FindFirstDescendantWithAttributeValue = function(element, attrName, value) {
	var list = Element.FindDescendantsWithAttributeValue(element, attrName, value);
	if (list.length == 0)
		return null;
	else 
		return list[0];
};
Element.GetElementById = function(element, id) {
	return Element.FindFirstDescendantWithAttributeValue(element, "id", id);
};
Element.GetElementsByName = function(element, name) {
	return Element.FindDescendantsWithAttributeValue(element, "name", name);
};


/// DEFINE ELEMENT INSTANCE METHODS
Element.prototype.findDescendantsWithAttributeValue = function(attrName, value) {
	return Element.FindDescendantsWithAttributeValue(this, attrName, value);
};
Element.prototype.findFirstDescendantWithAttributeValue = function(attrName, value) {
	return Element.FindFirstDescendantWithAttributeValue(this, attrName, value);
};
Element.prototype.getElementById = function(id) {
	return Element.GetElementById(this, id);
};
Element.prototype.getElementsByName = function(name) {
	return Element.GetElementsByName(this, name);
};



var URLInfo = Class.create();
URLInfo.prototype = {
	
	url: 					null,
	protocol: 			null,
	domain: 				null,
	filePath: 			null,
	isAbsolutePath:	null,
	queryString:		null,
	queryParams:		null,
	fragment:			null,
	
	initialize: function(urlString) {
		
		//Debug.Log("Parsing URL '"+urlString+"'");
		
		/// if urlString is not passed, then attempt to use the current page's url
		if (!urlString)
			urlString = document.URL;
		
		/* REGEX Breakdown
			- Accepts absolute & relative URL's with or without query string
			- Description of returned matches...
				0: original string
				1: protocol
				2: domain	
				3: file path
				4: query string
				5: page fragment (when a url contains a trailing # sign and name eg. http://www.gemlux.com/mypage.html#cleats)
			- Values at the specified indexes will be undefined if it was not specified in the URL String
			- Known issues:
				a) If an absolute path is provided, but does not begin with a protocol (e.g. http://) then is it viewed as a relative path.
		*/
		
		// pattern found at http://regexlib.com/REDetails.aspx?regexp_id=115
		var regex = /^(?=[^&])(?:([^:/?#]+):)?(?:\/\/([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/;
		var matches = urlString.match(regex);
		
		if (!matches) {
			/// assume invalid url
			throw "'GEM.URLInfo' could not parse the string '"+urlString+"'. Please check the URL format.";	
		}
		
		/// CREATE THE OBJECT TO BE RETURNED...
		Object.extend(this, {
			url: 					matches[0],
			protocol: 			matches[1],
			domain: 				matches[2],
			filePath: 			matches[3],
			isAbsolutePath:	(!isEmptyValue(matches[2])),
			queryString:		matches[4],
			queryParams:		null,
			fragment:			matches[5]
		});
		
		/// process query string parameters if present
		if (!isEmptyValue(this.queryString)) {
			this.queryParams = { };
			
			/// get array of current parameters and values
			var currentParams = this.queryString.split("&");
			var components = null;
			/// loop parameters and populate into an object....
			for (var i = 0; i < currentParams.length; ++i) {
					components = currentParams[i].split("=");
					this.queryParams[components[0]] = (components.length > 1) ? components[1] : "";
			}
		}
		else {
			Object.extend(this, {
				queryParams: null,
				queryString: null
			});
		}
	},
	
	hasQueryParams:	function() { return (!isEmptyValue(this.queryParams)) },
	getQueryParam:		function(paramName) { return (this.hasQueryParams()) ? this.queryParams[paramName] : null; },
	
	copyUrl:	function(replacementProperties) {
		var newUrl = Object.clone(this);
		Object.extend(newUrl, replacementProperties || {});
		newUrl.url = newUrl.toString();
		return newUrl;
	},
	toString: function() {
		return this.protocol+this.domain+this.filePath+this.queryString+this.fragment;
	}
};

GEM.URLInfo = URLInfo;

/// RETURNS AN OBJECT CONTAINING PROPERTIES OF INFORMATION PARSED FROM THE PROVIDED URL STRING
function parseUrl(urlString) {
	return new GEM.URLInfo(urlString);
}
