/**
*	Class containing commonly used utility methods.
*/
HD.util.Common = {
	observable : null,
	
	getObservable : function() {
		if(this.observable == null) {
			this.observable = new HD.util.Observable();
		}
		return this.observable;
	},
	
	/**
	* Method for comparing strings. If "a" is larger than "b" "1" will be
	* returned if "a" is smaller than "b" "-1" will be returned if 
	* equal "0" will be returned
	* @param a{String|HTMLElement} 
	* @param b{String|HTMLElement} 
	*/
	compareString : function(a,b) {			
		return (a===b) ? 0 : (a>b) ? 1 : -1;
	},
	
	/**
	* Method for displaying page overlay.
	* @param body{String|HTMLElement} the overlay iFrame HTML page location
	* @param width{int} (optional) the overlay width
	* @param height{int} (optional) the overlay height	
	*/

	showOverlay : function(body, title, width, height, isSkipDestroy) {
		var overlayEl = HD.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");
		
		// get viewport height			
		var isResizeViewPort = 540 > YAHOO.util.Dom.getViewportHeight() && parseInt(height, 10) > 450;
	
		// if the viewport it too small for the overlay we will resize the overlay
		if(isResizeViewPort){			
			height = YAHOO.util.Dom.getViewportHeight() - 40;				
		}			
		
		// check if number if not convert
		if(!(typeof width == 'number'))
			width = parseInt(width.replace(/px/g, ""));				
		// check if number if not convert	
		if(!(typeof height == 'number'))
			height = parseInt(height.replace(/px/g, ""));			
		
		// find center of the viewport
		var posX = (YAHOO.util.Dom.getViewportWidth() / 2) - (width / 2);			
		var sfs = YAHOO.util.Dom.getDocumentScrollTop();		
		var posY = ((YAHOO.util.Dom.getViewportHeight() + sfs) / 2) - (height / 2);		
		
		posX = Math.round(posX);
		posY = Math.round(posY);		
			
		// 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,
			x : posX,
			y : posY,
			// set width and height if passed, append "px" if integers
			height: typeof height == 'number' ? height + 'px' : height || null,	
			width: typeof width == 'number' ? width + 'px' : width || null						
		};  

		//set iframe to import page body as overlay body. passes width, height and src string.
		//body = "<iframe class='hdwcOverlayIframe' src='" + body + "' frameBorder='0' height='" + height + "' width='" + width + "' scrolling='no' allowTransparency='true'></iframe>";
				
		var overlay = new YAHOO.widget.Panel("hdwcOverlay", overlayConfig);
		
		//overlay.setHeader(header);
		overlay.setBody(body);
		overlay.render(document.body);
		//Centers the overlay with scrolling Fix 19770
		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 = HD.get("hdwcOverlay");
		
		var closeEls = HD.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 = HD.getByClass("container-close", "a", overlayEl);
		for(var i = 0, len = closeEls.length; i < len; i++) {
			closeEls[i].href = 'javascript:void(0)';
			(function() {
				closeEls[i].onclick = closeClickCb;
			})();
		}
		
		// if the viewport it too small for the overlay we will resize overlay content
		if(isResizeViewPort){
			YAHOO.util.Event.onContentReady("hdwcBody", function(){				
				var hdwcBodyEl = HD.get("hdwcBody");
				var scrollableDivEl = HD.get("scrollableDiv");				
				
				if(hdwcBodyEl) {
					hdwcBodyEl.style.height = (parseInt(height,10) - 65) + "px";
				}
				if(scrollableDivEl) {
					scrollableDivEl.style.height = (parseInt(height,10) - 90) + "px";					
				}
			}); 
			
			YAHOO.util.Event.onContentReady("suggestions", function(){	
				var suggestionsContentWrapperEL = YAHOO.util.Dom.getElementsByClassName("suggestionsContentWrapper","div");
				if(suggestionsContentWrapperEL[0]){	
					for(var x=0; x<suggestionsContentWrapperEL.length; x++){						
						suggestionsContentWrapperEL[x].style.height = (parseInt(height,10) - 65) + "px";
					}
				}			
			}); 			
		}
		
		this.overlay = overlay;
		return overlayEl;
	},

	
	
	/**
	* Method for hiding page overlay.
	*/
	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");
		}
	},
	/**
	* Method for scrolling the overlay to the top
	*/
	scrollOverlay: function() {
		if(this.overlay != null){
			var gfe = this.overlay.getFocusableElements();
			var gfeIFrame = gfe[0];
			var gfeIFrameDocument = gfeIFrame.contentWindow.document;
			var eBody = gfeIFrameDocument.getElementById("hdwcBody");
			eBody.scrollTop = 0;
		}
	},
    
    /**
	* Method for hidding the overlay which we will assume will be opened by a parent	
	* @param trigger{String|HTMLElement} className of the element we will target to close
	* the overlay, multiple instances of the classname can appear on the same page	
	*/
	closeOverlay : function (trigger){	       
        var classNamesElements = YAHOO.util.Dom.getElementsByClassName(trigger);       
        for(var x=0; x < classNamesElements.length; x++) {  
            YAHOO.util.Event.on(classNamesElements[x], "click", function(){
		        if(window.parent)
                    window.parent.HDWC.util.hideOverlay();
		        });//end event            
        }//end for      
	},   
	/**
	* Method for creating a content module.
	* @param element{String|HTMLElement} the module element
	* @param isVisible{Boolean} show/hide on render
	* @param toggleTrigger{HTMLElement} (option1) element, when clicked, toggles the module
	* @param onTrigger{HTMLElement} (option2) element, when clicked, shows the module
	* @param offTrigger{HTMLElement} (option2) element, when clicked, hides the module
	*/
	createModule : function(element, isVisible, toggleTrigger, onTrigger, offTrigger) {
		// create module
		var module = new YAHOO.widget.Module(element, { visible: isVisible });
		// render module, visible of hidden based on 'isVisible' param 
		module.render();
		
		var isShown = isVisible;
		
		// assign event on/off listeners
		if(toggleTrigger != null) {
			YAHOO.util.Event.on(toggleTrigger, "click", function() {
				isShown = !isShown;
				module[isShown? "show" : "hide"].call(module);
			});
		}
		if(onTrigger != null) {
			YAHOO.util.Event.on(onTrigger, "click", function() {
				isShown = !isShown;
				module.show.call(module);
			});
		}
		if(offTrigger != null) {
			YAHOO.util.Event.on(offTrigger, "click", function() {
				isShown = !isShown;
				module.hide.call(module);
			});
		}
	},
	
	createTabs : function(tabs, parent) {
		if(tabs == null || tabs.length < 1 || parent == null) {
			return null;
		}
		
	    var tabView = new YAHOO.widget.TabView();
	    
	    for(var i = 0, len = tabs.length; i < len; i++) {
	    	var tab = tabs[i];
			tabView.addTab( new YAHOO.widget.Tab({
		        label: tab.header,
		        content: tab.body,
		        active: tab.isActive || false
		    }));
	    }
	    
	    tabView.appendTo(parent);
	    return tabView;
	},
	
	requestContent : function(source, callback, method) {
		if(!this.hasValue(method)) {
			method = "GET";
		}
		
		var cb = callback;
		var handlers = {
		  	success: function(response) {cb(response.responseText);},
		  	failure: function(o) {}
		};
		
		YAHOO.util.Connect.asyncRequest(method, source, handlers);
	},
	
	hasValue : function(string) {
		return string != null && string != "";
	},
	
	timestamp : function() {
		return new Date().getTime();
	},
	
	generateElementId : function() {
		return "hdEl" + this.timestamp() + Math.floor(Math.random()*10000);
	},
	
	uploadFile : function(form, url, callback) {
	   // the second argument is true to indicate file upload.
	   YAHOO.util.Connect.setForm(form, true);
	   
		var cb = callback;
		var handlers = {
			upload : function(response) {cb(response.responseText);},
		  	failure: function(o) {}
		};
	
	   YAHOO.util.Connect.asyncRequest("POST", url, handlers);
	},
	
	/**
	 * This method checks the current url to see if it contains a match to the 
	 * passed in name. 
	 * 
	 * @method getRequestParam
	 * @param  {String} name  the url that we are parsing
	 * @return {String}       the match
	 */
	getRequestParam : function (name) {
		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];
		return !!res && res.match(/^(true|1)$/) ? true :
			(!!res && res.match(/^(false|0)$/) ? false : 
			(!!res && res.match(/^(null|undefined)$/) ? null : res));
	},
	
	log : function(message) {
		// TODO add logging
	},
	
	includeJs : function(url, callback) {
		var cb = callback;
		var script = document.createElement("script");
		script.type = "text/javascript";
		script.language = "javascript";
		script.src = url;
		
		if(navigator.userAgent.indexOf("IE")>=0) {
			script.onreadystatechange = function(){
				if(script && ("loaded" == script.readyState || "complete" == script.readyState)) {
					script.onreadystatechange=null;
					cb();
				}
			};
		} else {
			script.onload=function(){
				script.onload=null;
				cb();
			};
		}
		
		document.getElementsByTagName("head")[0].appendChild(script);
	},
	
	callbackCounter : 0,
	
	insertContent : function(element, url, callback) {
		var callbackId = "hdcb" + this.callbackCounter++;
		window[callbackId] = callback;
		
		// url doesn't have parameters
		if(url.indexOf("?") < 0) {
			url += "?"
		} // url ends with a '&', no need to add another one 
		else if(url.indexOf("&") == url.length - 1) {
		} // url contains parameters but doesn't end with '&', append one 
		else {
			url += "&"
		}
		
		url += "hdcbid=" + callbackId;
		
		var el = this.get(element);
		this.requestContent(url, function(response) {
			var div = document.createElement("div");
			div.innerHTML = response;
			el.appendChild(div);
		});
	},
	
	get : function(element) {
		return YAHOO.util.Dom.get(element);
	},
	
	trim : function(text, limit) {
		if(text.length > limit) {
			text = text.substr(0, limit).replace(/\s*$/, '');
		}
		return text;
	},
	
	stripHtmlTags : function(text, smart, tags, returnDom, limit) {
		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.
			if (limit) {
				var count = 0;
				var removeMask = new RegExp('^(' + blacklist.join('|') + ')$', 'i');
				
				// Copy all elements to a standalone array.
				var elCollection = frag.getElementsByTagName('*');
				var elements = [];
				for (var i = 0, l = elCollection.length; i < l; i++) {
					elements.push(elCollection[i]);
				}
				
				// Remove blacklisted elements.
				for (var j = 0, l = elements.length; j < l; j++) {
					if (elements[j].nodeName.match(removeMask)) {
						cleanEmptyNodes(elements[j], true);
						count++;
					}
					if (count >= limit) {
						break;
					}
				}
			}
			else {
				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, "");
		}
	},
	
	ellipseText : function(text, limit, smart) {
		if(text.length > limit) {
			if (smart) {
				// Smart strip specific HTML tags.
				var frag = this.stripHtmlTags(text, smart, null, true);
				
				// Generate an array of all text nodes (slow, but should be a small DOM).
				var textNodes = [];
				(function(el) {
					if (el.nodeType == 3) {
						textNodes.push(el);
					}
					else {						
						for (var i = 0; i < el.childNodes.length; i++) {
							arguments.callee(el.childNodes[i]);
						}
					}
				})(frag);
				
				// Trim text nodes.
				var digestedLength = 0;
				var markedNode = null;
				for (var i = 0; i < textNodes.length; i++) {
					if (textNodes[i].data.length + digestedLength > limit) {
						markedNode = textNodes[i];
						markedNode.data = this.trim(markedNode.data, limit - digestedLength);
						var lastIndex = markedNode.data.lastIndexOf(" ");
						if(lastIndex > 0) {
							markedNode.data = markedNode.data.substr(0, lastIndex);
						}
						markedNode.data += "...";
						break;
					}
					else {
						digestedLength += textNodes[i].data.length;	
					}
				}
				// Remove all siblings/nodes after the marked node.
				if (markedNode) {
					(function(el) {
						if (el) {
							while (el.nextSibling) {
								el.parentNode.removeChild(el.nextSibling);
							}
							arguments.callee(el.parentNode);
						}
					})(markedNode);
				}
				
				
				// Return smart trimmed result.
				text = frag.innerHTML;
			}
			else
			{
				text = this.stripHtmlTags(text, smart);
				text = this.trim(text, limit);
				var lastIndex = text.lastIndexOf(" ");
				if(lastIndex > 0) {
					text = text.substr(0, lastIndex);
				}
				text += "...";
			}
		}
		return text;
	},
	
	round : function(number, numOfDecimals) {
		if(numOfDecimals == null) {
			numOfDecimals = 0;
		}
		var multiplier = Math.pow(10, numOfDecimals);
		var temp = Math.round(number * multiplier);
		return temp / multiplier;
	},
	
	getAppUrl : function() {
		return window.location.href.split("?")[0];
	},
	
	getHostUrl : function() {
		var l = window.location;
		return l.host;
	},
	
	getServerUrl : function() {
		var l = window.location;
		return [l.protocol, "//", l.host].join("");
	},
	
	setCookie : function(name,value,duration) {
		try {
		var expires = "";
		if (duration != null) {
			expires = "; expires="+duration;
		}
		document.cookie = name+"="+value+expires+"; path=/";
		} catch(e) {}
	},
	
	getCookie : function(name, doc) {
		try {
		doc = doc != null ? doc : document;
		var nameEQ = name + "=";
		var ca = doc.cookie.split(';');
		for(var i=0;i < ca.length;i++) {
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
		}
		return null;
		} catch(e) {}
	},
	
	eraseCookie : function(name) {
		setCookie(name,"",-1);
	},
	
	contains : function(array, element) {
		if(array != null && element != null) {
			for(var i = 0, len = array.length; i < len; i++) {
				if(array[i] == element) {
					return true;
				}
			}
		}
		return false;
	},
	
	scrollTo : function(element){
		var posX = 0;
		var posY = 0;
		
		while(element != null){
			posX += element.offsetLeft;
			posY += element.offsetTop;
			element = element.offsetParent;
		}
		
		window.scrollTo(posX,posY);
	},
	
	scrollToTop : function() {
		window.scrollTo(0, 0);
	},
	
	addImage : function(url, callback) {
		var image = new Image();
		if (callback) {
			image.onload = callback;
		}
	    image.src = url;
	    image.style.width = "0px";
	    image.style.height = "0px";
	    document.body.appendChild(image);
	},
	
	printStackTrace : function() {
	  var callstack = [];
	  var isCallstackPopulated = false;
	  try {
	    i.dont.exist+=0; //doesn't exist- that's the point
	  } catch(e) {
	    if (e.stack) { //Firefox
	      var lines = e.stack.split("\n");
	      for (var i=0, len=lines.length; i<len; i++) {
	        if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
	          callstack.push(lines[i]);
	        }
	      }
	      //Remove call to printStackTrace()
	      callstack.shift();
	      isCallstackPopulated = true;
	    }
	    else if (window.opera && e.message) { //Opera
	      var lines = e.message.split("\n");
	      for (var i=0, len=lines.length; i<len; i++) {
	        if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
	          var entry = lines[i];
	          //Append next line also since it has the file info
	          if (lines[i+1]) {
	            entry += " at " + lines[i+1];
	            i++;
	          }
	          callstack.push(entry);
	        }
	      }
	      //Remove call to printStackTrace()
	      callstack.shift();
	      isCallstackPopulated = true;
	    }
	  }
	  if (!isCallstackPopulated) { //IE and Safari
	    var currentFunction = arguments.callee.caller;
	    while (currentFunction) {
	      var fn = currentFunction.toString();
//	      var fname = fn.substring(fn.indexOf("function") + 8, fn.indexOf("(")) || "anonymous";
	      callstack.push(fn);
	      currentFunction = currentFunction.caller;
	    }
	  }
	  
	  var console = HD.get("hdConsole");
	  if(console == null) {
		  console = document.createElement("div");
		  console.id = "hdConsole";
		  document.body.appendChild(console);
	  }
	  
	  console.innerHTML = callstack.join("<br/>");
	  
	  return;
	  
	  //alert(callstack.join("\n"));
	},
	
	analyticsOpenString : function() {
		return "default_analyticsOpenString";
	},
	
	analyticsCloseString : function() {
		return "default_analyticsCloseString";
	}
};

HD.register('hd_common', HD.util.Common, {version: "1.0", build: '1'});