/**
 * Static utility class containing functionality common to any JS application.
 * @static
 */
HD.util.Common = {
	/**
	 * Determine whether the string starts with a given string.
	 * 
	 * @param {String} string the string to test
	 * @param {String} start the pattern to search for
	 * @return boolean for whether the string starts with the other string
	 */
	startsWith : function(string, start) {
		return (string.match("^"+start)==start);
	},
	
	/**
	 * Determine whether the string ends with a given string.
	 * 
	 * @param {String} string the string to test
	 * @param {String} end the pattern to search for
	 * @return boolean for whether the string ends with the other string
	 */
	endsWith : function(string, end) {
		return (string.match(end+"$")==end);
	},
	
	/**
	 * Gets URL request parameter value by name.
	 * 
	 * @param {String} name the parameter name
	 * @param {boolean} skip whether to skip converting 0/1 to false/true (part of the original method implementation)
	 * @return the parameter value or null
	 */
	getRequestParam : function (name, skip) {
		if (!name) {return;}
		name = name.replace(/\[/g,"\[").replace(/\]/g,"\]");
		var regexS = "[\\?&]"+name+"=([^&#]*)";
		var regex = new RegExp(regexS);
		var results = regex.exec(window.location.href);
		var res = results == null ? null : results[1];
		if(skip) {
			return res != null ? decodeURIComponent(res) : null;
		} else {
			var temp = !!res && res.match(/^(true|1)$/) ? true :
				(!!res && res.match(/^(false|0)$/) ? false : 
				(!!res && res.match(/^(null|undefined)$/) ? null : res));
			return temp != null ? decodeURIComponent(temp) : null;
		}
	},
	
	/**
	 * Shows tooltip.
	 * 
	 * @param {String} id tooltip id
	 * @param {String|HTMLElement} ctx where to attach the tooltip
	 * @param {String} text the tooltip text
	 * @return reference to the created tooltip
	 */
	showToolTip : function(id, ctx, text) {
		var tooltip = new YAHOO.widget.Tooltip(id, 
				{ context:ctx, 
				  text:text });
		return tooltip;
	},
	
	/**
	 * Sets up default value for an input with auto clear on focus, 
	 * then reverts to the default value on blur if a value wasn't entered.
	 * 
	 * @param {HTMLElement} element the element to setup default value for
	 * @param {String} defaultValue the default element value
	 */
	defaultValue : function(element, defaultValue) {
		element.onfocus = function() {
			if(this.value == defaultValue) {
				this.value = "";
			}
		};
		element.onblur = function() {
			if(!HD.util.Common.hasValue(this.value)) {
				this.value = defaultValue;
			}
		};
	},
		
	/**
	 * Determine whether the string has value, null or empty strings return false.
	 * 
	 * @param {String} string the string to test
	 * @return whether the string has value
	 */
	hasValue : function(string) {
		return string != null && string != "";
	},
	
	/**
	 * Asynchronously submits a form.
	 * 
	 * @param {HTMLForm} form the form element
	 * @param {String} url the url to submit the form to
	 * @param {Function} callback the callback to execute upon successful completion
	 * @param {String} method (Optional) the HTTP verb to use during submission
	 */
	submitForm : function(form, url, callback, method) {
		if(method == null) {
			method = "POST";
		}
		YAHOO.util.Connect.setForm(form);
		YAHOO.util.Connect.asyncRequest(method, url, {success : callback});
	},
	
	/**
	 * Augments the functionality of one object's prototype with the functions from the other.
	 * 
	 * @param {Object} subClass the child class
	 * @param {Object} superClass the parent class
	 */
	extend : function(subClass, superClasses) {
		for(var i = 0, len = superClasses.length; i < len; i++) {
			var superClass = superClasses[i];
			for(var a in superClass.prototype) {
				if(!subClass.prototype[a]) {
					subClass.prototype[a] = superClass.prototype[a];
				}
			}
		}
	},
	
	/**
	 * Removes the specified element from the array.
	 * 
	 * @param {Array} array the array to remove the element from
	 * @param {Object} element the element to remove
	 * @return the array without the element
	 */
	remove : function(array, element) {
		var tempArray = [];
		for(var i = 0, len = array.length; i < len; i++) {
			if(array[i] != element) {
				tempArray.push(array[i]);
			}
		}
		return tempArray;
	},
	
	/**
	 * Merged the contents of two arrays.
	 * 
	 * @param {Array} array1 the array to copy to
	 * @param {Array} array2 the array to copy from
	 */
	merge : function(array1, array2) {
		for(var i = 0, len = array2.length; i < len; i++) {
			array1.push(array2[i]);
		}
	},
	
	/**
	 * Observable object used to keep track of overlay open/close events.
	 */
	observable : null,
	
	/**
	 * Returns a reference to the observable object.
	 * 
	 * @return observable
	 */
	getObservable : function() {
		if(this.observable == null) {
			this.observable = new HD.util.Observable();
		}
		return this.observable;
	},
	
	/**
	 * Displays an in-page overlay.
	 * 
	 * @param {String|HTMLElement} body the contents of the overlay
	 * @param {String|HTMLElement} title the content of the overlay header
	 * @param {int} width the overlay's width
	 * @param {int} height the overlay's height
	 * @param {boolean} isSkipDestroy whether to skip the destruction of the overlay (just hide it)
	 * @return reference to the overlay element
	 */
	showOverlay : function(body, title, width, height, isSkipDestroy) {
		var dom = HD.util.Dom;
		var overlayEl = dom.get("hdwcOverlay");
		//hide overlay instance if one already exists
		if(overlayEl){this.hideOverlay(isSkipDestroy);}		
		//HD.util.Analytics.track(this.analyticsOpenString(body));
		this.getObservable().notifyObservers("overlayOpen");				
			
		// configure overlay		
		var overlayConfig = {					
			constraintoviewport: true,
			close: true,		  // show close button
			draggable: true,	  // draggable
			zindex:100000,		  // z index
			modal: true,		  // overlays other elements
			visible: false,		  // visible right away
			iframe: true,		  // useful in overlay certain elements
			underlay : "shadow",   // show shadow,
			fixedcenter:true,
			height: height,
			width: width						
		};
		
		var overlay = new YAHOO.widget.Panel("hdwcOverlay", overlayConfig);
		
		//overlay.setHeader(title);
		overlay.setBody(body);
		overlay.render(document.body);
		//Centers the overlay with scrolling
		overlay.center();
		//show the overlay
		overlay.show();	
		
		var cb = this;
		var closeClickCb = function(){
			var observable = cb.getObservable.call(cb);
			observable.notifyObservers("overlayClose_Click");
			HD.util.Common.hideOverlay(isSkipDestroy);
		};
		
		var overlayEl = dom.get("hdwcOverlay");
		
		var closeEls = dom.getByClass("hdClose", "*", overlayEl);
		if(closeEls.length > 0) {
			closeEls[0].onclick = closeClickCb;
		}
		
		// use our hideOverlay method for when use clicks close on overlay
		// this allows for different events to fire when closing was user initiated
		closeEls = dom.getByClass("container-close", "a", overlayEl);
		for(var i = 0, len = closeEls.length; i < len; i++) {
			(function() {
				closeEls[i].onclick = closeClickCb;
			})();
		}
		
		this.overlay = overlay;
		return overlayEl;
	},

	/**
	* Method for hiding page overlay.
	*
	* @param {boolean} isSkipDestroy whether to skip the destruction of the overlay (just hide it)
	*/
	hideOverlay : function(isSkipDestroy) {
		//if there is an existent overlay, hide it			
		if(this.overlay != null) {
			this.overlay.hide();
			if(!isSkipDestroy) {
				this.overlay.destroy();
			}
			//HD.util.Analytics.track(this.analyticsCloseString());
			this.getObservable().notifyObservers("overlayClose");
		}
	},
	
	/**
	 * Strips HTML tags from text.
	 * 
	 * @param {String} text the text to strip
	 * @param {boolean} smart whether to strip all tags or conditionally strip some
	 * @param {Array} tags the list of tags to be removed conditionally
	 * @param {boolean} returnDom whether to return as text or as a DIV element with text set as innerHTML
	 * @return stripped text as a string or as as a DIV DIV element
	 */
	stripHtmlTags : function(text, smart, tags, returnDom) {
		if (smart) {
			var blacklist = tags || ['img','embed'];
			var frag = document.createElement('div');
			frag.innerHTML = text;
			
			// Remove the child and clean empty container nodes.
			var isEmpty = function(el) {
				var result = true;
				// Check for useless elements.
				if (el.childNodes && el.childNodes.length > 0) {
					for (var i = 0, l = el.childNodes.length; i < l; i++) {
						if (!el.childNodes[i].nodeName.match(/^br$/i)) {
							result = false;
							break;
						}
					}
				}
				return result;
			};
			var cleanEmptyNodes = function(el, force) {
				if (el && (force || isEmpty(el))) {
					var parent = el.parentNode;
					parent.removeChild(el);
					arguments.callee(parent);
				}
			};
			
			// Remove nodes from the DOM.
			for (var i = 0; i < blacklist.length; i++) {
				var elements = frag.getElementsByTagName(blacklist[i]);
				for (var j = elements.length - 1; j >= 0; j--) {
					cleanEmptyNodes(elements[j], true);
				}
			}
			
			// Return the resulting DOM fragment.
			return returnDom ? frag : frag.innerHTML;
		}
		else {
			return text.replace(/<\S[^><]*>/g, "");
		}
	},
	
	/**
	 * Converts URL to the specified protocol, optionally replaces the path.
	 * 
	 * @param {String} protocol the new protocol
	 * @param {String} newRelativePath (Optional) the relative path to use
	 * @param {String} url (Optional) the URL to convert, if one isn't passed in, window.location.href is used
	 * @return converted URL
	 */
	switchProtocol : function(protocol, newRelativePath, url) {
		if(url == null) {
			url = window.location.href;
		}
		
		if(!url.match(/^http:\/\/localhost/)) {
			// replace protocol
			url = url.replace(/^.*:\//, protocol + ':/'); 
		}
		
		// if new relative path was provided, replace the path
		if(newRelativePath != null) {
			// add '/' to the end of the relative path if necessary
			if(!newRelativePath.match(/^\//)) {
				newRelativePath = "/" + newRelativePath;
			}
			
			// extract the URL portion up until the context
			var match = url.match(/^(.*:\/\/[^\/]+)\/.*$/);
			if(match != null && match.length > 1) {
				url = match[1] + newRelativePath;
			}
		}
		
		return url;
	},
	
	isLocal : function() {
		var url = window.location.href;
		return url.indexOf("://localhost") > 0;
	},
	
	/**
	 * Appends parameters to the URL.
	 * 
	 * @param {String} url the URL to append parameters to
	 * @param {Array} params the list of parameters to append
	 * @return the URL with parameters
	 */
	propagateParams : function(url, params) {
		if(params == null || params.length < 1) {
			return url;
		}
		var common = HD.util.Common;
		if(url.indexOf("?") < 0) {
			url += "?";
		}
		for(var i = 0, len = params.length; i < len; i++) {
			var paramKey = params[i];
			var paramValue = common.getRequestParam(paramKey);
			if(paramValue != null) {
				url += (url.match(/\?$/) ? "" : "&") + paramKey + "=" + paramValue;
			}
		}
		return url;
	},
	
	getForwardUrl : function(relativePath, paramsToPropage, protocol) {
		var pathWithParams = HD.util.Common.propagateParams(relativePath, paramsToPropage);
		if(HD.util.Common.hasValue(protocol)) {
			return HD.util.Common.switchProtocol(protocol, pathWithParams);
		}
		return pathWithParams;
	},
	
	_testSwitchProtocol : function() {
		var urlBefore1 = "http://localhost:8080/en_US/Content/Advanced_Features/riders_edge_online/courseSelection.jsp";
		var urlAfter1 = HD.util.Common.switchProtocol(urlBefore1, "https", "/en_US/Content/Advanced_Features/riders_edge_online/testPage1.jsp");
		
		var urlBefore2 = "https://localhost:8080/en_US/Content/Advanced_Features/riders_edge_online/courseSelection.jsp";
		var urlAfter2 = HD.util.Common.switchProtocol(urlBefore2, "http", "en_US/Content/Advanced_Features/riders_edge_online/testPage2.jsp?locale=en_US");
		
		var urlBefore3 = "http://wip.wcm.harley-davidson.com/wcm/Content/Pages/riders_edge_online/search.jsp?locale=en_US";
		var urlAfter3 = HD.util.Common.switchProtocol(urlBefore3, "https", "/en_US/Content/Advanced_Features/riders_edge_online/testPage3.jsp?locale=en_US");
		
		var urlBefore4 = "https://www.harley-davidson.com/wcm/Content/Pages/riders_edge_online/search.jsp?locale=en_US";
		var urlAfter4 = HD.util.Common.switchProtocol(urlBefore4, "http", "en_US/Content/Advanced_Features/riders_edge_online/testPage4.jsp?locale=en_US");

		var urlBefore5 = "https://www.harley-davidson.com/";
		var urlAfter5 = HD.util.Common.switchProtocol(urlBefore5, "http");
		
		alert("urlBefore1 [" + urlBefore1 + "]\nurlAfter1 [" + urlAfter1 + "]\n" + 
				"urlBefore2 [" + urlBefore2 + "]\nurlAfter2 [" + urlAfter2 + "]\n" + 
				"urlBefore3 [" + urlBefore3 + "]\nurlAfter3 [" + urlAfter3 + "]\n" +
				"urlBefore4 [" + urlBefore4 + "]\nurlAfter4 [" + urlAfter4 + "]\n" +
				"urlBefore5 [" + urlBefore5 + "]\nurlAfter5 [" + urlAfter5 + "]");
	}
};
