(function() {
    
    /*
     * Private members.
     */
    
    /**
     * Controller providing access to user state.
     */
    var controller = null;
    
    /**
     * Track page view status.
     */
    var isInitialPageView = true;
	
    /**
     * Logs an action.  Supports the following signatues:
     * <p/>
     * actionName<br/>
     * actionName, screenName
     * <p/>
     * Any signature may also include an options and/or pause parameter.
     *
     * @param {String} actionName   action name
     * @param {String} screenName   screen name to be set as prop23
     * @param {String} options      options controlling how the action is processed (optional)
     * @param {Number} pause        amount of time (in milliseonds) to pause when logging the action (optional)
     */
    function logAction() {
        pre();
    
        // Implicitly process arguments to handle various parameter combinations.
        var args = Array.prototype.slice.call(arguments);
        var arg = args.splice(0,1)[0];

        var actionName;
        var screenName;
        var options;
        var pause;
        var isPageExit = false;
        var isPageView = false;
        var isAdRefresh = false;
        var magicNumber;

        if (typeof arg == "string") {
            // Standard argument list.
            actionName = arg;

            if (args.length > 0) {
				// Grab optional "pause" and "options" from the end of the argument list.
				arg = args[args.length - 1];

                if (m2.util.isNumber(arg)) {
                    pause = args.pop();
                    arg = args[args.length - 1];
                }

                if ((m2.util.isString(arg) && (arg.length == 1)) || (m2.util.isArrayLike(arg))) {
                    options = args.pop();
                }

				// Grab the rest of the parameters in order from the beginning of the argument list.
                screenName = args.shift();
            }
        } else {
            // Arguments passed as object properties.  Used in iframe calls.
            actionName = arg.action;
            screenName = arg.screen;
            options = arg.options;
            pause = arg.pause;
        }

        if (options) {
             if (typeof options == "string") { options = [ options ]; }

            for (var i= 0; i < options.length; ++i) {
                var option = options[i];
                if (option == 'e') { isPageExit = true; }
                if (option == 'v') { isPageView = true; }
                if (option == 'r') { isAdRefresh = true; }
                if (option.match(/r:/)) {
                	isAdRefresh = true;
                	magicNumber = option.split(':')[1];
                }
            }
		}

        // Optionally log screen name.
        if (!m2.util.isEmptyString(screenName)) {
            s_265.prop23 = screenName;
        }
    
        // Log the action.
        if (isPageExit) {
            // Set as a page view attribute to be logged on the next page view.
            m2.Cookie.setCookie("pageViewAttribute", actionName, 1, "/");
        } else if (isPageView) {
            // Set as an action to be logged in place of the next page view.  Used in rare cases
            // where a page is loaded to execute client-side logic that in turn may reload the
            // page to refresh its content (e.g., auto-login).  Ensures only one page view is
            // logged even though two page views occur.
            m2.Cookie.setCookie("pageViewAction", actionName, 1, "/");
        } else {
            // Log immediately.
            var pageName = s_pageName;
			var prop2 = generateProp2(screenName);
    
            s_265.prop21 = pageName;
			s_265.prop2 = prop2;
    
            if (typeof(testbedOmnitureValue) != 'undefined') {
                s_265.prop22 = testbedOmnitureValue;
            }
			
            getLogger(s_accountCL, true).tl(true, "o", actionName);
            debug("[omniture] an: " + actionName + ", pv(prop21): '" + pageName +"'" + (s_265.prop23 ? ", pv(prop23): '" + s_265.prop23 +"'" : "")); 
            
            // Argh...optional pause.  Supposedly fixes issues when logging upon page exit.
            if (pause) {
                var later = (new Date()).getTime() + pause;
                var keepGoing = true;
                while (keepGoing) {
                    if ((new Date()).getTime() > later) {
                        keepGoing = false;
                    }
                }
            }

			// Fixes an issue with subsequent page views not getting logged to all of the
			// requested accounts.  See BLT 482693 for more information. 
			s_265.sa(s_account);
        }
        
        // Refresh the ads.
        if (isAdRefresh) {
            refreshAds(actionName,null,magicNumber);
        }
        
        post();
    };
    
    /**
     * Logs a page view.  The initial page view for a request is called without any parameters.  Subsequent calls
     * support the following signatues:
     * <p/>
     * actionName<br/>
     * actionName, screenName<br/>
     * actionName, screenName, pageName
     * <p/>
     * Any signature may also include an options parameter.
     *
     * @param {String} actionName  action that caused the page view (i.e., page view attribute)
     * @param {String} screenName  screen name to be set as prop23
     * @param {String} pageName    page name to log in place of the global setting
     * @param {String} options     options controlling how the page view is processed (optional)
     */
    function logPageView() {
        pre();
        
        // Determine if a previous action "overrides" the page view.  See logAction() for more info.
        var actionName = m2.Cookie.getCookie("pageViewAction");
        
        if (actionName) {
            m2.Cookie.deleteCookie("pageViewAction", "/");
            logAction(actionName);
        } else {
            // Implicitly process arguments to handle various parameter combinations.
            var args = Array.prototype.slice.call(arguments);
            var arg = args.splice(0,1)[0];
            
            var screenName;
            var pageName;
            var options;
            var pause;
            var isAdRefresh = false;
            
            if (typeof arg == "string") {
                // Standard argument list.
                actionName = arg;
                
                if (args.length > 0) {
					// Grab optional "pause" and "options" from the end of the argument list.
                    arg = args[args.length - 1];
                     
                    if (m2.util.isNumber(arg)) {
                        pause = args.pop();
                        arg = args[args.length - 1];
                    }
					
					if ((m2.util.isString(arg) && (arg.length == 1)) || (m2.util.isArrayLike(arg))) {         
                        options = args.pop();
                    }
                    
					// Grab the rest of the parameters in order from the beginning of the argument list.
                    screenName = args.shift();
                    pageName = args.shift();
                }
            }
            
            if (options) { 
                if (typeof options == "string") { options = [ options ]; }
                
                for (var i= 0; i < options.length; ++i) {
                    var option = options[i];
                    if (option == 'r') { isAdRefresh = true; }
                }
            }
            
            // Optionally log screen name.
            if (!m2.util.isEmptyString(screenName)) {
                s_265.prop23 = screenName;
            }

            // Set prop2 (subdepartment) based on the page name.
            pageName = pageName || s_pageName;
            var prop2 = generateProp2(pageName);
            
            // Add on the mapquest pfxID.
            s_265.pageName = s_265.pfxID + " : " + pageName;
            s_265.prop2 = s_265.pfxID + " : " + prop2;
			
            // Set prop20 (page view attribute).  Cookie takes precedence.
            actionName = m2.Cookie.getCookie("pageViewAttribute") || actionName;
            var anDebug = "";
            
            if (actionName) {
                actionName = (actionName.indexOf(":") == 0) ? actionName.substring(1, actionName.length) : actionName;
                s_265.prop20 = actionName;
                m2.Cookie.deleteCookie("pageViewAttribute", "/");
                anDebug = ", an(prop20): " + s_265.prop20;
            } else {
                s_265.prop20 = "none";
            }
            
            // Log the page view.
            s_account = s_accountCL + ((m2.getServerPurpose() == "production")? ",aolsvc" : "");
            
            if (typeof(testbedOmnitureValue) != 'undefined') {
                s_265.prop17 = testbedOmnitureValue; 
            }
        
            getLogger(s_account, false).t();
            debug("[omniture] pv: " + pageName + ", sd(prop2): '"+ prop2 + "'" + anDebug);
            
            // Log comScore for "forced" page views.
            if (!isInitialPageView) {
                pageName = pageName || s_pageName;
                var pv = "?pv=" + pageName;
                var a = "&an=" + actionName;
                var r = "&r="+Math.round((Math.random() * 10000))+"&h=2"; // Random number to prevent caching.
                var url = "/mqrequest.html" + pv + a + r;
                var callback = function(response) {
                    if (response instanceof Error){
                        ua.debug("[comScore] something went horribly, horribly wrong."); 
                    }
                };
                var config = {
                    method : "GET",
                    timeout : 10000            
                }; 
                m2.util.AJAX.asyncRequest(url, callback, config);
                debug("[comScore] pv: " + url);
            } else {
                debug("[comScore] pv: false");
            }
            
            // Refresh the ads for "forced" page views.
            if (!isInitialPageView && isAdRefresh) {
                refreshAds(actionName, pageName);
            }
        }
        
        isInitialPageView = false;
        
        // Set mq.UA flags for cases where both Omniture logging mechanisms
        // are used (e.g., http://www.mapquest.com/traffic).
        window.ua._initialAdSuppressionComplete = true;
        window.ua._initialComScoreSuppressionComplete = true;

        post();
        // added for selenium flow control
        debugSelenium();
    };

    /**
     * Backward compatibility for promo links.
     * 
     * @param {String} actionName  action name
     */
    function promo(actionName){
        logAction(actionName, null, 250);
    };
    
    /**
     * Backward compatibility for action calls.
     * 
     * @param {String} actionName
     */
    var ua = {
    
        _actions: {
            'MQ08AOLSearch': {
                o: null,
                p: 250
            }
        },
        
        a: function(actionName){
            if (actionName.charAt(0) == ':') {
                actionName = actionName.substring(1, actionName.length);
            }
            
            var action = this._actions[actionName];
            
            logAction(actionName, action.o, action.p);
        }
    };

    /**
     * Logs a message to the debug console.
     * 
     * @param {String} msg  message
     */
    function debug(msg) {
        //Provides a debugger helpful for QAing the reporting requests
        var dbgr = m2.$("userActionDebugger");
        if(dbgr){
            var current = dbgr.value;
            dbgr.value = current + "\n" + msg;
            dbgr.value = dbgr.value;
            dbgr.scrollTop = dbgr.scrollHeight;
        }
    }
    
    /**
     * Called before logging.
     */
    function pre() {
        // Clear important values.
        s_265.prop20 = null;
        s_265.prop21 = null;
        s_265.prop23 = null;
        s_265.prop2 = "";
        s_265.pageName = "";
    };
    
    /**
     * Called after logging.
     */
    function post() {
        //Clear important values
        s_265.prop20 = null;
        s_265.prop21 = null;
        s_265.prop22 = null;
        s_265.prop23 = null;
        s_265.prop2 = "";
        s_265.pageName = "";
        if(s_265.prop16) { s_265.prop16 = null; }
    };
    
    /**
     * Refreshes ads based on the given action name and page name.
     * 
     * @param {Object} actionName  action name
     * @param {Object} pageName    page name override (optional)
     * @param {Objcet} magicNumber specific magic number to use to refresh ads. for BL (optional)
     */
    function refreshAds(actionName, pageName, magicNumber) {
        //try {
            // Build the user state
            if (!controller) return;    // If no controller registered, then do nothing
            
            // For generic Biz Loc icon activation, concatenate prop23 to action to specify icon
            if(!magicNumber && "MQ08BizLocOn" == actionName && s_265.prop23) {
            	actionName += ':'+s_265.prop23;
            }
            
            pageName = pageName || s_pageName;
            var userState = controller.adUserStateFromModel();
            userState.brandedMagicNumber=magicNumber;
            var regions = m2.Ad.selectCurrentRegions();
            
            m2.Ad.refreshRegions(regions, {
                userAction: actionName,
                pageView: pageName,
                userState: userState, 
                promotionalBrandingId: (controller._model) ? controller._model.blId : 0
            });
            debug("[ad] true");
        //} catch (e) {
        //    debug("[ad] Error in ad call.");
        //}
    };
    
    /**
     * Generates the prop2 (subdepartment) value using the given page name or screen name.
     * 
     * @param {String} name  page name or screen name
     */
    function generateProp2(name) {
		if (!name) {
			return null;
		}
		
        var names = name.split('.');
		var name0 = names[0];
        var prop;
		
		if (name0 == "mapquest") {
			// "External" names, such as those used by OnStar.
			names.pop();
			prop = names.join(".");
		} else {
			// Internal (typically page) names.
	        if (names.length >= 2) {
	            var name1 = names[1];
	            
	            if (name0 == "dir") {
	                name0 = "directions"; 
	            } else if ((name0 == "address") || (name0 == "settings") || (name0 == "traffic")) {
	                name1 = null;
	            }
	            
	            prop = name0 + (name1 ? (" " + name1) : "");
	        }
		}
        
        return prop;
    };
    
    /**
     * Gets the Omniture logger.
     * 
     * @param {String} acct  account
     * @param {boolean} isLink whether or not logging link information
     * @return logger info
     */
    function getLogger(acct, isLink) {
        var s = s_gi(acct);
        if (!s) {
            return;
        }
		
		if (isLink) {
			var trackVars = null;
			var trackEvents = null;
			
			if (acct == s_accountCL) {
				trackVars = "prop2,prop21,prop22,prop23,eVar1,eVar2";
				
				if (s_265.events) { 
					var events = s_265.events.split(',');
					var eventCount = events.length;
					var event;
					
					for (var i = 0; i < eventCount; ++i) {
						event = events[i];
						
						// Track events limited to a specific list.
						if ((event == "event1") || (event == "event2") || (event == "event3") || (event == "event4") || (event == "event5") || (event == "event6") || (event == "event11") || (event == "event12")) {
							if (trackEvents) {
								trackEvents += "," + event;
							} else {
								trackVars += ",events";			
								trackEvents = event;								
							}
						}
					}
				}
			}
			
	        s.linkTrackVars = (trackVars) ? trackVars : "None";
	        s.linkTrackEvents= (trackEvents) ? trackEvents : "None";
		}
		
        return s;
    };
    
    /**
     * Used for Selenium flow control.  Copied from old ua class.
     */
    function debugSelenium() {
        var selenium = m2.$("seleniumDebugger");
		if(selenium){
			var current = selenium.value;
			selenium.value = current + "\nok";
		}
    };

    /*
     * Public namespace.
     */
    
    m2.Omniture = {
        
        init : function(c) {
            controller = c;
        },
        
        showDebugger : function() {
            m2.util.removeClass(m2.$("userActionDebugger").parentNode, 'hiddenButPresent');
        },
        
        hideDebugger : function() {
            m2.util.addClass(m2.$("userActionDebugger").parentNode, 'hiddenButPresent');
        },
    	
    	clearDebugger : function(){
    		//Clears debugger
    		m2.$("userActionDebugger").value = "";
    	},
    	
    	// need this while the results pages are using both types of omniture
    	setInitialPageView : function(flag){
    		isInitialPageView = flag;
    	}
    };

    /*
     * Global functions.  Shortens the syntax required for logging.
     */
    
    window.$a = logAction;
    window.$awsn = logAction;
    window.$pv = logPageView;
    window.$od = debug;
    window._o = m2.Omniture;  // Namespace backward compatibility.
    window._o.$w = logAction; // Namespace backward compatibility.
    if (typeof window.promo == "undefined") { window.promo = promo; }
    if (typeof window.ua == "undefined") { window.ua = ua; }
})();
