/**
 * Base object for all HP javascript
 * Contains common utility methods
 */
var HP = {
	LOG_TO_WINDOW: false,
	LOG_TO_SERVER: true,
	// Request wrapper needed to create multiple instances of the ajax request
	doAjaxGet: function(request, pars, successCallBack, options){
		options = options || {};
		new HP.Ajax('get', request, pars, successCallBack, options).makeCall();
	},
	doAjaxPost: function(request, pars, successCallBack, options){
		options = options || {}; 
		new HP.Ajax('post', request, pars, successCallBack, options).makeCall();
	},
	getIdNumber: function(element){
		element = $(element);
		if(element){
			return element.readAttribute('id').replace(/[^0-9]/g, '');
		}
		return null;
	},
	reload: function(){
		window.location.reload();
	},
	cleanElement: function(node){
		if(node){
			while(node.firstChild)
				node.removeChild(node.firstChild);
		}
	},
	getWindowHeight: function(){
		return ((Prototype.Browser.IE) ? document.body.clientHeight : window.innerHeight) + 
			this.getScroll().y;
	},
	getWindowWidth: function(){
		return (Prototype.Browser.IE) ? document.body.clientWidth : window.innerWidth;
	},
	getScroll: function() {
		var scr = {x:0, y:0};
	  	if( typeof( window.pageYOffset ) == 'number' ) {
			//Netscape compliant
	    	scr.y = window.pageYOffset;
	    	scr.x = window.pageXOffset;
	  	} else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
	    	//DOM compliant
	    	scr.y = document.body.scrollTop;
	    	scr.x = document.body.scrollLeft;
	  	} else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
	    	//IE6 standards compliant mode
	    	scr.y = document.documentElement.scrollTop;
	    	scr.x = document.documentElement.scrollLeft;
	  	}
		return scr;
	},
	hideFlash: function(){
		$$('object').each(function(el){Element.setStyle(el,{visibility:'hidden'})});
		$$('embed').each(function(el){Element.setStyle(el,{visibility:'hidden'})});
		if(Prototype.Browser.IE6){
			$$('select').each(function(el){Element.setStyle(el,{visibility:'hidden'})});
		}
	},
	showFlash: function(){
		$$('object').each(function(el){Element.setStyle(el,{visibility:'visible'})});
		$$('embed').each(function(el){Element.setStyle(el,{visibility:'visible'})});
		if(Prototype.Browser.IE6){
			$$('select').each(function(el){Element.setStyle(el,{visibility:'visible'})});
		}
	},
	logError: function(e){
		// If the callback encounters an error, tell us what happened.
		// Get a stack trace in FireFox, according to 
		// http://cfis.savagexi.com/articles/2007/05/08/what-went-wrong-with-my-javascript
		if (typeof e == "string") {
			e = new Error(e);
		}
		var fullMessage = "";
		var stack = "";
		var uri = "";
		var line = "";
		try {
			fullMessage = e.name + ": " + e.message;
			stack = e.stack;
			line = e.lineNumber;
			uri = e.fileName;
		} catch (e2) {
		}
		this.log(fullMessage + "\n at " + uri + ": " + line + "\n" + stack);
	},
	log: function(message) {
		if(message.stack){
			this.logError(message)
			return;
		}
		message = "TIME: " + new Date() + "\n"
				+ "BROWSER: " + this.getBrowser() + "\n"
				+ "HTML VERSION: a8\n" 
				+ message;
		if(this.LOG_TO_WINDOW){
		   if (!this.log.window_ || this.log.window_.closed) {
		        this.log.window_ = window.open("logWindow", null, "width=400,height=200," +
		                              "scrollbars=yes,resizable=yes,status=no," +
		                              "location=no,menubar=no,toolbar=no");
		        if (!this.log.window_) return;
		        var doc = this.log.window_.document;
		        doc.write("<html><head><title>JumpPage Debug Log</title></head>" +
		                  "<body></body></html>");
		        doc.close();
		    }
		    var logLine = this.log.window_.document.createElement("pre");
		    logLine.appendChild(this.log.window_.document.createTextNode(message));
		    logLine.width = 80;
		    this.log.window_.document.body.appendChild(this.log.window_.document.createElement('hr'));
		    this.log.window_.document.body.appendChild(logLine);
		}
		if(this.LOG_TO_SERVER){
		    this.doAjaxPost("logJSError", {jserror: message});
		}
	},
	getBrowser: function(){
		if(Prototype.Browser.IE6){
			return "ie6";
		}else if(Prototype.Browser.IE7){
			return "ie7";
		}else if(Prototype.Browser.Gecko){
			return "ff";
		}else{
			return undefined;
		}
	},
	getCookie: function(cookieName){
		var cookies = document.cookie.split(';');
		var cookieObj = {};
		for(var i = 0; i < cookies.length; i++){
			var parts = cookies[i].split('=');
			if(unescape(parts.first().strip()) == cookieName){
				return unescape(parts.last().strip());
			}
		}
		return undefined;
	}
}

Object.extend(Event,{ 
	delayedObserver: function(element, eventName, callback, delay){
		Event.observe(element, eventName, function(){
			setTimeout(callback, delay);
		});
	}
});

/**
 * Pop-up dialog object
 * Options:
 * 			openTrigger: rel value for DOM elements that should open the dialog when clicked
 * 			closeTrigger: rel value for DOM elements that should close the dialog when clicked
 * 			onShow: function called after the dialog is displayed
 * 			onClose: function called after the dialog is hidden
 * 			masking: true = mask the background with a grey filter; false = no mask
 * 			position: {top: top offset, left: left offset} or 'center' to center on the screen
 */
HP.Dialog = Class.create({
	initialize: function(dialog, options){	
		HP.Dialog.duration = 0.5;	
		this.dialog = $(dialog);
		this.options = options || {};
		if(!HP.Dialog.zindex){
			HP.Dialog.zindex = 100;
		}
		if(!HP.Dialog.mask){
			HP.Dialog.mask = new Element('div', {style: 'display:none;'}).update('   ');
			HP.Dialog.mask.addClassName('popupOverlay');
			document.body.appendChild(HP.Dialog.mask);
		}
		this.hideHandler = this.hide.bind(this);
		this.showHandler = this.show.bind(this);
		if(this.options.openTrigger){
			this.registerTrigger(this.options.openTrigger, this.showHandler);
		}
		if(this.options.closeTrigger){
			this.registerTrigger(this.options.closeTrigger, this.hideHandler);
		}
		this.registerTrigger('closeDialog', this.hideHandler);
	},
	registerTrigger: function(triggerRel, callback){
		var triggers = $$('[rel=' + triggerRel + ']');
			for(var i = 0; i < triggers.length; i++){
				Event.observe(triggers[i], 'click', callback);
			}
	},
	destroy: function(){
		if(this.options.openTrigger){
			this.unregisterTrigger(this.options.openTrigger, this.showHandler);
		}
		if(this.options.closeTrigger){
			this.unregisterTrigger(this.options.closeTrigger, this.hideHandler);
		}
		this.unregisterTrigger('closeDialog', this.hideHandler);
		for(key in this){
			delete this[key];
		}
		delete this;
	},
	unregisterTrigger: function(triggerRel, callback){
		var triggers = $$('[rel=' + triggerRel + ']');
			for(var i = 0; i < triggers.length; i++){
				Event.stopObserving(triggers[i], 'click', callback);
			}
	},
	show: function(){
		HP.Dialog.zindex++;
		this.setMask();
		if(this.options.position){
			if(typeof this.options.position == 'object'){
				this.setPosition(this.options.position);
			}else if(this.options.position == 'center'){
				this.center();
			}
		}else{
			Element.setStyle(this.dialog, {zIndex: ++HP.Dialog.zindex});
		}
		HP.hideFlash();
		if(!Prototype.Browser.IE6){
			if(this.options.masking){
				Effect.Appear(HP.Dialog.mask, {duration: HP.Dialog.duration});
			}
			Effect.Appear(this.dialog, {duration: HP.Dialog.duration});
		}else{
			if(this.options.masking){
				Element.show(HP.Dialog.mask);
			}
			Element.show(this.dialog);
		}
		if(this.options.onShow){
			this.options.onShow();
		}
	},
	hide: function(){
		if(!Prototype.Browser.IE6){
			if(this.options.masking){
				Effect.Fade(HP.Dialog.mask, {	duration: HP.Dialog.duration, 
												afterFinish: HP.showFlash});
			}else{
				HP.showFlash();
			}
			Effect.Fade(this.dialog, {duration: HP.Dialog.duration});
		}else{
			if(this.options.masking){
				Element.hide(HP.Dialog.mask);
			}
			Element.hide(this.dialog);
			HP.showFlash();
		}
		if(this.options.onClose){
			this.options.onClose();
		}
	},
	center: function(){
		var diaDim = Element.getDimensions(this.dialog);
		var winDim = {width: HP.getWindowWidth(), height: HP.getWindowHeight()};
		var position = {left: (winDim.width - diaDim.width) / 2, 
						top: (winDim.height - diaDim.height) / 2};
		this.setPosition(position);
	},
	setMask: function(){
		if(this.options.masking){
			var winDim = {width: HP.getWindowWidth() + Math.max(document.documentElement.scrollWidth,document.body.scrollWidth), 
						height: HP.getWindowHeight() + Math.max(document.documentElement.scrollHeight,document.body.scrollHeight)};
			Element.setStyle(HP.Dialog.mask, {position: 'absolute', 
											zIndex: HP.Dialog.zindex, 
											left: '0px', 
											top: '0px',
											height: winDim.height + 'px',
											width: winDim.width + 'px'});
		}
	},
	setPosition: function(position){
		Element.setStyle(this.dialog, {position: 'absolute', 
										zIndex: ++HP.Dialog.zindex, 
										left: position.left + 'px', 
										top: position.top + 'px'});
	}
});



/**
 * AJAX request
 * 
 * Sends an AJAX request to the server.  The request is sent again on failure.
 * The retryObject indicates if the request should be retried on failure.
 * If the parameter is null or omitted from the arguments, no retries are 
 * attempted.
 * The retryObject includes the retryRate (time between retries in ms) and
 * the displayMessage (message displayed int the error pop-up.)
 * If the displayMessage is null, no pop-up is shown.
 */
HP.Ajax = Class.create({
	initialize: function(method, request, pars, successCallBack, options){
		this.method = method;
		this.request = request = 'ajax/' + request + '.action';
		this.pars = pars;
		this.successCallBack = (successCallBack) ? successCallBack : function(){};
		this.options = options;
		this.count = 0;
	},
	makeCall: function(){
		this.pars['rand'] = new Date().getTime();
		new Ajax.Request( this.request, 
				{	method: this.method, 
				    parameters: this.pars, 
				    onSuccess: this.wrappedSuccess.bind(this),
				    onFailure: this.failureHandler.bind(this)
				}
		);
	},
	wrappedSuccess: function(response){
		try {
			if(response.status == 0){
				this.failureHandler();
				return;
			}
			var rt = response.responseText.strip();
			// must return false for any redirects because an attempt to call
			// successCallBack after a redirect will send a rogue logError
			// ajax request with a bad remember-me cookie
			if(rt.startsWith("SessionTimedout")){
				window.location.href = 'sessionTimeout.jsp';
				return false;
			}else if(rt.toUpperCase().startsWith("ERROR")){
				HP.reload();
				return false;
			}else if(rt.startsWith("<!DOCTYPE")){
				throw{	name:"AJAX error",
						message:this.request + " AJAX request failed."};
			}
			this.successCallBack(response);
		} catch (e) {
			HP.logError(e);
			HP.logError(callingPoint);
		}
	},
	failureHandler: function(){
		if(this.options.rate && (this.count++ * this.options.rate < 300000)){ // timeout after 5 mins
        	setTimeout(this.makeCall.bind(this), this.options.rate);
		}
	}
});


HP.Location = Class.create({
	initialize: function(loc){
		this.city = loc.city || loc.readAttribute('city');
		this.state = loc.state || loc.readAttribute('state');
		this.country = loc.country || loc.readAttribute('country');
		this.zipcode = loc.zipcode || loc.readAttribute('zipcode');
		this.citycode = loc.citycode || loc.readAttribute('citycode');
		this.primary = loc.primary || loc.readAttribute('primary');
	},
	appendAttributes: function(element){
		element.city = this.city;
		element.state = this.state;
		element.country = this.country;
		element.zipcode = this.zipcode;
		element.citycode = this.citycode;
		element.primary = this.primary;
	},
	toString: function(){
		var str = this.city;
		if(this.state){
		  str += ', ' + this.state;
		}
		if(this.country){
			str += ', ' + this.country;
		}
		return str;
	},
	toJSON: function(){
		var json = {};
		if(this.city){
			json['city'] = this.city;
		}
		if(this.state){
			json['state'] = this.state;
		}
		if(this.country){
			json['country'] = this.country;
		}
		if(this.zipcode){
			json['zipCode'] = this.zipcode;
		}
		if(this.citycode){
			json['cityCode'] = this.citycode;
		}
		if(this.primary){
			json['primary'] = this.primary;
		}
		return Object.toJSON(json);
	}
	
});

HP.IE6Warning = function(){
	new HP.Dialog($('ie6Warning'),{masking: true, position:'center'}).show();
} 
if(Prototype.Browser.IE6){
	document.observe('dom:loaded',HP.IE6Warning);
}
