
if (!ContextManager) {
    var ContextManager = {
        /**
         * Populate ContextManager with properties supplied by backend
         */
        init: function(paramOb){
            var k;
            for (var k in paramOb) {
                ContextManager[k] = paramOb[k];
            }
            // start session 
            var d = new Date();
            var start = d.getTime();
            var dur = 240000;
            // 4 min = 240000 ms
            ContextManager.session = {
                duration: dur,
                startTime: start
            };
            //
            ContextManager.InventoryManagerRef = (window.InventoryManager) ? InventoryManager : {};
            // If InventoryManager does not exist, just set up a dummy that returns null
            if (!ContextManager.InventoryManagerRef.getProperty) {
                ContextManager.InventoryManagerRef.getProperty = function(prop){
                    return null
                };
            }
        },
        
        /********************************************************************************/
        /* Helper Methods */
        
		setPageMonitoring: function(value){
			ContextManager.pageMonitoring = value;
        },
		
        getPageMonitoring: function(){
			return (ContextManager.pageMonitoring === true || ContextManager.pageMonitoring === "true");
        },
		setSessionStartTime: function(timestamp){
            ContextManager.getSession().startTime = timestamp;
        },
        getSession: function(){
            return ContextManager.session;
        },
        getSessionStartTime: function(){
            return ContextManager.getSession().startTime;
        },
        getSessionDuration: function(){
            return ContextManager.getSession().duration;
        },
        
        isProd: function(){
            return (ContextManager.getEnvName()) ? (ContextManager.getEnvName().toLowerCase() == "prod") : false;
        },
        
        isLive: function(){
            return (ContextManager.getVersion()) ? (ContextManager.getVersion().toLowerCase() == "live") : false;
        },
        
        /********************************************************************************/
        /* Env specific data */
        
        getTrafficServerUrl: function(){
            return ContextManager.trafficServerUrl;
        },
        getAssetServerUrl: function(){
            return ContextManager.assetServerUrl;
        },
        getVersionedAssetServerUrl: function(){
            return ContextManager.versionedAssetServerUrl;
        },
        getEnvName: function(){
            return ContextManager.envName;
        },
        
        /********************************************************************************/
        /* Visit specific data */
        
        getSessionId: function(){
            return ContextManager.sessionId;
        },
        getEventId: function(){
            return ContextManager.eventId;
        },
        getPageName: function(){
            return ContextManager.pageName;
        },
        getPageLayout: function(){
            return ContextManager.pageLayout;
        },
        getPageLabel: function(){
            return ContextManager.pageLabel;
        },
        getRequestDomain: function(){
            return ContextManager.requestDomain;
        },
        getRequestUri: function(){
            return ContextManager.requestUri;
        },
        getReferrerDomain: function(){
            return ContextManager.referrerDomain;
        },
        getReferrerUri: function(){
            return ContextManager.referrerUri;
        },
        getVisitorId: function(){
            return ContextManager.visitorId;
        },
        getLeadId: function(){
            return ContextManager.leadId;
        },
        
        /********************************************************************************/
        /* Site specific data */
        
        getDealershipName: function(){
            return ContextManager.dealershipName;
        },
        getWebId: function(){
            return ContextManager.webId;
        },
        getSiteId: function(){
            return ContextManager.siteId;
        },
        getDealerCode: function(){
            return ContextManager.dealerCode;
        },
        getUrl: function(){
            return ContextManager.url;
        },
        
        getFranchises: function(){
            return ContextManager.franchises;
        },
        getSiteGroups: function(){
            return ContextManager.siteGroups;
        },
        
        getVersion: function(){
            return ContextManager.version;
        },
        getSiteType: function(){
            return ContextManager.siteType;
        },
        getSubType: function(){
            return ContextManager.subType;
        },
        getLocale: function(){
            return ContextManager.locale;
        },
        
        getAddressLine1: function(){
            return ContextManager.addressLine1;
        },
        getAddressLine2: function(){
            return ContextManager.addressLine2;
        },
        getCity: function(){
            return ContextManager.city;
        },
        getState: function(){
            return ContextManager.state;
        },
        getPreferredCity: function(){
            return ContextManager.preferredCity;
        },
        getPreferredState: function(){
            return ContextManager.preferredState;
        },
        getZip: function(){
            return ContextManager.zip;
        },
        getRadius: function(){
            return ContextManager.radius;
        },        
        getLatitude: function(){
            return ContextManager.latitude;
        },
        getLongitude: function(){
            return ContextManager.longitude;
        },
        
        getDesign: function(){
            return ContextManager.design;
        },
        getTheme: function(){
            return ContextManager.theme;
        },
        getColor: function(){
            return ContextManager.color;
        },
        
        getNewPhone: function(){
            return ContextManager.newPhone;
        },
        getUsedPhone: function(){
            return ContextManager.usedPhone;
        },
        getFinancePhone: function(){
            return ContextManager.financePhone;
        },
        getPrimaryPhone: function(){
            return ContextManager.primaryPhone;
        },
        getFleetPhone: function(){
            return ContextManager.fleetPhone;
        },
        getPartsPhone: function(){
            return ContextManager.partsPhone;
        },
        getServicePhone: function(){
            return ContextManager.servicePhone;
        },
        
        /********************************************************************************/
        /* LSLP specific data */
        
        getDma: function(){
            return ContextManager.dma;
        },
        getVisitorZip: function(){
            return ContextManager.visitorZip;
        },
		getSelectedWebId: function(){
			return ContextManager.selectedWebId;
		}, 
        
        /********************************************************************************/
        /* Promo specific data */
        
        getPromoName: function(){
            return ContextManager.promoName;
        },
        getPromoMode: function(){
            return ContextManager.promoMode;
        },
        getPromotions: function(){
        	return ContextManager.promotions;
        },
        getDynamicParams:function(){
        	return ContextManager.dynamicParams;
        },
        /********************************************************************************/
        /* INV getters */
        
        getMake: function(){
            return ContextManager.getInventoryProperty("make");
        },
        getModel: function(){
            return ContextManager.getInventoryProperty("model");
        },
        getTrim: function(){
            return ContextManager.getInventoryProperty("trim");
        },
		getSeries: function(){
            return ContextManager.getInventoryProperty("series");
        },
        getBodyType: function(){
            return ContextManager.getInventoryProperty("bodyType");
        },
        getExteriorColor: function(){
            return ContextManager.getInventoryProperty("exteriorColor");
        },
        getPrice: function(){
            return ContextManager.getInventoryProperty("retailPrice");
        },
        getModelId: function(){
            return ContextManager.getInventoryProperty("modelId");
        },
        getStyleId: function(){
            return ContextManager.getInventoryProperty("styleId");
        },
        getVin: function(){
            return ContextManager.getInventoryProperty("vin");
        },
        getYear: function(){
            return ContextManager.getInventoryProperty("year");
        },
        
        /* INV Search Specific getters */
        
        getSearch: function(){
            return ContextManager.getInventoryProperty("search");
        },
        getSearchMake: function(){
            return ContextManager.getInventoryProperty("make");
        },
        getSearchModel: function(){
            return ContextManager.getInventoryProperty("model");
        },
        getSearchTrim: function(){
            return ContextManager.getInventoryProperty("trim");
        },
		getSearchSeries: function(){
            return ContextManager.getInventoryProperty("series");
        },
        getSearchBodyType: function(){
            return ContextManager.getInventoryProperty("bodyType");
        },
        getMileageRange: function(){
            return ContextManager.getInventoryProperty("mileageRange");
        },
        getPaymentRange: function(){
            return ContextManager.getInventoryProperty("paymentRange");
        },
        getPriceRange: function(){
            return ContextManager.getInventoryProperty("priceRange");
        },
        getYearRange: function(){
            return ContextManager.getInventoryProperty("yearRange");
        },
        getPageNumber: function(){
            return ContextManager.getInventoryProperty("pageNumber");
        },
        getResultCount: function(){
            return ContextManager.getInventoryProperty("resultCount");
        },
        
        /*****************************/
        
        /* Generic getter */
        getProperty: function(prop){
            var getter = ContextManager.getterMap[prop];
            var val;
            var defaultKey = "default";
            if (getter) {
                if ((typeof getter == "string") && (typeof ContextManager[getter] == "function")) {
                    val = ContextManager[getter]();
                }
                else if (typeof getter == "object") {
					var thisPage = ContextManager.getPageName();
					if ((getter[thisPage]) && (typeof ContextManager[getter[thisPage]] == "function")) {
						val = ContextManager[getter[thisPage]]();
					} else if ((getter[defaultKey]) && (typeof ContextManager[getter[defaultKey]] == "function")) {
						val = ContextManager[getter[defaultKey]]();
					}
				}
            }
            return val || ContextManager.getContextProperty(prop);
        },
        
        /*****************************/
        
        getInventoryProperty: function(prop){
            return ContextManager.InventoryManagerRef.getProperty(prop) || ContextManager.getContextProperty(prop);
        },
        
        /*****************************/
        
        getContextProperty: function(prop){
            if (ContextManager[prop]) {
                return ContextManager[prop];
            }
            else {
                switch (prop) {
                    case "make":
                        if (ContextManager.getPageName() == "VehicleDetails") {
                            return jQuery("#gaq input[name$=':make']").val();
                        }
                        return null;
                        break;
                    case 'model':
                        if (ContextManager.getPageName() == "VehicleDetails") {
                            return jQuery("#gaq input[name$=':model']").val();
                        }
                        return null;
                        
                        break;
                    case 'trim':
                        if (ContextManager.getPageName() == "VehicleDetails") {
                            return jQuery("#gaq input[name$=':trim']").val();
                        }
                        return null;
                        
                        break;
                        
					case 'series':
                        if (ContextManager.getPageName() == "VehicleSearchResults") {
                            return jQuery("#inv_search_series").val();
                        }
                        return null;
                        break;
                    case 'search':
                        if (ContextManager.getPageName() == "VehicleDetails") {
                            return jQuery("#gaq input[name='search']").val()
                        }
                        return null;
                        
                        break;
                    case 'bodyType':
                        if (ContextManager.getPageName() == "VehicleDetails") {
                            return jQuery("#gaq input[name='bodyType']").val();
                        }
                        return null;
                        
                        break;
                    case 'exteriorColor':
                        if (ContextManager.getPageName() == "VehicleDetails") {
                            return jQuery("#gaq input[name*='exteriorcolor']").val();
                        }
                        return null;
                        
                        break;
                    case 'retailPrice':
                        if (ContextManager.getPageName() == "VehicleDetails") {
                            return jQuery("#gaq input[name$='price:asking']").val();
                        }
                        return null;
                        
                        break;
                    case 'modelId':
                        if (ContextManager.getPageName() == "VehicleDetails") {
                            return jQuery("#gaq input[name='modelId']").val();
                        }
                        return null;
                        
                        break;
                    case 'styleId':
                        if (ContextManager.getPageName() == "VehicleDetails") {
                            return jQuery("#gaq input[name='styleId']").val();
                        }
                        return null;
                        
                        break;
                    case 'year':
                        if (ContextManager.getPageName() == "VehicleDetails") {
                            return jQuery("#gaq input[name$=':year']").val();
                        }
                        return null;
                        
                        break;
                        
                    case 'pageNumber':
                        if (ContextManager.getPageName() == "VehicleSearchResults") {
                            return jQuery("#currentPageCount").text();
                        }
                        return null;
                        
                        break;
                    case 'resultCount':
                        if (ContextManager.getPageName() == "VehicleSearchResults") {
                            return jQuery("#resultCount").val();
                        }
                        return null;
                        
                        break;
                        
                    default:
                        // does not exist
                        return null;
                }
                return null;
            }
        },
        
        getterMap: {
            trafficServerUrl: "getTrafficServerUrl",
            assetServerUrl: "getAssetServerUrl",
            versionedAssetServerUrl: "getVersionedAssetServerUrl",
            envName: "getEnvName",
            
            sessionId: "getSessionId",
            eventId: "getEventId",
            pageName: "getPageName",
            pageLabel: "getPageLabel",
            pageLayout: "getPageLayout",
            requestDomain: "getRequestDomain",
            requestUri: "getRequestUri",
            referrerDomain: "getReferrerDomain",
            referrerUri: "getReferrerUri",
            visitorId: "getVisitorId",
            leadId: "getLeadId",
            
            dealershipName: "getDealershipName",
            webId: "getWebId",
            siteId: "getSiteId",
            dealerCode: "getDealerCode",
            url: "getUrl",
            franchises: "getFranchises",
            siteGroups: "getSiteGroups",
            version: "getVersion",
            siteType: "getSiteType",
            subType: "getSubType",
            locale: "getLocale",
            addressLine1: "getAddressLine1",
            addressLine2: "getAddressLine2",
            city: "getCity",
            state: "getState",
            preferredCity: "getPreferredCity",
            preferredState: "getPreferredState",
            zip: "getZip",
            radius: "getRadius",
            latitude: "getLatitude",
            longitude: "getLongitude",
            design: "getDesign",
            theme: "getTheme",
            color: "getColor",
            newPhone: "getNewPhone",
            usedPhone: "getUsedPhone",
            financePhone: "getFinancePhone",
            primaryPhone: "getPrimaryPhone",
            fleetPhone: "getFleetPhone",
            partsPhone: "getPartsPhone",
            servicePhone: "getServicePhone",
            
            make: {
                VehicleSearchResults: "getSearchMake",
                VehicleDetails: "getMake",
                "default": "getMake"
            },
            model: {
                VehicleSearchResults: "getSearchModel",
                VehicleDetails: "getModel",
                "default": "getModel"
            },
            trim: {
                VehicleSearchResults: "getSearchTrim",
                VehicleDetails: "getTrim",
                "default": "getTrim"
            },
            bodyType: {
                VehicleSearchResults: "getSearchBodyType",
                VehicleDetails: "getBodyType",
                "default": "getBodyType"
            },
			series: {
                VehicleSearchResults: "getSearchSeries",
                VehicleDetails: "getSeries",
                "default": "getSeries"
            },
            search: "getSearch",
            mileageRange: "getMileageRange",
            paymentRange: "getPaymentRange",
            priceRange: "getPriceRange",
            yearRange: "getYearRange",
            vin: "getVin",
            exteriorColor: "getExteriorColor",
            price: "getPrice",
            modelId: "getModelId",
            styleId: "getStyleId",
            year: "getYear",
            pageNumber: "getPageNumber",
            resultCount: "getResultCount",
            
            dma: "getDma",
            visitorZip: "getVisitorZip",
            promoName: "getPromoName",
            promotions: "getPromotions",
            dynamicParams: "getDynamicParams"	
        },
        /********************************************************************************/
        /**
         * Given a param string, update any relevant Context properties
         */
        updateProperties: function(params){
            var paramOb = ContextManager.parseParamString(params);
            //
            for (var k in paramOb) {
                switch (k) {
                    // handle special INV cases
                    case 'make':
                    case 'model':
                    case 'trim':
                    case 'search':
                    case 'bodyType':
                    case 'minMileage':
                    case 'maxMileage':
                    case 'minMonthlyPayment':
                    case 'maxMonthlyPayment':
                    case 'minPrice':
                    case 'maxPrice':
                    case 'minYear':
                    case 'maxYear':
                        ContextManager.updateInventoryProperties(k, paramOb);
                        break;
                    default:
                        if (paramOb[k] != undefined) {
                            ContextManager[k] = paramOb[k];
                        }
                }
            }
        },
        updateInventoryProperties: function(k, paramOb){
            switch (k) {
                case 'make':
                case 'model':
                case 'trim':
                case 'bodyType':
                    if (paramOb[k] != undefined) {
                        ContextManager[k] = (paramOb[k] == "" || paramOb[k] == "all") ? 'All' : paramOb[k];
                    }
                    break;
                case 'search':
                    ContextManager.search = paramOb.search;
                    break;
                case 'minMileage':
                case 'maxMileage':
                    ContextManager.mileageRange = paramOb.minMileage + '-' + paramOb.maxMileage;
                    break;
            }
            ContextManager.paymentRange = (paramOb.minMonthlyPayment) ? paramOb.minMonthlyPayment + '-' + paramOb.maxMonthlyPayment : 'unspecified';
            ContextManager.priceRange = (paramOb.minPrice) ? paramOb.minPrice + '-' + paramOb.maxPrice : 'unspecified';
            ContextManager.yearRange = (paramOb.minYear) ? paramOb.minYear + '-' + paramOb.maxYear : 'All';
        },
        //
        parseParamString: function(params){
            var i, temp;
            // split the params
            var pArray = params.split("&");
            // hash to store result
            var pHash = {};
            // Determine if search is being updated, is so reset the search array
            if (params.indexOf('search=') != -1) {
                pHash.search = [];
            }
            // parse each param in the array and put it in the hash
            for (i = 0; i < pArray.length; i++) {
                temp = pArray[i].split("=");
                // add search params to array
                if (temp[0] == 'search') {
                    if (!ContextManager.valueInArray(pHash.search, temp[1])) {
                        pHash.search.push(temp[1]);
                    }
                }
                else {
                    pHash[temp[0]] = ContextManager.URLEncode(unescape(temp[1]));
                }
            }
            return pHash;
        },
        //
        valueInArray: function(arr, val){
            var len = arr.length;
            var i;
            for (i = 0; i < len; i++) {
                if (arr[i] == val) {
                    return true;
                }
            }
            return false;
        },
        /**
         * URLEncode provides more accurate encoding than native Javascript functions.
         */
        URLEncode: function(str){
            // The Javascript escape and unescape functions do not correspond
            // with what browsers actually do...
            var SAFECHARS = "0123456789" + // Numeric
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + // Alphabetic
            "abcdefghijklmnopqrstuvwxyz" +
            "-_.!~*'()"; // RFC2396 Mark characters
            var HEX = "0123456789ABCDEF";
            
            var encoded = "";
            for (var i = 0; i < str.length; i++) {
                var ch = str.charAt(i);
                if (ch == " ") {
                    encoded += "+"; // x-www-urlencoded, rather than %20
                }
                else 
                    if (SAFECHARS.indexOf(ch) != -1) {
                        encoded += ch;
                    }
                    else {
                        var charCode = ch.charCodeAt(0);
                        if (charCode > 255) {
                            /*
                         alert( "Unicode Character '"
                         + ch
                         + "' cannot be encoded using standard URL encoding.\n" +
                         "(URL encoding only supports 8-bit characters.)\n" +
                         "A space (+) will be substituted." );
                         */
                            encoded += "+";
                        }
                        else {
                            encoded += "%";
                            encoded += HEX.charAt((charCode >> 4) & 0xF);
                            encoded += HEX.charAt(charCode & 0xF);
                        }
                    }
            } // for
            return encoded;
        },
        
        // functions to generate a GUID
        /**
         * Return 4-char random string
         */
        S4: function(){
            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
        },
        /**
         * Get a 12-char event ID suffix: used for Cobalt pixel tag
         */
        generateEventIdSuffix: function(){
            return ContextManager.generateUid(12);
        },
        /**
         * Get a full 44-char event ID
         */
        generateEventId: function(){
            return ContextManager.generateUid(44);
        },
        /**
         * Generate a UID of variable length.
         */
        generateUid: function(length){
            var i;
            var unit = 4;
            var st = "";
            // determine # of iterations - each unit is 4 chars
            var count = Math.ceil(length / unit);
            for (i = 1; i <= count; i++) {
                st += ContextManager.S4();
            }
            return st.substr(0, length);
        }
        // END : functions to generate a GUID
    };
}





