/**
 * @fileOverview This file contains the static Iframe class utilized in cross domain scripting.
 * @author <a href="mailto:sunder@spatialinteractive.com">Sunder</a>
 */
/**
 * @class
 * Since browsers natively prevent cross domain communications, this file was specifically create to 
 * circumvent that issue using Iframes.  It also supplies logic for the generic creation of Iframes.
 * @example
 * Cross domain communication structure:
 * 
 * ParentPage : http://www.mapquest.com/
 * |
 * | This is the ParentPage that contains m2.util.Iframe.js and the child iframe from a different domain
 * |
 * | required code:
 * | 
 * | <script type="text/javascript" src="cdn/js/mq/m2.util.Iframe.js"></script>
 * | <iframe src="http://www.aol.com/#http://www.mapquest.com"></iframe>
 * | 
 * |
 * ---> ChildIFrame : http://www.aol.com/#http://www.mapquest.com
 *      |
 *      | The page Iframe refers to must contain m2.util.Iframe.js.  Whenever it wants to communicate with 
 *      | the ParentPage it will call m2.util.Iframe.sendMessage(type,msgData).  The sendMessage function 
 *      | creates a child frame that has the parent's base url (taken from it's hash as shown above) and 
 *      | will send the specified message data (encoded as JSON) in that url's hash.
 *      | 
 *      | required code in the child frame:
 *      |
 *      | <script type="text/javascript" src="cdn/js/mq/m2.util.Iframe.js"></script>
 *      | <script type="text/javascript">
 *      |     // example call to the send message
 *      |      m2.util.Iframe.sendMessage("loginSuccess",{user:"user123"});
 *      | </script>
 *      |
 *      |
 *      ---> ChildIframeIframe : http://www.mapquest.com/cdn/html/comm.html#{type:"loginSuccess",user:"user123"}
 *           |
 *           | This dynamically created inner frame refers to a special html page (comm.html) on the parent 
 *           | site.  Since it has the same base url as the ParentPage it is able to call js functions in the 
 *           | parent.  The comm.html page just contains basic js that calls m2.util.Iframe.handleMessage 
 *           | in the ParentPage.
 *           |
 *           | required code in comm.html:
 *           | 
 *           | var h = location.hash;
 *           | if (h && h != "") {
 *           |     parent.parent.m2.util.Iframe.handleMessage(h.substring(h.indexOf('=') + 1));
 *           | }
 *           |
 *           -
 *            
 * That's about it.
 * @static
 */
m2.util.Iframe = {
	/**
	 * This variable holds the url of the parent taken from the hash.  The parentURL is stored in the hash, the parent
	 * url can be stored as the hash itself or the hash can be a JSON object with the parentURL in it.  This is done
	 * to accommodate the easy access of multiple sets of data within the hash.
	 * 
	 * @private
	 * @type String
	 */
	getParentFrameURL : function() {
		var h = window.location.hash || null;
		h = (h) ? h.substring(1) : h;

		if (h.indexOf("{") >= 0 ) {
			h = window.location.hash.substring(1);
			// safari needs the value unescaped to process the dojo stuff in the url
			h = (m2.isSafari) ? unescape(h) : h;
			h = m2.util.fromJson(h).parentUrl;
		}
		if (typeof h == "undefined") {
			h = "";
		}
		return h;
	},
    
	/**
	 * frameCounter  generic counter to set the id of an iframe if necessary
	 * @private
	 * @type int
	 */
	frameCounter : 0,

	/**
	 * commFrameURL  holds the URL of the generic comm frame
	 * NOTE: The url is set to the cdn which is typically served from its own base url.  Will need to 
	 *       change the location of this comm.html file to be some place within mapquest's site.
	 * @type String 
	 */
	commFrameURL : "/cdn/html/comm.html",

	/**
	 * Reference to the properties of the last message received
	 * @type Object
	 */
	msg : null,

	/**
	 * Function creates an Iframe
	 * @param {Object} config  the config for this iframe.  Allowable configuration options are:
	 *                             id : "1"                // {String}  id we will use for this iframe
	 *                             style : Object          // {Object}  the style settings we want for this frame
	 *                             src : "http://m2.com"   // {String}  new src of the frame
	 *                             className : "fr"        // {String}  new cssclass of the iframe
	 *                             node : DomEl            // {DomEl}   the dom node that we want to append to, defaults to the document body
	 * @return {DomNode}  The Iframe Element
	 */
	create : function(config) {
		// remove any existing iframes that have the same id as the one we are creating        
		if (config.id && m2.$(config.id)) {
			var oldEl = m2.$(config.id);
			oldEl.parentNode.removeChild(oldEl);
			oldEl = null;
		}

		// create the iframe dom el
		this.frameCounter ++;
		var el;
        
        if (m2.isIE) {
            var f = '<iframe';
            if (config.onload) { 
                f += ' onload="this.doOnLoad();"'
            }
            f += '></iframe>';
            el = document.createElement(f);
            if (config.onload) { 
                el.doOnLoad = config.onload;
            }
        } else {
            el = document.createElement("iframe");
    		if (config.onload) {
    			m2.util.Event.add(el,'load',config.onload);
    		}		
        }
		el.id                = config.id || "iframe_" + this.frameCounter;
		el.src               = config.src || "";
		el.className         = config.className || "";
		if (m2.isIE) {
			el.frameBorder       = "0";
		}

		el.allowTransparency = "true";

		// style a hidden iframe if set 
		if (config.hidden) {
			config.style = {
				border: 0,
				width: 0,
				height: 0,
				position: "absolute",
				left: 0,
				top: -900
			};
		}

		// loop through the config.styles 
		if (config.style){
			for (var i in config.style) {
				var styleTag = i;
				var style = config.style[i];
				m2.util.setStyle(el,i,config.style[i]);
			}
		}

		// append the new frame
		if (!config.node) {
			document.body.appendChild(el);
		} else {
			m2.$(config.node).appendChild(el);
		}
		return el;
	},
	
	/**
	 * This creates a frame that is used to communicate with another domain.
	 * @param {String}   type
	 * @return {DomNode}  The Iframe Element
	 */
	createCommFrame : function(type) {
		// if the parent frame url already contains .html assume that it is the location of the
		// comm.html file
		var pfu = this.getParentFrameURL();
		var u = (pfu && pfu.indexOf(".html") > 0) ? pfu : pfu + this.commFrameURL;

		return this.create({
			hidden: true,
			id:     type,
			src:    u
		});
	},
	
	/**
	 * Function will send a message to the parent of a cross domain iframe
	 * @param {String}        type   The type of the message.  Used when processing to determine what parent function
	 *                               should be called.  Also will become the id of the frame.
	 * @param {String|Object} data   the data that we want to pass
	 */
	sendMessage : function(type,data) {
		// init the data object to send and make it url friendly
		var d = (!data) ? {data:null} : (m2.util.isString(data)) ? {data:data} : data;
		d._type = type;
		d = m2.util.toJson(d);
		d = encodeURIComponent(d);
	   
		// create the frame and set the src
		var f = this.createCommFrame(type);
		f.src = f.src + '#data=' + d;
	},
	
	/**
	 * Function sends the width and height of the body of the frame to the hash in the url.  This function is
	 * typically used to resize the iframe to the size of the document.
	 */
	sendDocumentDimensions : function(animateTime) {
		// sends a message with the document body dimensions as the data
		this.sendMessage("dialogDimensions",{
			width   : document.body.offsetWidth,
			height  : document.body.offsetHeight
		},"dimensionsFrame");
	},
	
	/**
	 * Handles a new message passed from a child comm frame
	 * @param {String} msg  the encoded hash message
	 */
	handleMessage : function(msg)  {
		msg = decodeURIComponent(msg);
		msg = m2.util.fromJson(msg);
		this.msg = msg;
		switch (msg._type) {
			case "dialogDimensions" :
				m2.dialog.updateDialogIframe(msg);
				break;
			case "showLoginDialog" :
                m2.widget.user.Registration.closeSignUpDialog(msg);
				m2.widget.user.Login.showLoginDialog();
				break;
			case "closeLoginDialog" : 
				m2.widget.user.Login.closeLoginDialog(msg);
				break;
			case "initLogin" : 
				m2.widget.user.Login.initLoginDialog(msg);
				break;
			case "dispatchOpenIdLogin" : 
				m2.widget.user.Login.dispatchOpenIdLogin(msg);
				break;
            case "loggedIn" :
				m2.widget.user.setWelcomeMessage(msg);
				break;
			case "loginFailure" :
				m2.widget.user.Login.closeLoginDialog(msg);
				break;
			case "dispatchLogout" : 
				m2.widget.user.Logout.dispatchLogout(msg);
				break;
            case "loggedOut" :
				m2.widget.user.setWelcomeMessage();
				break;
			case "resetPassword" : 
				m2.widget.user.Login.goResetPassword();
				break;
			case "loading" :
				m2.dialog.loading(msg.message);
				break;
			case "hideLoading" :
				m2.dialog.hideLoading();
				break;
			case "closeDialog" :
				m2.dialog.close();
				break;
			case "initSignUp" : 
				m2.widget.user.Registration.initSignUpDialog(msg);
				break;
			case "showSignUpDialog" : 
				m2.widget.user.Login.closeLoginDialog(msg);
				m2.widget.user.Registration.showSignUpDialog();
				break;
			case "closeSignUpDialog" : 
                m2.widget.user.Registration.closeSignUpDialog(msg);
                break;
			case "logAction":
                if (typeof $a != "undefined") { $a(msg); }
                break;
			default :
				break;
		}
	},
    
    /**
     * Gets an absolute url for the given relative url using the current window host/port information.
     * 
     * @param {Object} url  relative url
     * @return the absolute url
     */
    getWindowUrl : function(url) {
        var wl = window.location;
        return wl.protocol + "//" + wl.hostname + (wl.port ? ":" + wl.port : "") + url;
    }
};
