/**
 * @fileOverview This file contains all necessary classes and functions to generate a Dialog in MapQuest's api.
 * @author <a href="mailto:sunder@spatialinteractive.com">Sunder</a>
 */

/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
(function() { 

	// declare local shortcut vars
	var _mu, _dm, _dc;
	
	// declare local private html strings
	var _HTML = {
		alert    : '<div class="alertDialog">' + 
                       '<div class="msg">${msg}</div>' + 
                       '<div class="btnWrapper">' + 
                           '<a href="javascript:void(0);" mqattachevent="close" class="btnBeige"><span>Ok</span></a>' + 
                       '</div>' + 
                   '</div>',
		confirm  : '<div class="confirmDialog">' + 
                       '<div class="msg">${msg}</div>' + 
                       '<div class="btnWrapper">' + 
                           '<a href="javascript:void(0);" mqattachevent="close" class="btn"><span>Cancel</span></a>' + 
                           '<a href="javascript:void(0);" mqattachevent="confirm" class="btn"><span>Ok</span></a>' + 
                       '</div>',
		loading  : '<div class="loadingDialog">' + 
                       '<div class="msg">${msg}</div>' + 
                   '</div>',
		dialog   : '<div class="mqDialog ${classname}" id="${dialogid}">' +
                       '<table cellspacing="0"><tbody>' +
                       '<tr><td class="tl"></td><td class="tc"></td><td class="tr"></td></tr>' +
                       '<tr><td class="ml"><div></div></td><td class="mc" id="${dialogid}_content"></td><td class="mr"><div></div></td></tr>' +
                       '<tr><td class="bl"></td><td class="bc"></td><td class="br"></td></tr>' +
                       '</tbody></table>' +
                   '</div>',
		arrow    : '<div class="arrow ${arrowDirection}"><div></div></div>',
		close : '<a href="javascript:void(0);" id="dialog_1_close" class="close"><div></div></a>',
		defaultClass : "mqDialog"
	};



	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/**
	 * @namespace
	 * This namespace contains the functions, methods, and classes necessary to build and manage mapquest dialogs.  
	 * The functions that exist at the root of this namespace (open, close, closeAll, & update), are basically a 
	 * bridge / pass thru connecting directly to the m2.dialog._Manager object.
	 *
	 * @example
	 * DIALOG CREATION:
	 *     // initialize the dialog
	 *     var dialog1 = m2.dialog.open({ 
	 *         content :  "this is a test<br /><br />" + 
	 *                    "<a href='javascript:void(0)' onclick='m2.dialog.close();>Close</a>",
	 *         size : {width:500,height:"auto"}
	 *     });
	 *     
	 *     
	 * UPDATE THE TOPMOST DIALOG:
	 *     // step 1 : create a dialog
	 *     var dialog1 = m2.dialog.open({ 
	 *         dialogName : "dialog",
	 *         content :  "this is a test<br /><br />" + 
	 *                    "<a href='javascript:void(0)' onclick='m2.dialog.close();>Close</a>",
	 *         size : {width:500,height:"auto"}
	 *     });
	 * 
	 *     // step 2 : update a dialog
	 *     m2.dialog.udpate({ 
	 *         content :  "this is a test 2",
	 *         size : {width:300,height:200}
	 *     });
	 *     
	 *     
	 * UPDATE A SPECIFIC DIALOG:
	 *     // step 1 : create two dialogs
	 *     var dialog1 = m2.dialog.open({ 
	 *         dialogName : "dialog1",
	 *         content :  "this is a test 1111111",
	 *         size : {width:500,height:"auto"}
	 *     });
	 *     
	 *     var dialog2 = m2.dialog.open({ 
	 *         dialogName : "dialog1",
	 *         content :  "this is a test 2222222",
	 *         size : {width:500,height:"auto"}
	 *     });
	 * 
	 *     // step 2 : update the first dialog by passing in its name
	 *     m2.dialog.udpate({ 
	 *         dialogName : "dialog1",
	 *         content :  "this is a test 2",
	 *         size : {width:300,height:200}
	 *     });
	 *     
	 *     // or step2 : or update the first dialog by calling update on the returned object
	 *     dialog1.update({ 
	 *         dialogName : "dialog1",
	 *         content :  "this is a test 2",
	 *         size : {width:300,height:200}
	 *     });
	 *     
	 */
	m2.dialog = {
		/**
		 * Function will create a dialog determine if it should overlay / replace another dialog, how to animate 
		 * it and will run it.
		 * @param {m2.dialog.Config} config  The dialog's configuration object
		 * @param {String|DomNode}          el      (optional) the id/domelement that we will use to position the dialog.
		 * @return {String}                         The id of the dialog 
		 */
		open: function(config,el) {
			if (el) {
				el.blur();
			}
			
			// test if this config has not been initialized propery
			if (!config._init) {
				config = new _dc(config);
			}
			return _dm.open(config,el);
		},

		/**
		 * Function will hide a dialog.
		 * @param {String|DOMElement} dialogId  (optional) the id of the dialog we want to close, or the element in
		 *                                      the dialog that was clicked.  The element clicked must be a child
		 *                                      of a dialog in order to close a dialog.  If the value is null / not 
		 *                                      passed, this function will close the topmost dialog.
		 */
		close : function(dialogId) {
			return _dm.close(dialogId);
		},

		/**
		 * Function will hide all showing dialogs.
		 */
		closeAll : function() {
			return _dm.closeAll();
		},

		/**
		 * Function will update the current dialog, or the passed in dialog based on the incoming config
		 * @param {m2.dialog.Config} newConfig      (optional) new configuration for the current dialog, 
		 *                                                 if not passed assume that old config has changed
		 * @param  {String}                 dialogToUpdate (optional) id of the the dialog we are updating
		 * @return {String}                                The id of the dialog that was updated
		 */
		update : function(newConfig,dialogToUpdate) {
			/* debugger; */
			return _dm.update(newConfig,dialogToUpdate);
		},

		/**
		 * The base z-index that we will start displaying dialog boxes at
		 * @param {Object} dialog
		 */
		baseZIndex : 100500,
		
		/**
		 * Updates the topmost dialog if it has an iframe in it
		 * @param {Object} data
		 */
		updateDialogIframe : function(data) {
			_dm.updateDialogIframe(data);
		},		

		/**
		 * Updated the dialogs content based on the passed in content
		 * @param {Object} dialogId
		 * @param {Object} content
		 */
		updateDialogContent : function(dialogId,content) {
			var d = _dm.getDialog(dialogId);
			if (_mu.isString(content)) {
				var c = document.createElement("div");
				c.innerHTML = content;
				content = c;
			}
			
			if (content.parentNode) {
				content = content.parentNode.removeChild(content);
			}
	
			d.contentEl.innerHTML = "";
			d.contentEl.appendChild(content);
		},

		/**
		 * Function will determine if a dialog exists
		 * @param {Object}     dialogId
		 * @return {boolean}   true if the dialog exists, false otherwise
		 */	
		hasDialog : function(dialogId) {
			return _dm.getDialog(dialogId) ? true : false;
		},

		/**
		 * 
		 * @param {Object} dialogId
		 */
		getDialog : function(dialogId) {
			return _dm.getDialog(dialogId);
		},

		/**
		 * Function will open a dropdown menu
		 * @param {String|HTMLElement} clickedEl
		 * @param {String|HTMLElement} content
		 * @param {boolean}            skipFocus whether or not you want the focuz logic to be skipped
		 */	
		openDropDown : function(content,clickedEl,skipFocus) {
			skipFocus = (skipFocus != null) ? skipFocus : true;
			return this.open({
	            dialogName: "dropdown",
	            content: content,
	            modal: false,
	            showCloseButton: false,
	            position:{el:clickedEl,align:{one:"b",two:"l"}},
	            overflow: "auto",
	            closeOnBackgroundClick: true,
	            dialogClass: "mqDialogDD",
	            skipFocus: skipFocus
	        });
		},

		/**
		 * Function will show a loading dialog
		 * @param {String} msg  (optional) the loading message.  Defaults to "Loading ..."
		 */
		loading: function(msg) {
			msg = msg || m2.Label.Loading + " ...";
			return this.open({
				dialogName: "loadingMessage",
				content: "<div class='loadingDialog'>" + msg + "</div>",
				modal: false,
				showCloseButton: false,
				position: {y: 300},
				closeOthers : false,
				dialogClass: "mqDialogYellow"      
			});
		},


		/**
		 * Function will hide the loading dialog
		 */
		hideLoading : function() {
			m2.dialog.close("loadingMessage");
		},


		/**
		 * Function will show an alert dialog
		 * @param {String} msg  the alert message
		 */	
		alert: function(msg) {
			var el = document.createElement("div");
			el.innerHTML = _mu.widget.replace(_HTML.alert,"msg",msg);
			_mu.widget.attachEvents(el,{close:{event:'click',fn:function() {m2.dialog.close("alertDialog");}}})
			m2.dialog.open({
				dialogName: "alertDialog",
				content: el,
				modal: false,
				showCloseButton: true,
				position: {y: 300},
				closeOthers : false
			});
		},
		
		/**
		 * Function will show a confirmation dialog and attach listeners to attach events based on confirmation
		 * @param {String}      msg  the description of the action that requires confirmation
		 * @param {FunctionRef} fnc  the function that will run on confirm
		 */
		confirm: function(msg,fnc) {
			if (!fnc) {
				this.alert(msg);
			}
			var el = document.createElement("div");
			el.innerHTML = _mu.widget.replace(_HTML.confirm,"msg",msg);
			_mu.widget.attachEvents(el,{
				close:{event:'click',fn:function() {m2.dialog.close("alertDialog");}},
				confirm:{event:'click',fn:fnc}
			})
			m2.dialog.open({
				dialogName: "alertDialog",
				content: el,
				modal: false,
				showCloseButton: true,
				position: {y: 300},
				closeOthers : false
			});			
			
		},
		
	    /**
	     * Funciton will apply fix to properly show cursors in form fields.
	     * @param {Object} wrapper
	     */
	    fixFieldCursors : function(wrapper) {
	        // firefox has problems showing cursors when positioning over different types of scrolled elements
	        // this workaround sets the div wrapper of each input to overflow auto, allowing the cursor to show.
	        if (m2.isFF) {
	            var el = m2.$(wrapper).getElementsByTagName('fieldset')[0];
	            var arr = m2.$(wrapper).getElementsByTagName('fieldset')[0].getElementsByTagName("div");
	            for (var i = 0; i < arr.length; i++) {
	                _mu.setStyle(arr[i], "overflow", "auto");
	            }
	        }
	    }
	};


	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/**
	 * @class
	 * This class is the configuration object used for the dialog.  All the initial values 
	 * here are the defaults for the dialog's look and behavior.  These should be overridden
	 * as needed before calling render.
	 * 
	 * The only really required element is the content used for the dialog.
	 * @constructor
	 * @param {Object} configOverride  - the object that will set the properties of the dialog
	 */
	m2.dialog.Config = function(configOverride) {
		var c = configOverride || {};
		/**
		 * variable indicating that this is a valid config
		 * @private
		 */
		this._init = true;

		/**
		 * An optional name that can be used to identify this particular dialog.  Defaults to "".
		 * @type String  
		 */
		this.dialogName = c.dialogName || "";

		/**
		 * The content of the dialog, can be a string of an HTML element.
		 * @type HTMLElement,String   
		 */
		this.content =  c.content || "";

		/**
		 * if true will disable the rest of the page.  i.e. the user can only interact with this dialog.  Defaults to false
		 * @type boolean  
		 */
		this.modal =  c.modal || false;

		/**
		 * The width and height in pixels or can be set to "auto".  Defaults to "auto".
		 * @type Object
		 */
		this.size = c.size || {width:"auto",height:"auto"};

		c.position = c.position || {};
		/**
		 * the x/y object {x,y} used to position the dialog.
		 * @type Object  
		 */
		this.position =  {
			x : (c.position.x !== null) ? c.position.x : null,
			y : (c.position.y !== null) ? c.position.y : null,
			ox : c.position.ox || 0,
			oy : c.position.oy || 0,
			el : m2.$(c.position.el) || null,
			align : {
				one: (c.position.align && c.position.align.one !== null) ? c.position.align.one : "",
				two: (c.position.align && c.position.align.two !== null) ? c.position.align.two : ""
			},
			fallback : {
				x: (c.position.fallback && c.position.fallback.x !== null) ? c.position.fallback.x : "",
				y: (c.position.fallback && c.position.fallback.y !== null) ? c.position.fallback.y : ""
			}
		};

		/**
		 * template  the html wrapper for this dialog.
		 * @type String
		 */
		this.dialogClass = c.dialogClass || "";

		/**
		 * if true will close the other dialogs.  Defaults to false;
		 * @type boolean  
		 */
		this.closeOthers =  (c.closeOthers !== null) ? c.closeOthers : false;

		/**
		 * determines if an arrow will show.  will show based on the position that the dialog is at
		 * @type boolean
		 */
		this.showArrow = (c.showArrow !== null) ? c.showArrow : false;

		/**
		 * The class of the background.  Used to show or hide the background
		 * @type String
		 */
		this.backgroundClass = c.backgroundClass || "mqDialogBackground";

		/**
		 * Object contains booleans indicating what actions if any should close this dialog.
		 * @type Object  
		 */
		this.closeOnBackgroundClick = c.closeOnBackgroundClick || false;

		/**
		 * Determines if the close button shows or not.  Defaults to true
		 * @type boolean
		 */
		this.showCloseButton = (c.showCloseButton !== null) ? c.showCloseButton : true;
        
        /**
         * Callback executed when the close button is cliked.
         */
        this.closeButtonCallback = c.closeButtonCallback || null;
		
		/**
		 * The id of the elment to focus on
		 * @type String
		 */
		this.focusId = c.focusId || null;
	
		/**
		 * Will cause the dialog to skip trying to find an element to focus on within it.  Defaults to false.
		 * @type Booelan
		 */
		this.skipFocus = c.skipFocus || false;
		
		/**
		 * Will force the dialog to remain at the desired position even if it overlaps the edges of the browser screen.
		 * Defaults to true.
		 * @type Boolean
		 */
		this.skipReposition = c.skipReposition || false;
	
		/**
		 * Property sets the css property for the content wrapper within the dialog.  Defaults to "hidden".
		 * @type String
		 */
		this.overflow = c.overflow;
	
		/**
		 * Determines the start opocity of the content
		 * @type int 
		 */
		this.contentOpacity = (c.contentOpacity !== null) ? c.contentOpacity : 1;
		
		/**
		 * Event that will fire when a dialog closes.
		 * @type FunctionRef
		 */		
		this.onclose = c.onclose || null;
	};


	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/**
	 * @class
	 * This class manages all currently showing dialogs.
	 * @static
	 * @private
	 */
	m2.dialog._Manager = {
			
		/**
		 * The dialogs that are currently showing
		 * @type Array
		 */
		dialogs : [],
		
		/**
		 * The dom node that is the background
		 * @type DomNode
		 */
		backgroundEl : null,
		
		/**
		 * variable to hold the dom node hacks necessary to prevent floating elements above our dialogs
		 * @type DomNode
		 * @private
		 */
		backgroundDomHack : null,
		
		/**
		 * ffMacListener  holds a reference to the listener on the window for ffmac hacks
		 * @type String
		 */
		ffMacListener : null,
		
		/**
		 * Tracks the state of the resize listener
		 * @type boolean
		 */
		_resizeListenerSet : false,
	
		/**
		 * Function will create a dialog, determine if it should overlay / replace another dialog, how to animate 
		 * it, and will open it.
		 * @param {m2.dialog.Config} config  The dialog's configuration object
		 * @param {String|DomNode}          el      (optional) the id/domnode used to position the dialog.
		 */
		open : function(config,el) {
			if (config.closeOthers) {
				this.closeAll();
			}
			if (config.dialogName && this.getDialog(config.dialogName)) {
				return this.update(config,config.dialogName,el);
			}
			var dialog = new m2.dialog._Dialog(config,this.dialogs.length,el);
			this.add(dialog);
			dialog.open();
			this.updateZIndexes();
			this.setPageResizeListener();
			return dialog;
		},
	
		/**
		 * Function will update the current dialog, or the passed in dialog based on the incoming config
		 * @param {m2.dialog.Config} config    the new config settings for the dialog
		 * @param {String}                  dialogId  (optional) the id / name of the dialog to update
		 * @param {String|DomNode}          el        (optional) the id/domnode used to position the dialog.
		 */
		update : function(config,dialogId,el) {
			if (this.dialogs.length === 0 && config) {
				return this.open(config);
			}
			// get the dialog
			var dialog = this.getDialog(dialogId || config.dialogName) || this.dialogs[this.dialogs.length - 1];

			// put the dialog on top
			this.remove(dialog);
			this.add(dialog);
			this.updateZIndexes();
	
			// update the dialog's look
			dialog.update(config);
			this.updateZIndexes();
	
			return dialog.id;
		},
	
		/**
		 * Function will hide a dialog.
		 * @param {String} dialogId  the id of the dialog we want to close
		 */
		close : function(dialogId) {
			var d;
			if (dialogId) {
				d = this.getDialog(dialogId);
				if (d) {
					// close methods unloads values, so call it after remove is run
					this.remove(d);
					d.close();
				}
			} else if (this.dialogs.length > 0) {
				d = this.dialogs.pop();
				d.close();
			}
			this.updateZIndexes();
			if (this.dialogs.length === 0) {
				this.removePageResizeListener();
			}
		},
	
		/**
		 * Function will hide all showing dialogs.
		 */
		closeAll : function() {
			for (var i = 0; i < this.dialogs.length; i++) {
				if (this.dialogs[i].config.dialogName != "formDialog") {
					this.dialogs[i].close();
				}
			}
			this.dialogs = [];
			this.removeBackground();
			this.removePageResizeListener();
		},
	
		/**
		 * Function will get the dialog object with the passed in id or name
		 * @param {String} identifier  the id or name of this dialog
		 * @return m2.Dialog
		 */
		getDialog : function(identifier) {
			for (var i = 0 ; i < this.dialogs.length ; i++) {
				if (this.dialogs[i].id == identifier || this.dialogs[i].config.dialogName == identifier) { 
					return this.dialogs[i];
				}
			}
		},
	
		/**
		 * Function will add the current dialog to the list of dialogs
		 * @param {m2.Dialog} dialog
		 */
		add : function(dialog) {
			if (!dialog) {
				return;
			}
			this.dialogs[this.dialogs.length] = dialog;
			this.updateDialogIndexes();
		},
	
		/**
		 * Function will remove the dialog from the current set of dialogs
		 * @param {m2.Dialog} dialog (optional)
		 */
		remove : function(dialog) {
			this.dialogs.splice((dialog) ? dialog.managerIndex : this.dialogs.length - 1,1);
			this.updateDialogIndexes();
		},
		
		/**
		 * Sets the zIndex of all dialogs based on their position in the dialogs array
		 */
		updateZIndexes :function() {
			var zIndex = m2.dialog.baseZIndex;
			var backgroundSet = false;
			for (var i = this.dialogs.length -1 ; i >= 0 ; i--) {
				this.dialogs[i].managerIndex = i;
				this.dialogs[i].updateZIndex(zIndex);
				if (this.dialogs[i].config.modal && !backgroundSet) {
					this.setBackground(zIndex - 1,this.dialogs[i].config.backgroundClass);
					backgroundSet = true;
				}
				zIndex -= 2; 
			}
			if (!backgroundSet) {
				this.removeBackground();
			}
		},
	
		/**
		 * Sets background based on the settings of the most restrictive dialog
		 * @param {int}    zIndex   the zIndex that we want the background displayed at
		 * @param {String} bgClass  the class of the background
		 */
		setBackground : function(zIndex,bgClass) {
			// create and set the bg 
			this.backgroundEl = this.backgroundEl || document.createElement("div");
			if (bgClass != this.backgroundEl.className) {
				// added a hack for firefox 2 to prevent strange scrolling / repeating behavior
				// NOTE: if there is ever more than one browser that needs a similar hack, the classname here
				// should be adjusted to add teh browser name.
				this.backgroundEl.className = bgClass + ((m2.isFF == 2) ? " ff2" : "");
			}
			this.backgroundEl.style.zIndex = zIndex;
	
			// set to the full page's height ... not just the viewport
			var d = _mu.getDocumentDimensions();
			this.backgroundEl.style.width = d.w + "px";
			this.backgroundEl.style.height = d.h + "px";
			
			document.body.appendChild(this.backgroundEl);
			
			// remove bg hack
			if (this._backgroundDomHack) {
				document.body.removeChild(this._backgroundDomHack);
			}
	
			// get a new bg hack
			this._backgroundDomHack = _mu.getBrowserHackDomNode(this.backgroundEl);
	
			// set the bg hack
			if (this._backgroundDomHack) {
				document.body.appendChild(this._backgroundDomHack);
	
				// for ff mac listen to window events and reset overlays
				if (m2.isFFMac) {
					this.ffMacListener = _mu.addFFMacListeners(this._backgroundDomHack);
				}
			}
		},
		
		/**
		 * Function will remove the background that makes the dialog modal
		 */
		removeBackground : function() {
			if (!this.backgroundEl) {
				return;
			}
			document.body.removeChild(this.backgroundEl);
			this.backgroundEl = null;
	
			if (this._backgroundDomHack) {
				// for ff mac listen to window events and reset overlays
				if (m2.isFFMac) {
					_mu.removeFFMacListeners(this.ffMacListener);
				}
				document.body.removeChild(this._backgroundDomHack);
				this._backgroundDomHack = null;
			}
		},
		
		/**
		 * Function will update the dialog indexes so that they will refer to themselves properly in the dialog 
		 * manager
		 */
		updateDialogIndexes : function() {
			for (var i = 0 ; i < this.dialogs.length ; i++) {
				this.dialogs[i].managerIndex = i;
			}
		},
		
		/**
		 * Function will attach a page resize listener to the page.  Will reposition dialog elements when resized.
		 */
		setPageResizeListener : function() {
            if (!this._resizeListenerSet) {
    			m2.util.Event.add(window, 'resize', function(){_dm.pageResized();});
				this._resizeListenerSet = true;
            }
		},
        
		/**
		 * Function will remove the page resize listener from the page.
		 */
		removePageResizeListener : function() {
            if (this._resizeListenerSet) {
				try {
					m2.util.Event.remove(window, 'resize', function(){_dm.pageResized();});
					this._resizeListenerSet = false;
				} catch(e) {}
            }
		},
		
		/**
		 * Method executed when the page resizes.  Will reset the position of the dialogs in the page.
		 */
		pageResized : function() {
			for (var i = 0 ; i < this.dialogs.length ; i++) {
				// update the position of all the dialogs
				this.dialogs[i].setPosition();
				if (this.dialogs[i].config.showArrow) {
					this.dialogs[i].addArrow();
				}
				// take care of IE and FF hacks
				this.dialogs[i].addDialogDomHack();
			}
			this.removeBackground();
			this.updateZIndexes();
		},
		
		/**
		 * Method will update the topmost dialog that contains an iframe
		 * @param {Object} data
		 */
		updateDialogIframe : function(data) {
			for (var i = this.dialogs.length - 1; i >= 0 ; i--) {
				if (this.dialogs[i].domEl.getElementsByTagName("iframe").length > 0) {
					this.dialogs[i].updateIframeDimensions(data);
					return;
				}
			}
		}
	};



	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/**
	 * @class 
	 * This class contains the properties and methods necessary to manage and display dialogs.  
	 * These objects should never be accessed by anything other than the dialog manager, as it 
	 * manages the display of all dialogs on the page.
	 * @private
	 * @param {m2.dialog.Config} config  the configuration for this dialog
	 * @param {Integer}                 index   the index of the dialog in the dialog manager
	 */
	m2.dialog._Dialog = function(config,index) {
		/**
		 * The id of the dialog
		 * @type String
		 */
		this.id = "mqDialog_" + index;
	
		/**
		 * The index this dialog is at in the Dialog Manager
		 * @type Integer
		 */	
		this.managerIndex = index;
	
		/**
		 * The configuration for this dialog
		 * @type m2.DiaglogConfig
		 */
		this.config = config;
	
		/**
		 * The dom node for this dialog
		 * @type DomNode
		 */
		this.domEl = null;
		
		/**
		 * The dom node we append content to
		 * @type DomNode
		 */
		this.contentEl = null;
	
		/**
		 * The dom node for the close button
		 * @type DomNode
		 */    
		this.closeEl = null;
	
		/**
		 * The target/end position of the dialog
		 * @type Object
		 */
		this.targetPosition = {x:0,y:0};
		

		/**
		 * Handle to the arrow element for the dialog
		 * @type HTMLElement
		 */		
		this.arrowEl = null;
		
		/**
		 * Handle to the alignment of a dialog.  Only used when dialog is aligned in relation to another element.
		 */
		this.currentAlign = null;
	
		/**
		 * Holds the event listeners for this object
		 * @type Array
		 */
		this.events = [];
		
		/**
		 * Holds a reference to the dom node that is used to prevent elements from floating above our dialog
		 * @type DomNode
		 */
		this.dialogDomHack = null;
		
		/**
		 * Tracks the size the content wants to be
		 * @type Object
		 */
		this.contentSize = {w:0,h:0};
		
		this.backgroundClickListener = {};
	};
	
	/**
	 * Additional dialog functions
	 */
	m2.dialog._Dialog.prototype = {
		/**
		 * Function will open the dialog.
		 * @private
		 * 
		 * @param {DomNode|String} el  (optional) the element that we will use to position this dialog
		 */
		open: function(el) {
			// set the dialog HTML
			var config = this.config;
			var dialogHTML = _mu.widget.template(_HTML.dialog,{
				classname : config.dialogClass,
				dialogid : this.id
			});
			
			// create the dialog wrapper
			this.domEl = document.createElement("div");
			this.domEl.innerHTML = dialogHTML;
			this.domEl = this.domEl.childNodes[0];
			
			// keep the dialog hidden while we do stuff to it
			this.domEl.style.zIndex = "-1";
			
			// add it to the dom so we can accurately determine size and position
			document.body.appendChild(this.domEl);
	
			// create/append the dialog content node
			this.contentEl = document.createElement("div");
			m2.$(this.id + "_content").appendChild(this.contentEl);
	
			this.contentEl.style.position = "relative";
			_mu.setStyle(this.contentEl,"opacity",this.config.contentOpacity);
	
			// set stuff
			this.setContent();
			
			// add close button before size as it changes the padding on the content
			this.setCloseActions();
			this.setSize();
			this.setPosition();
			// add arrow after positioning so we can adjust as needed
			this.addArrow();
			this.setFocus();
	
			// take care of IE and FF hacks
			this.addDialogDomHack();
		},
		
		/**
		 * Function will update the currently showing dialog 
		 * @param {Object} config (optional) the config that we will be updating to
		 */
		update : function(config,el) {
			var i,o,j;

			// update the config with the passed in data
			if (config) {
				// update the current config's info with the passed in one
				for (var i in config) {
					o = config[i];
					// if it is a nested object then go down one level and update that content
					if ((typeof o == "object" || _mu.isArray(o)) && i != "content") {
						for (var j in o) {
							this.config[i][j] = o[j];
						}
					} else {
						this.config[i] = config[i];
					}
				}
			} else {
				config = {};
			}

			// set stuff based on if they have changed in the config
			if (config.dialogClass) {
				this.setClass();
			}
			
			if (config.content) {
				this.clearContents();
				this.setContent();
			}

			if (config.closeOnBackgroundClick || config.showCloseButton || config.closeButtonCallback) {
				this.setCloseActions();
			}

			if (config.size || config.overflow || config.position) {
				this.setSize();
				this.setPosition();
			}

			if (config.showArrow) {
				this.addArrow();
			}

			this.setFocus();
			
			// take care of IE and FF Hacks
			this.removeDialogDomHack();
			this.addDialogDomHack();
		},

		/**
		 * Function will close the dialog
		 * @private
		 */
		close: function() {
			document.body.removeChild(this.domEl);
			this.removeDialogDomHack();
			if (this.config.onclose){
				this.config.onclose(this);
			}
			this.unload();
		},

		/**
		 * Sets the class of the dialog
		 */
		setClass : function() {
			this.domEl.className = _HTML.defaultClass + " " + this.config.dialogClass;
		},
		
		/**
		 * Function will set the focus of the page onto elements within the dialog
		 * @private
		 */
		setFocus: function() {
			if (this.config.skipFocus) {
				return;
			}
			function elemEnabled(el) {
	            /*
				if (typeof el.style == "undefined") {
					debugger;
				}
				*/
				return (!el.disabled && el.style.visibility != "hidden" && el.style && el.style.display != "none" && el.type != "hidden");
			}
	
			var el,els,i,j;
	
			// if the content is an iframe.  set the focus to the iframe
			els = this.domEl.getElementsByTagName("iframe");
			if (els.length > 0) {
				els[0].focus();
				return;
			}
	
			// check the passed in id
			if (this.config.focusId) {
				el = m2.$(this.config.focusId);
				if (el && elemEnabled(el)) {
					el.focus();
					return;
				}
			}
	
			// check elements with focus classes
			els = _mu.getElementsByClassName("focus",this.domEl);
			for(i=0;i<els.length;i++){
				if (elemEnabled(els[i])) { 
					els[i].focus();
					return;
				}
			}
	
			// check all focusable elements
			var tagsToCheck = ["input","button"];
			for(j=0;j<tagsToCheck.length;j++) {
				els = this.domEl.getElementsByTagName(tagsToCheck[j]);
				for(i=0;i<els.length;i++){
					if (elemEnabled(els[i])) { 
						els[i].focus();
						return;
					}
				}
			}
	
			// check links for browsers other than ie
			if (!m2.isIE) {
				els = this.domEl.getElementsByTagName("a");
				for(i=0;i<els.length;i++){
					if (elemEnabled(els[i])) { 
						els[i].focus();
						return;
					}
				}
			}
		},
	
		/**
		 * Function sets the content of the dialog
		 */
		setContent : function() {
			var c = document.createElement("div");
			if (_mu.isString(this.config.content)) {
				c.innerHTML = this.config.content;
			} else {
				c.appendChild(this.config.content);
			}
			
			// append the created element to the body to determine its size
			// TODO - Appending and moving the child element is an expensive process
			//        find a way to determine content size without having to do this.
			c.style.zIndex = -1;
			c.style.position = "absolute";
			document.body.appendChild(c);
			this.contentSize = {w:c.offsetWidth,h:c.offsetHeight};
			c.style.zIndex = 0;
			c.style.position = "relative";
	
			// append to dialog
			this.contentEl.appendChild(c);
		},
		
		/**
		 * Sets the position of the dialog based on the config
		 */
		setPosition : function() {
			var pos = {x:null,y:null};
			var elc = _mu.coords(this.domEl);
			this.currentAlign = null;
			
			if (this.config.position.el) {
				// position based on element
				pos = m2.dialog.util.getPositionFromElement(this.config.position.el,this.domEl,this.config.position.align,null,this.config.skipReposition);
				this.currentAlign = {one:pos.one,two:pos.two};
			}
			if (!pos.x && this.config.position.x !== null && this.config.position.x !== "") {
				pos.x = this.config.position.x;
			}
			if (!pos.y && this.config.position.y !== null && this.config.position.y !== "") {
				pos.y = this.config.position.y;
			}
			
			// position in center of viewport if position is not already set
			var v = _mu.getDocumentDimensions();
			if (!pos.x) {
				pos.x = v.l + Math.round(v.vw/2) - Math.round(elc.w/2);
			}
			if (!pos.y) {
				pos.y = v.t + Math.round(v.vh/2) - Math.round(elc.h/2);
			}
	
			// If position is negative, use configured fallback position
			if (pos.x < 0 && this.config.position.fallback.x != null && this.config.position.fallback.x !== "") {
				pos.x = this.config.position.fallback.x;
			}
			if (pos.y < 0 && this.config.position.fallback.y != null && this.config.position.fallback.y !== "") {
				pos.y = this.config.position.fallback.y;
			}

			this.domEl.style.left = pos.x + this.config.position.ox + "px";
			this.domEl.style.top = pos.y + this.config.position.oy + "px";

			return pos;
		},
	
		/**
		 * Function will set the size (height/width) of the dialog
		 */
		setSize : function() {
			// get the new width / width if explicityly set
			if (this.config.size.width && this.config.size.width != "auto") {
				this.contentSize.w = this.config.size.width - (this.domEl.offsetWidth - this.contentEl.offsetWidth);
			}
			// due to display bugs in IE width always needs to be set.
			this.contentEl.style.width = this.contentSize.w + "px";
	
	
			if (this.config.size.height && this.config.size.height != "auto") {
				this.contentSize.h = this.config.size.height - (this.domEl.offsetHeight - this.contentEl.offsetHeight);
				this.contentEl.style.height = this.contentSize.h + "px";
			} else {
				// will resize the dialog based on the content's height automatically
				this.contentEl.style.height = "";
			}
	
			// ensure that content will scroll if necssary
			if (this.config.overflow) {
				this.contentEl.style.overflow = this.config.overflow;
			} else {
				this.contentEl.style.overflow = "hidden";
			}
		},
	
		/**
		 * Function will clear the content's div.  Will not change the size of the content.
		 */    
		clearContents : function() {
			this.contentEl.innerHTML = "";
		},
	
		/**
		 * ffMacListener  the id reference to the window listener hack in place for ffMac
		 * @type String 
		 */
		ffMacListener : null,
	
		/**
		 * Function will remove an existing hack dom node.
		 */
		removeDialogDomHack : function() {
			if (this.dialogDomHack) {
				try {
					document.body.removeChild(this.dialogDomHack);
				} catch (e) {}
	
				// for ff mac remove listener on window events
				if (m2.isFFMac) {
					_mu.removeFFMacListeners(this.ffMacListener);
				}
				this.dialogDomHack = null;
			}
		},
		
		/**
		 * Adds the dialog dom hack element to the document
		 * @param {DomNode} el  the dom element 
		 */
		addDialogDomHack : function(el) {
			// remove any existing dialog dom hacks
			if (this.dialogDomHack) {
				try {
					document.body.removeChild(this.dialogDomHack);
				} catch (e) {
					if (typeof console != "undefined" && console.debug) {
						console.debug("there was a problem removing a dialog dom hack.  see the addDialogDomHack method in dialog.js.")
					}
				}
			}
			
			this.dialogDomHack = _mu.getBrowserHackDomNode(this.domEl);
			if (this.dialogDomHack) {
				document.body.appendChild(this.dialogDomHack);
				// for ff mac listen to window events and reset overlays
				if (m2.isFFMac) {
					this.ffMacListener = _mu.addFFMacListeners(this.dialogDomHack);
				}
			}
		},
		
		/**
		 * Function adds a close button ("x") to the top right corner of the dialog,
		 * and checks if should listen to bg click for closing
		 */
		setCloseActions : function() {
			// add the close button
			if (this.config.showCloseButton) {
				var w = document.createElement("div");
				w.innerHTML = _HTML.close;
				this.closeEl = w.firstChild;
				
				this.contentEl.parentNode.appendChild(this.closeEl);
				var self = this;
				var callback = this.config.closeButtonCallback;
                
				// attach event
				m2.util.Event.add(self.closeEl,"click",function(){
					m2.dialog.close(self.id);
                    if (callback) callback();
				});
		
				this.contentEl.style.paddingRight = "17px";
			}
			
			// add the bg click listener
			this.removeBackgroundClickListener();
			if (this.config.closeOnBackgroundClick) {
				this.addBackgroundClickListener();
			}
		},
		
		/**
		 * Adds background click listener to close the document
		 */
		addBackgroundClickListener : function() {
			if (!this.backgroundClickListener) { 
				var self = this;
				m2.util.Event.add(document,'mousedown', function(ev){self.checkBackgroundClickListener(ev,self.config);});
				this.backgroundClickListener = true;
			}
		},
	
		/**
		 * Removes background click listener from the document
		 */
		removeBackgroundClickListener : function() {
			if (this.backgroundClickListener) {
				var self = this;
				m2.util.Event.remove(document,'mousedown', function(ev){self.checkBackgroundClickListener(ev,self.config);});
				this.backgroundClickListener = false;
			}
		},
		
		/**
		 * checks the click of the document is inside the dialog bounds or not.  will close if so
		 * 
		 * @param {Object} ev
		 */
		checkBackgroundClickListener : function(ev,config) {
			
			// if the click is over an open dialog then don't close any of them
			var xy = _mu.getXYFromEvent(ev),
			arr = _dm.dialogs,
			shouldClose = true,
			i=0,cb;
			for (; i < arr.length;i++) {
				if (_mu.pointInBounds(xy,arr[i].domEl)) {
					shouldClose = false;
				}
			}
			if (shouldClose) {
				m2.dialog.close(this.id);
				var cb = (config) ? config.closeButtonCallback : null;
                if (cb) {
					cb();
				}
				this.removeBackgroundClickListener();
			}
		},
		
		/**
		 * Adds the arrow element to the dialog
		 */
		addArrow : function() {
			// removes the existing arrows
			if (this.arrowEl) {
				this.removeArrow();
			}
			// check if we should show arrows
			if (!this.config.showArrow  || !this.currentAlign) {
				return;
			}

			// declare vars
			var cn = m2.dialog.constants;
			var arrow, a1,a2,dir,ss,of,offsets,st;

			// create the arrow element
			arrow = document.createElement("div");
			
			// determine the directio of the arrow based on the positioning
			a1 = this.currentAlign.one;
			a2 = this.currentAlign.two;
			dir = (a1 == cn.TOP) ? cn.DOWN : (a1 == cn.BOTTOM) ? cn.UP : (a1 == cn.LEFT) ? cn.RIGHT : cn.LEFT;

			// set the class so we show the appropriate arrow
			arrow.className = "arrow " + dir;

			// append to the dialog and cache
			arrow.appendChild(document.createElement("div"));
			this.arrowEl = arrow;
			this.domEl.appendChild(this.arrowEl);
			
			// calclulate the offests necessary for the arrow
			ss = 12;              // guesstimate amount for shadow size
			of = 0;               // temp var to hold the height or width of the arrow used to offset the dialog
			offsets = {h:0,v:0};  // the amount we will offset the dialog
			st = this.arrowEl.style; // handle to the style element
			
			// if it's an arrow showing on the left or right, offset the dialog left/right and move the arrow vertically
			// to the appropraite positions
			if (dir == "l" || dir == "r") {
				// offset the dialog by the width of the arrow minus the shadow
				offsets.h = this.arrowEl.offsetWidth - (ss / 2);
				if (dir == "r") {
					// negative offset if arrow is on the right
					offsets.h = offsets.h * -1;
				}

				// calculate the vertical offset of the arrow, and move the dialog vertically if the arrow is at the end.
				of = parseInt(this.arrowEl.offsetHeight / 2);
				if (a2 == "t") {
					offsets.v = of * -2;
					st.top = (of + ss) + "px";
				} else if (a2 == "b") {
					offsets.v = of * 2;
					st.bottom = (of + ss) + "px";
				} else if (a2 == "m") {
					st.top = (parseInt(this.domEl.offsetHeight / 2) - of) + "px";
				}
			} else {
				// arrow is pointing up or down, so move the dialog verticall to give the arrow space
				offsets.v = this.arrowEl.offsetHeight - (ss / 2);
				if (dir == "d") {
					// negative offset if the arrow is pointing down
					offsets.v = offsets.v * -1;
				}

				// calculate the horizontal offset of the arrow, and move the dialog horizantally if the arrow is at either end.
				of = parseInt(this.arrowEl.offsetWidth / 2);
				if (a2 == "l") {
					offsets.h = of * -2;
					st.left = (of + 9) + "px"; 
				} else if (a2 == "r") {
					offsets.h = of * 2;
					st.right = (of + 9) + "px"; 
				} else if (a2 == "c") {
					st.left = (parseInt(this.domEl.offsetWidth / 2) - of) + "px";
				}
			}
			
			// set the offset
			this.domEl.style.left = (parseInt(this.domEl.style.left) + offsets.h) + "px";
			this.domEl.style.top = (parseInt(this.domEl.style.top) + offsets.v) + "px";

		},
		
		/**
		 * Removes the arrow element from the dialog
		 */
		removeArrow : function() {
			if (this.arrowEl) {
				this.arrowEl.parentNode.removeChild(this.arrowEl);
			}
			this.arrowEl = null;
		},
		
		/**
		 * Function will set the zIndex of the dialog based on its config and position in the manager
		 * @param {boolean} zIndex  the zIndex we want the dialog at
		 */
		updateZIndex : function(zIndex) {
			this.domEl.style.zIndex = zIndex;
			if (this.dialogDomHack) {
				this.dialogDomHack.style.zIndex = zIndex -1;
			}
		},
		
		
		updateIframeDimensions : function(data) {
			this.config.size.height = "auto";
			this.setSize();
			var iframeEl = this.domEl.getElementsByTagName("iframe")[0];
			var time = data.time || 500;
			iframeEl.style.height = data.height + "px";
		},
		
		/**
		 * Clears out all property references
		 */
		unload : function() {
			var self =this;
			this.removeBackgroundClickListener();
			this.id = null;
			this.managerIndex = null;
			this.config = null;
			this.domEl = null;
			this.contentEl = null;
			if (this.closeEl) {
				m2.util.Event.remove(self.closeEl,"onClick",function(){
					m2.dialog.close(self.id);
				});
				this.closeEl.onclick = null;
				this.closeEl = null;
			}
			if (this.arrowEl) {
				this.arrowEl = null;
			}
			this.targetSize = null;
			this.targetPosition = null;
			this.events = null;
		}
	};



	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/**
	 * @namespace
	 * Object Holds functions that assist in the processing of dialogs
	 */
	m2.dialog.util = {
		/**
		 * This function will get the position of an element (elToShow) based on the position of another
		 * element (positioningEl) and the desired placement.
		 * 
		 * @method getPositionFromElement
		 * @param {object}  positioningEl    the element that we are basing the new position on.
		 * @param {object}  elToShow         the elment that will be shown relative to the positioningEl.
		 * @param {object}  align            the desired alignment of the dialog
		 * @param {Object}  offset           (optional) an array containing the new X & Y offsets for the element 
		 * @param {boolean} skipReposition   will skip the overflow of document bounds check and position the dialog 
		 *                                   in the specified position
		 * 
		 * @return {Object} an object containing the x,y and placement of the dialog
		 */
		getPositionFromElement : function (positioningEl,elToShow,align,offset,skipReposition) {
			// get the coordinates of the elements
			var pelc = _mu.coords(positioningEl,true);
			var elsc = _mu.coords(elToShow,true);
	
			// dojo seems to account for margins when calculating width and height.  so calc our own.
			pelc.w = positioningEl.offsetWidth;
			pelc.h = positioningEl.offsetHeight;
			elsc.w = elToShow.offsetWidth;
			elsc.h = elToShow.offsetHeight;
			
			// setup two versions of the element so that we can compare their overlaps with the page bounds
			cn = m2.dialog.constants;
			var a1 = align;
	
			// calculate the position for both the options
			var pos1 = this.calculateXY({x:pelc.x,y:pelc.y},pelc,elsc,a1);
			offset = offset || {x:0,y:0};
			pos1.x += offset.x;
			pos1.y += offset.y;
			pos1.one = a1.one;
			pos1.two = a1.two;
	
			if (skipReposition) {
				return pos1;
			}
	
			// check if the element overlaps any part of the page bounds
			var p1Over = _mu.getPageOverlap(elToShow,{y:pos1.y,x:pos1.x});
	
			// if there are no overlap of page bounds, return the position calculated
			if (p1Over.overTop === 0 && p1Over.overBottom === 0 && p1Over.overLeft === 0 && p1Over.overRight === 0) {
				return pos1;
			}
			
			// since there is a page overlap set an inverted alignment for comparison
			var a2 = {
				one: (a1.one == cn.RIGHT || a1.one == cn.CENTER) ? cn.LEFT : (a1.one == cn.LEFT) ? cn.RIGHT : (a1.one == cn.BOTTOM) ? cn.TOP : cn.BOTTOM,
				two: (a1.two == cn.TOP || a1.twp == cn.MIDDLE) ? cn.BOTTOM : (a1.two == cn.BOTTOM) ? cn.TOP : (a1.two == cn.LEFT) ? cn.RIGHT : (a1.two == cn.RIGHT) ? cn.LEFT : cn.MIDDLE
			};
			var pos2 = this.calculateXY({x:pelc.x,y:pelc.y},pelc,elsc,a2);
			pos2.x -= offset.x;
			pos2.y -= offset.y;
			pos2.one = a2.one;
			pos2.two = a2.two;
			var p2Over = _mu.getPageOverlap(elToShow,{y:pos2.y,x:pos2.x});
	
			var finalAlign = {one:a1.one,two:a1.two};
			// set the alignment for vertical overlap
			if ((p1Over.overTop + p1Over.overBottom) > (p2Over.overTop + p2Over.overBottom)) {
				if (a1.one == cn.BOTTOM || a1.one == cn.TOP) {
					finalAlign.one = a2.one;
				} else {
					finalAlign.two = a2.two; 
				}
			} 
	
			// set the alignment for horizontal overlap
			if ((p1Over.overLeft + p1Over.overRight) > (p2Over.overLeft + p2Over.overRight)) {
				if (a1.one == cn.LEFT || a1.one == cn.RIGHT) {
					finalAlign.one = a2.one;
				} else {
					finalAlign.two = a2.two; 
				}
			}
	
			// if the ideal position is one we have already calculated, return it
			if (finalAlign.one == a1.one && finalAlign.two == a1.two) {
				return pos1;
			} else if (finalAlign.one == a2.one && finalAlign.two == a2.two) { 
				return pos2;
			}
	
			// get a new position 
			var pos3 = this.calculateXY({x:pelc.x,y:pelc.y},pelc,elsc,finalAlign);
			pos3.x -= offset.x;
			pos3.y -= offset.y;
			pos3.one = finalAlign.one;
			pos3.two = finalAlign.two;
			return pos3;
	
		},
	
	
		/**
		 * Calculates teh xy position of a new dialog based on the passed in parameters.
		 * 
		 * @param {Object} pos    the desired x/y position 
		 * @param {Object} pelc   object containing the coordinates (x,y,w,& h) of the element we base position off of
		 * @param {Object} elsc   object containing the coordinates (x,y,w,& h) of the element we are positioning
		 * @param {Object} align  the object containing the 
		 */
		calculateXY : function(pos,pelc,elsc,align) {
			var cn = m2.dialog.constants;
			// set the position based on the placement value
			switch (align.one) {
				case cn.TOP :
					pos.y = pos.y - elsc.h;
					break;
				case cn.BOTTOM :
					pos.y = pos.y + pelc.h;
					break;
				case cn.RIGHT :
					pos.x = pos.x + pelc.w;
					break;
				case cn.LEFT :
					pos.x = pos.x - elsc.w;
					break;
			}
	
			switch (align.two) {
				case cn.BOTTOM :
					pos.y = pos.y + (pelc.h - elsc.h);
					break;
				case cn.MIDDLE :
					pos.y = pos.y + parseInt(pelc.h / 2) - parseInt(elsc.h / 2);
					break;
				case cn.TOP :
					pos.y = pos.y;
					break;
				case cn.RIGHT :
					pos.x = pos.x - elsc.w + pelc.w;
					break;
				case cn.CENTER :
					pos.x = pos.x + parseInt(pelc.w / 2) - parseInt(elsc.w / 2);
					break;
			}
			return pos;
		}
	};

	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
	/**
	 * Holds the constants used in dialog processing
	 * @type object
	 */
	m2.dialog.constants = {
		LEFT   : "l",
		RIGHT  : "r",
		CENTER : "c",
		TOP    : "t",
		BOTTOM : "b",
		MIDDLE : "m",
		UP     : "u",
		DOWN   : "d"
	};

	_mu = m2.util;
	_dm = m2.dialog._Manager;
	_dc = m2.dialog.Config;

})();
