var usePrototype = typeof(Prototype) != 'undefined';
usePrototype = false;	// force AJAX/JSON to use YUI

var useBase64 = true;

var nmAjaxServiceUrl = "/ajaxservice";


function log(message) {
  if (!log.window_ || log.window_.closed) {
    var win = window.open("", null, "width=400,height=200," +
      "scrollbars=yes,resizable=yes,status=no," +
      "location=no,menubar=no,toolbar=no");
    if (!win) return;
    var doc = win.document;
    doc.write("<html><head><title>Debug Log</title></head>" +
              "<body></body></html>");
    doc.close();
    log.window_ = win;
  }

  var logLine = log.window_.document.createElement("div");
  logLine.appendChild(log.window_.document.createTextNode(message));
  log.window_.document.body.appendChild(logLine);
}
/*
function dumpProps(obj, parent, showFunctions, useLog) 
{
   // Go through all the properties of the passed-in object
   if (useLog) log("------");
   for (var i in obj) 
   {
   	  var value = obj[i];
   	  if (typeof(value) != 'function' || showFunctions)
   	  {
	      // if a parent (2nd parameter) was passed in, then use that to
	      // build the message. Message includes i (the object's property name)
	      // then the object's property value on a new line
	      if (parent) { var msg = parent + "." + i + "\n" + value; } else { var msg = i + "\n" + value; }
	      // Display the message. If the user clicks "OK", then continue. If they
	      // click "CANCEL" then quit this level of recursion
	      if (useLog)
	      {
	      	  log(msg);
	      }
	      else
	      {
	      	  if (!confirm(msg)) { return; }
	      }
	      
	      // If this property (i) is an object, then recursively process the object
	      if (typeof value == "object") 
	      {
	         if (parent) { dumpProps(value, parent + "." + i, showFunctions, useLog); } 
	         else { dumpProps(value, i, showFunctions, useLog); }
	      }
      }
   }   
   
   if (useLog && !parent) log("------");
}
*/

var NMAjax =
{
	propertyCount: function(obj)
	{
		var cnt = 0;
		for (p in obj)
		{
			if (typeof(obj[p]) != 'function')
				++cnt;
		}
		
		return(cnt);
	},
	
	isArray: function(obj)
	{
	 	return(obj != null && typeof obj == "object" && 'splice' in obj && 'join' in obj);
	},

	isObject: function(obj)
	{
		if (this.isArray(obj))
			return(false);
			
		return(typeof(obj) == 'object');
	},
	
	copyObject: function(from, to)
	{
		var x;
		for (x in from)
			to[x] = from[x];
			
		return(to);
	},
	
	cloneObject: function(obj)
	{
		var newObj;
		if (typeof(obj.objectType) == 'function')
		{
			var exp = "new " + obj.objectType() + "()";
			newObj = eval(exp);
		}
		else
		{
			newObj = new Object();
		}
		
		NMAjax.copyObject(obj, newObj);
		return(newObj);
	},

	addTypeToObject: function(obj)
	{
		if (typeof(obj.objectType) == 'function')
		{	    
			var type = obj.objectType();
			var typedObj = new Object();
			typedObj[type] = obj;
			return(typedObj);
		}
			
	    return(obj);
	},

	removeTypeFromObject: function(obj)
	{					
		var p;
		for (p in obj)
		{
			var o = obj[p];
			if (this.isArray(o) || this.isObject(o))
			{			
				var exp = "new " + p + "()";
				try
				{
					if (this.isArray(o))
					{
						var newObj = new Array(o.length);
						for (var i = 0; i < o.length; ++i)
						{
							var arrayElem = eval(exp);
							this.copyObject(o[i], arrayElem);
							newObj[i] = this.untypeObject(arrayElem);
						}
					}
					else
					{
						var newObj = eval(exp);
						this.copyObject(o, newObj);
						newObj = this.untypeObject(newObj);
					}
					
					obj = newObj;
				}
				catch(err)
				{
				}
				
				break;
			}
		}
		
		return(obj);
	},

	typeArrayObject: function(obj)
	{			
		var type = null;
		for (p in obj)
		{
			var value = obj[p];
			if (this.isObject(value))
			{
				type = value.objectType();
				break;
			}
		}
		
		if (type != null)
		{
			var o = new Object();
			o[type] = obj;
			obj = o;
		}
		
		return(obj);
	},

	typeObject: function(obj, level)
	{
		if (typeof(obj.convertOnSend) == 'function')
			obj.convertOnSend();
			
		var p;
		for (p in obj)
		{
			var value = obj[p];
			if (this.isArray(value))
				obj[p] = this.typeArrayObject(value);
			else if (this.isObject(value))
				obj[p] = this.typeObject(value, level + 1);
		}
		
		if (level == 0)
			obj = this.addTypeToObject(obj);
			
		return(obj);
	},

	untypeObject: function(obj)
	{
		if (obj.hasOwnProperty("zzStringMapzz"))
		{
			var o = new StringMap();
			delete obj.zzStringMapzz;
			this.copyObject(obj, o);
			obj = o;
		}
		
		var p;
		for (p in obj)
		{
			var value = obj[p];
			if (this.isObject(value) || this.isArray(value))
				obj[p] = this.untypeObject(value);
		}
		
		var ret = obj;
		if (this.propertyCount(ret) == 1)
			ret = this.removeTypeFromObject(obj);		
			
		if (typeof(ret.convertOnReceive) == 'function')
			ret.convertOnReceive();
			
		return(ret);
	},
	
	eventMap: {},	
	eventIdCount: 0,
	
	addEventListener: function(eventName, callback)
	{
		if (typeof(callback) == 'object' && !callback.hasOwnProperty('callback'))
		{
			alert("Event callback object has no callback function");
			return(null);
		}
		
		var eventId = "event" + (++this.eventIdCount);
		if (this.eventMap.hasOwnProperty(eventName))
		{
			var obj = this.eventMap[eventName];
			obj[eventId] = callback;
		}
		else
		{
			var o = new Object();
			o[eventId] = callback;
			this.eventMap[eventName] = o;
		}
		
		return(eventId);
	},
	
	removeEventListener: function(eventName, eventId)
	{
		if (eventMap.hasOwnProperty(eventName))
		{
			var obj = eventMap[eventName];
			if (obj.hasOwnProperty(eventId))
			{
				delete obj[eventId];
				return(true);
			}
		}
		
		return(false);
	},
	
	dispatchEvents: function(obj)
	{
		NMAjax.dispatchLifecycleEvents(NMAjax.Lifecycle_Dispatch_Event, obj);
		for (eventName in obj)
		{
			if (this.eventMap.hasOwnProperty(eventName))
			{
				var eventObj = obj[eventName];
				var callbacks = this.eventMap[eventName];
				for (eventId in callbacks)
				{
					var eventHandler = callbacks[eventId];
					if (typeof(eventHandler) == 'function')
						eventHandler(eventObj, eventName, eventId, null);
					else
						eventHandler.callback(eventObj, eventName, eventId, eventHandler);
				}
			}
		}
	},
	
	Lifecycle_Request_Event: "lifecycleRequest",					// before request is submitted
	Lifecycle_Dispatch_Event: "lifecycleDispatch",					// before response events are dispatched
	Lifecycle_Response_Event: "lifecycleResponse",					// after response events are dispatched
	Lifecycle_Post_Response_Event: "lifecyclePostResponse",			// after callers response function called
	Lifecycle_Error_Event: "lifecycleError",						// when error response received
	Lifecycle_Post_Error_Event: "lifecyclePostError",				// after callers error function called
	Lifecycle_Javascript_Error: "lifecycleJavascriptError",			// Javascript error processing response
	lifecycleEvents: {},
	
	addLifecycleListener: function(lifecycleEvent, callback)
	{
		if (typeof(callback) == 'object' && !callback.hasOwnProperty('callback'))
		{
			alert("Event callback object has no callback function");
			return(null);
		}
		
		if (this.lifecycleEvents.hasOwnProperty(lifecycleEvent))
		{
			var obj = this.lifecycleEvents[lifecycleEvent];
			obj.push(callback);
		}
		else
		{
			var o = new Array();
			o.push(callback);
			this.lifecycleEvents[lifecycleEvent] = o;
		}
	},
	
	dispatchLifecycleEvents: function(lifecycleEvent, obj)
	{
		if (this.lifecycleEvents.hasOwnProperty(lifecycleEvent))
		{
			var arrHandlers = this.lifecycleEvents[lifecycleEvent];
			for (var i = 0; i < arrHandlers.length; ++i)
			{
				var eventHandler = arrHandlers[i];
				if (typeof(eventHandler) == 'function')
					eventHandler(obj, lifecycleEvent);
				else
					eventHandler.callback(obj, lifecycleEvent, eventHandler);				
			}
		}
	},
	
	lockpage:function(){
		var pageBody = document.getElementById("pagebody");
		var pageHeight = pageBody ? pageBody.offsetHeight : 0;
		
		document.body.style.cursor="wait";
		var locker = document.getElementById("pagelock");		
		if( locker != null && locker != "undefined"){
			locker.style.zIndex="299";
			locker.style.display="block";			
			locker.style.height=pageHeight+"px";	
			locker.style.width=Screen.viewwidth()+"px";				
		}
	},
	
	releasepage:function(){
		var locker = document.getElementById("pagelock");
		if( locker != null && locker != "undefined"){
			locker.style.display="none";
			locker.style.zIndex="-1";
			locker.style.height = locker.style.width ="0px";
		}
		document.body.style.cursor="auto";		
	},
	
	//***************************** Base 64 Utilities
	// we are using a modified base64 where end filler chars use '$' rather than '='
	// since '=' causes problems in forming the query string of a URL request.
	_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789*/$",
	
	base64_encode : function(input) 
	{
		var output = "";
		var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
		var i = 0;
 
		input = NMAjax._utf8_encode(input);
 
		while (i < input.length) 
		{
 
			chr1 = input.charCodeAt(i++);
			chr2 = input.charCodeAt(i++);
			chr3 = input.charCodeAt(i++);
 
			enc1 = chr1 >> 2;
			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
			enc4 = chr3 & 63;
 
			if (isNaN(chr2)) 
			{
				enc3 = enc4 = 64;
			} 
			else if (isNaN(chr3)) 
			{
				enc4 = 64;
			}
 
			output = output +
			NMAjax._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
			NMAjax._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
		}
 
		return output;
	},
	
	base64_decode : function (input) 
	{
		var output = "";
		var chr1, chr2, chr3;
		var enc1, enc2, enc3, enc4;
		var i = 0;
 
		input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
 
		while (i < input.length) 
		{
			enc1 = NMAjax._keyStr.indexOf(input.charAt(i++));
			enc2 = NMAjax._keyStr.indexOf(input.charAt(i++));
			enc3 = NMAjax._keyStr.indexOf(input.charAt(i++));
			enc4 = NMAjax._keyStr.indexOf(input.charAt(i++));
 
			chr1 = (enc1 << 2) | (enc2 >> 4);
			chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
			chr3 = ((enc3 & 3) << 6) | enc4;
 
			output = output + String.fromCharCode(chr1);
 
			if (enc3 != 64) 
			{
				output = output + String.fromCharCode(chr2);
			}
			if (enc4 != 64) 
			{
				output = output + String.fromCharCode(chr3);
			}
		}
 
		output = NMAjax._utf8_decode(output);
		return output;
	},
	
	// private method for UTF-8 encoding
	_utf8_encode : function (string) 
	{
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";
 
		for (var n = 0; n < string.length; n++) 
		{
			var c = string.charCodeAt(n);
 
			if (c < 128) 
			{
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) 
			{
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else 
			{
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}
		}
 
		return utftext;
	},
	
	// private method for UTF-8 decoding
	_utf8_decode : function (utftext) 
	{
		var string = "";
		var i = 0;
		var c = c1 = c2 = 0;
 
		while ( i < utftext.length ) 
		{ 
			c = utftext.charCodeAt(i);
 
			if (c < 128) 
			{
				string += String.fromCharCode(c);
				i++;
			}
			else if((c > 191) && (c < 224)) 
			{
				c2 = utftext.charCodeAt(i+1);
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
				i += 2;
			}
			else 
			{
				c2 = utftext.charCodeAt(i+1);
				c3 = utftext.charCodeAt(i+2);
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			} 
		}
 
		return string;
	},
	//*****************************
	
	ajaxService: function(obj, funcResp, funcError, serviceName, callObj, useSSL)
	{		
		var url = nmAjaxServiceUrl;
		if (useSSL)
		{
			url = "https://" + document.location.hostname;
			if ("" != serverHttpsPort)
				url += ":" + serverHttpsPort;
				
			 url += nmAjaxServiceUrl;
		}
			
		NMAjax.dispatchLifecycleEvents(NMAjax.Lifecycle_Request_Event, obj);
		var origObj = NMAjax.cloneObject(obj);
		obj = this.typeObject(obj, 0);
		NMAjax.lockpage();
		var releaselock = this.releasepage;
		if (usePrototype)
		{
			var json = $H(obj).toJSON();
			if (useBase64)
				json = "$b64$" + NMAjax.base64_encode(json);
				
			var params = { data: json };
			if (null != serviceName)
				params.service = serviceName;
							
			var req = new Ajax.Request(url,
				{
					nmRespFunc:		funcResp,
					nmErrorFunc:	funcError,
					nmCallObj: 		callObj,
					nmOrigReq:		origObj,
					method: 		"post",
					parameters:		params,								
					onSuccess:		function(response)
									{
										try
										{
								  			var resp = response.responseText;
								  			var obj = resp.evalJSON();
								  			obj = NMAjax.untypeObject(obj);
								  			NMAjax.dispatchEvents(obj);
											NMAjax.dispatchLifecycleEvents(NMAjax.Lifecycle_Response_Event, obj);
											var req = response.request;				
																																
								  			if (null != req.options.nmRespFunc){
								  				if( null != req.options.nmCallObj ){					  					
								  					req.options.nmRespFunc(req.options.nmCallObj,obj);								  					
								  				}else{
								  					req.options.nmRespFunc(obj);									  									  					
									  			}								  			
									  		}
											NMAjax.dispatchLifecycleEvents(NMAjax.Lifecycle_Post_Response_Event, obj);
									  		NMAjax.releasepage();	
								  		}
								  		catch (e)
								  		{
					  						NMAjax.releasepage();	
											var err = e;
											err.responseText = response.responseText;
											err.status = response.status;
											err.statusText = response.statusText;
											err.req = response.request.options.nmOrigReq;		
											if (err.req.objectType() != 'ClientErrorBean')
												NMAjax.dispatchLifecycleEvents(NMAjax.Lifecycle_Javascript_Error, err);
								  		}
									},
					onFailure:		function(response)
									{
										var req = response.request;
										var err = new Object();
										err.status = response.status;
										err.statusText = response.statusText;
										err.req = req.options.nmOrigReq;				
										NMAjax.dispatchLifecycleEvents(NMAjax.Lifecycle_Error_Event, err);
							  			if (null != req.options.nmErrorFunc){
							  				if( null != req.options.nmCallObj ){
							  					req.options.nmErrorFunc(req.options.nmCallObj,err);
							  					document.body.style.cursor="auto";			
							  				}else{
											  	req.options.nmErrorFunc(err);	
											  	document.body.style.cursor="auto";							
												}
										  }		
    									  NMAjax.dispatchLifecycleEvents(NMAjax.Lifecycle_Post_Error_Event, err);
										  NMAjax.releasepage();			
									}								
				}
			);		
		}
		else 	// assume we are using yui
		{
			var json = YAHOO.lang.JSON.stringify(obj);
			if (useBase64)
				json = "$b64$" + NMAjax.base64_encode(json);
				
			var params = "data=" + json;
			if (null != serviceName)
				params += "&service=" + serviceName;
				
			var callback = {
								success: 		function(response)
										 		{
										 			try
										 			{
											 			var resp = response.responseText;
											 			var obj = YAHOO.lang.JSON.parse(resp);
								  						obj = NMAjax.untypeObject(obj);
											  			NMAjax.dispatchEvents(obj);
														NMAjax.dispatchLifecycleEvents(NMAjax.Lifecycle_Response_Event, obj);
								  						if (null != this.nmRespFunc)
								  						{
								  							if( null != this.nmCallObj )
								  							{
								  								this.nmRespFunc.call(this.nmCallObj, obj);
								  								document.body.style.cursor="auto";
								  							}
								  							else
								  							{
								  							  this.nmRespFunc(obj);
								  							  document.body.style.cursor="auto";
								  						    }
								  						}
														NMAjax.dispatchLifecycleEvents(NMAjax.Lifecycle_Post_Response_Event, obj);
								  						NMAjax.releasepage();	
											  		}
											  		catch (e)
											  		{
								  						NMAjax.releasepage();	
														var err = e;
														err.responseText = response.responseText;
														err.status = response.status;
														err.statusText = response.statusText;
														err.req = this.nmOrigReq;		
														if (err.req.objectType() != 'ClientErrorBean')
															NMAjax.dispatchLifecycleEvents(NMAjax.Lifecycle_Javascript_Error, err);
											  		}
										 		},
							 	failure: 		function(response)
							 					{
													var err = new Object();
													err.status = response.status;
													err.statusText = response.statusText;
													err.req = this.nmOrigReq;
													NMAjax.dispatchLifecycleEvents(NMAjax.Lifecycle_Error_Event, err);
													if( null != this.nmErrorFunc){
														if( null != this.nmCallObj ){
															this.nmErrorFunc.call(this.nmCallObj,err);		
															document.body.style.cursor="auto";
														}else{
															this.nmErrorFunc(err);	
															document.body.style.cursor="auto";	
														}
													}
                                                    NMAjax.dispatchLifecycleEvents(NMAjax.Lifecycle_Post_Error_Event, err);
													NMAjax.releasepage();								
							 					},
								nmRespFunc:		funcResp,
								nmErrorFunc:	funcError,
								nmCallObj: 		callObj,
								nmOrigReq:      origObj			 										 				
						  }			
				
			YAHOO.util.Connect.initHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
			var trans = YAHOO.util.Connect.asyncRequest("POST", url, callback, params);			
		}
	},
	
	setInnerHtml: function(element, fragment)
	{
		if (typeof(element) == 'string')
			element = document.getElementById(element);
			
 		element.innerHTML = fragment;
		var d = element.getElementsByTagName("script");
		var t = d.length
		for (var x = 0; x < t; x++)
		{
			var newScript = document.createElement('script');
			newScript.type = "text/javascript";
			if ("" != d[x].src)
				newScript.src = d[x].src;
			else
				newScript.text = d[x].text;					
				
			element.appendChild (newScript); 				
		}
	}
}

function NM_AjaxService(obj, funcResp, funcError, serviceName)
{
	NMAjax.ajaxService(obj, funcResp, funcError, serviceName);
}

var Screen = {
	viewheight:function() {
		if (!window.opera && (!document.compatMode || document.compatMode=="CSS1Compat")) {return document.documentElement.clientHeight;}
		else if (document.compatMode && !window.opera) {return document.body.clientHeight;}
		else{return window.innerHeight;}
	},
	viewwidth:function(){
		if (!document.compatMode || document.compatMode=="CSS1Compat") {return document.documentElement.clientWidth;}
		else if (document.compatMode) {return document.body.clientWidth;}
		else{ window.innerWidth; }
	}
};

/**
 * The client error bean is designed to encapsulate basic information about javascript errors that occur on the site
 * in order to attempt to send the information to the server for logging.  Any failure in this object should be ignored.
 * @param e - the error object
 * @param cmpnt - A string value denotes what occurred when the error happened.  This is used as an indication of 
 *                what action the user was performing when the error occurred.
 * @param msg - A short but friendly message to be included as the error when a critical error is encounter.  This should
 *              be worded to give the user a general idea of what happend.  This value is passed to the server, but 
 *              but only displayed when an unrecoverable event occurs in the alert.
 * NOTE: FF (only) includes a property on the error object which holds some basic stack trace information, however the
 * json string was unable to parse this data properly resulting in a failed error message. 
 */
function ClientErrorBean(){};
ClientErrorBean.prototype.objectType = function() { return("ClientErrorBean"); }
function NMError(e, cmpnt, msg){	
	if (null == cmpnt) cmpnt = "";
	if (null == msg) msg = "";
	this.err = new ClientErrorBean();		
	this.err["jsMessage"] = e.message;
	this.err["jsFileName"] = escape(e.fileName);
	this.err["jsLineNumber"] = e.lineNumber;
	this.err["jsName"] = e.name;
	this.err["jsNumber"] = e.number;	
	this.err["jsDescription"] = e.description;  
	this.err["jsComponent"] = cmpnt;
	this.err["jsInfoMessage"] = msg;		
}
NMError.prototype={
	critical:function(){ 
		try{ this.reportError(); }
		catch(e){}
		finally{ window.location = "/common/store/clienterror.jhtml?jsErrMsg="+encodeURI(this.err["jsInfoMessage"]); }
	},
	recoverable:function(){ try{ this.reportError(); }catch(e){  } },
	responsefailure:function(){ 
		try{ NMAjax.releasepage(); }
		catch(e){}
		finally{
			this.displayAlert();
		}		
	},
	displayAlert: function()
	{
		alert("We are sorry, but we were unable to complete your request at this time.  Please try your request again.  If you "+
				"continue to encounter difficulty please contact our customer care department. \n\n"+this.err["jsMessage"]);
	},
	reportError:function(){	try{NMAjax.ajaxService(this.err,null,null);}catch(e){ }}
};
/**
 * DocWriter is designed to provide a level of protection from third party script using document.write on
 * files returned from ajax references.  When a page is loading and document is not fully processed document.write
 * will add to the loading the document when the script executes, however using document.write after the dom is
 * fully loaded results in the replacement of the entire dom document with the content of the document.write
 * function.  This object provides a function 'write' which creates a new element with string passed to the function
 * and appends this as the last child of the <body> element.  Once the dom is fully loaded the definition of
 * document.write is changed to this new function.
 */
var DocWriter = {
	write:function(data){
		try{
				var dataElem = document.createElement("div");
				var dataElemId = YAHOO.util.Dom.generateId(dataElem);
				var nodes = YAHOO.util.Dom.getElementsBy(
					function(elem){ return elem.nodeName==="body" || elem.nodeName==="BODY";} , "body" , document );
				YAHOO.util.Dom.insertAfter(dataElem, YAHOO.util.Dom.getLastChild(nodes[0]));
				NMAjax.setInnerHtml(dataElemId, data);
		}catch(e){
			alert(e);
		}
	},
	definewrite:function(){
		document.nativewriter = document.write;
		document.write=DocWriter.write;
	}
}
YAHOO.util.Event.onDOMReady( DocWriter.definewrite );
