/** * Iterates an array calling the passed function with each item, stopping if your function returns false. If the 
* passed array is not really an array, your function is called once with it. 
* The supplied function is called with (Object item, Number index, Array allItems). 
* @param {Array/NodeList/Mixed} array * @param {Function} fn * @param {Object} scope */ 
Ext.each = function (array, fn, scope) {    if(typeof array.length == "undefined" || typeof array == "string") {        array = [array];    }    for (var i = 0, len = array.length; i < len; i++) {        if (fn.call(scope || array[i], array[i], i, array) === false) { return i; };    } };

/*
 * Fix for the expanding icons to not throw Ext.fly(...) in IE.
 */
Ext.override(Ext.EventObjectImpl, {
    getTarget : function(selector, maxDepth, returnEl){
        var targetElement;

        try {
            targetElement = selector ? Ext.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
        } catch(e) {
            targetElement = this.target;
        }

        return targetElement;
    }
});

/* 
 * When leaving the BMO pages in IE an error is being thrown because document.getElementById == null
 * for some reason the getElementById function is null
*/
if (Ext.isIE) {
	Ext.apply(Ext, {
			/**
	         * Return the dom node for the passed string (id), dom node, or Ext.Element
	         * @param {Mixed} el
	         * @return HTMLElement
	         */
	        getDom : function(el){
	            if(!el || !document ||!document.getElementById /*Added check for IE to preven error mentioned above*/){
	                return null;
	            }
	            return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
	        }
	});
}
(function() {

var iofUrl = '';
var financialUrl = '';
var cfCreditAppUrl = '';
var bridgeUrl = '';
var extDimIofUrl='';

ASC.apply(ASC.cfg, {
	setIofUrl: function (newIofUrl)
	{
		if (typeof newIofUrl !== 'string') { return; }			
		iofUrl = newIofUrl;
	},
	getIofUrl: function () {
		return iofUrl;
	},
	
	setExtDimensionsIofUrl: function( newExtDimIofUrl ){
		if (typeof newExtDimIofUrl !== 'string') { return; }			
		extDimIofUrl = newExtDimIofUrl;
	},
	
	getExtDimensionsIofUrl: function(){
		return extDimIofUrl;
	},
	
	/**
	 * Return the IOF url excluding the ?IMG=EAL_IMAGES\ 
	 */
	getBaseIofUrl: function ()
	{		
		return iofUrl.split('?')[0];
	},
	
	getIofUrlEscaped: function () {
		return iofUrl.replace(/\\/g, '\\\\');
	},
	
	setFinancialUrl: function (url)
	{
		financialUrl = url;
	},
	
	getFinancialUrl: function ()
	{
		return financialUrl;
	},
	
	setCFCreditAppUrl: function (url)
	{
		cfCreditAppUrl = url;
	},
	
	getCFCreditAppUrl: function ()
	{
		return cfCreditAppUrl;
	},
	
	setBridgeUrl: function (url) 
	{
		bridgeUrl = url;
	},
	
	getBridgeUrl: function ()
	{
		return bridgeUrl;
	},
	
	/**
	 * For a given Brand return the matching host name url  This method will use the current hostname
	 * and replace the current brand with the switchToBrand parameter  Use this method to jump between
	 * brands
	 * @param {String} switchToBrand return the host name for this brand 'chrysler', 'dodge', or 'jeep'
	 * also accepts 'C', 'D', or 'J' NOTE: Case insensitive
	 */
	getBrandHostnameUrl: function (switchToBrand)
	{
		var brand = '';
		
		switch (switchToBrand.toUpperCase()) {
		case 'C':
		case 'CHRYSLER':
			brand = 'chrysler';
			break;
		case 'D':
		case 'DODGE':
			brand = 'dodge';
			break;
		case 'J':
		case 'JEEP':
			brand = 'jeep';
			break;
		default:
			brand = ASC.cfg.getTheme();
		}
		
		return window.location.protocol + '//' + window.location.hostname.replace(ASC.cfg.getTheme(), brand) + ASC.cfg.getContextPath();
	}
});

if (ASC_config) {
	if (ASC_config.iofUrl) {
		ASC.cfg.setIofUrl(ASC_config.iofUrl);
	}
	if (ASC_config.financialUrl) {
		ASC.cfg.setFinancialUrl(ASC_config.financialUrl);
	}
	if (ASC_config.bridgeUrl) {
		ASC.cfg.setBridgeUrl(ASC_config.bridgeUrl);
	}
	if (ASC_config.cfCreditAppUrl) {
		ASC.cfg.setCFCreditAppUrl(ASC_config.cfCreditAppUrl);
	}
	if (ASC_config.extDimensionsIofUrl) {
		ASC.cfg.setExtDimensionsIofUrl(ASC_config.extDimensionsIofUrl);
	}
}

})();

(function () {

	function cleanupMetricsParam(param)
	{
		if (typeof param !== 'string') { 
			param = param.toString();
		}
		param = ASC.util.trim(param);
		return param.replace(/(\s+)&(\s+)/g, " ") /*replace (space)&(space), for example Town & Country*/
			.replace(/[^a-z0-9,\s,+,-,_,\/]/gi,'')	/*convert invalid characters to ''*/
			.replace(/,\s/gi,' ').replace(/,/gi,' ')
			.replace(/\s+/g,"_") /*replace all spaces to _*/
			.replace(/\/\//g,'\/') /* remove double slashes*/
			.replace(/\//g,'_')	
			.toLowerCase();	
	}
	

	ASC.namespace('ASC.Chrysler');
	ASC.apply(ASC.Chrysler, {
		
		foo: function (str) {
			return cleanupMetricsParam(str);
		},
		
		imageOnError: function (img) 
		{		
			img.src = ASC.cfg.getBaseIofUrl() + '?IMG=CC_NOIMAGE_W.jpg';
			img.setAttribute('asc:imgName',img.src);	 
			img.onerror = null;
		},
				
		/**
		 * This method will execute a metrics request and should be used when the hitbox script cannot 
		 * auto-bind to the metrics event
		 * @param {String} lpos
		 * @param {String} lid
		 */
		trackLinkMetrics: function (lpos, lid)
		{
			linkTrack(cleanupMetricsParam(lpos), cleanupMetricsParam(lid));
			
			ASC.log('LPOS: ' + lpos + '\nLID: ' + lid);
		},
		
		/**
		 * Send a Page View request to the analytics website
		 * This function can be used from flash/flex components to record page views
		 * It can also be used to reset the page's MLC value 
		 */
		trackPageMetrics: function (mlc) 
		{		
			mlc = mlc.replace(/(\s+)&(\s+)/g, " ")	/*replace (space)&(space), for example in Town & Country*/
					 .replace(/\/(\s*)/g,"/").replace(/(\s*)\//g,"/"); /*replace (space)/ and /(space)*/
			var trackMLC = nameCleaner(mlc);			 			
 			var trackPN = hbx.pndef; // ignore the passed in Page Name 			 			
 			
 			var mlc = (trackMLC + ';/' + (ASC.cfg.getTheme()||'').toLowerCase() + '/' + trackMLC)
 				.replace('//', '/'); 			
 			_hbPageView(trackPN, mlc);
 			
 			ASC.log('PN: ' + trackPN + '\nMLC: ' + trackMLC);
		}	
	});

})();

(function () {	
	/**
	 * Protected event object used to fire custom events for when cookie values are changed 
	 * @private
	 * @type Ext.util.Observable 
	 */
	var cookieEvents =  new Ext.util.Observable();
	cookieEvents.addEvents({
		'dealerpf': true,
		'zipcode': true,
		'bmostate': true,
		'bmopayest': true
	});
	
	
	ASC.namespace('ASC.Chrysler.Cookies');
	ASC.apply(ASC.Chrysler.Cookies, {
		
		/**
		 * Persist a dealer as the user's preferred dealership for 2 years
		 * @param {String} dealerCode The ID of the dealer to be flagged as the preferred dealer
		 */
		setPreferredDealer: function (dealerCode)
		{
			var preferredDealer = ASC.Chrysler.Cookies.getPreferredDealer();
			var expires = new Date();
			expires.setFullYear(expires.getFullYear() + 2);
			ASC.Cookies.set('dealerpf', dealerCode, expires);
			cookieEvents.fireEvent('dealerpf', dealerCode, preferredDealer);			
		},
		
		/**
		 * @type String
		 * returns an Object with the Preferred Dealerships information
		 */
		getPreferredDealer: function ()
		{
			return ASC.Cookies.get('dealerpf');
		},
		
		/**
		 * Delete the user's preferred dealer cookie
		 */
		removePreferredDealer: function ()
		{
			//this.setPreferredDealer("");
			
			cookieEvents.fireEvent('dealerpf', null, ASC.Chrysler.Cookies.getPreferredDealer());
			ASC.Cookies.clear('dealerpf');
			
		},
		
		/**
		 * Add an event handler for the dealerpf cookie (fired on set/delete)
		 */
		onPreferredDealer: function (/**Function*/ handler, /**[Object]*/ scope, /**[Object]*/ options)
		{
			cookieEvents.on('dealerpf', handler, scope, options);
		},
		
		/**
		 * Retrieve Organic's User Data cookie
		 */
		 getUserData: function ()
		 {
		 	var json = ASC.Cookies.get('userdata') || '';
			var userdata = {
				audiopref: null,
				zipcode: null
			};		
			return ('' !== json ? ASC.apply(userdata, Ext.decode(json)) : userdata);	
		 },
		
		/**
		 * Store the user's zip code to a cookie (session cookie)
		 * @param {String} zipCode U.S. five digit Postal Code	 
		 */
		setZipCode: function (zipCode)
		{
			var prevZip = ASC.Cookies.get('zipcode');
			if(typeof inBound != 'undefined'){
				inBound.setZipCode(zipCode);
			}
		},
		
		/**
		 * Retrieve the user's zip code
		 * @type String
		 */
		getZipCode: function () 
		{
			var zipCode = ASC.Cookies.get('zipcode');
			return (zipCode !== null ? zipCode : this.getUserData().zipcode);
		},
		
		/**
		 * Delete the Zip Code cookie
		 */
		removeZipCode: function ()
		{
			ASC.Cookies.clear('zipcode');
			inBound.removeZipCode();
		},
		
		/**
		 * Add an event handler for the zipcode cookie (fired on set/delete)
		 */
		onZipCode: function (/**Function*/ handler, /**[Object]*/ scope, /**[Object]*/ options)
		{
			cookieEvents.on('zipcode', handler, scope, options);
		},
		
		/**
		 * Retrieve the BMO State from the Cookie
		 * @type Object
		 * @returns This method will always return an Object if the cookie did not exist the properties of the object
		 * will be null
		 */
		getBmo: function ()
		{	
			var json = ASC.Cookies.get('autodata.bmostate') || '';
			var bmo = {
				cCode: null,
				llpCode: null,
				stateString: null
			};		
			return ('' !== json ? ASC.apply(bmo, Ext.decode(json)) : bmo);			
		},
		
		/**
		 * Write the bmo state object to a cookie
		 * @param {Object} stateObj An object containing the BMO state values to be written to a cookie
		 */
		setBmo: function (/** Object */ stateObj) 
		{
			if (!stateObj) { return; }		
			var json = (ASC.isObject(stateObj) ? Ext.encode(stateObj) : stateObj);
			
			ASC.Cookies.set('autodata.bmostate', json);
			
			cookieEvents.fireEvent('bmostate', stateObj);
		},
				
		/**
		 * Add an event handler for the autodata.bmostate cookie (fired on set/delete)
		 */
		onBmo: function (/**Function*/ handler, /**[Object]*/ scope, /**[Object]*/ options)
		{
			cookieEvents.on('bmostate', handler, scope, options);
		},
		
		/**
		 * Retrieve the Chrysler Financial Payment Estimator state parameters
		 * @type Object
		 * @returns Returns null if the cookie could not be found
		 */
		getBmoPaymentEstimator: function ()
		{
			var json = ASC.Cookies.get('cf.payest');
			
			//Create the object structure first incase the object does not exist 
			var pe = {
				monthlyPmt: null,
		 		pmtTerm: null,
		 		pmtAPR: null
			};
			
			return ('' !== json ? ASC.apply(pe ,Ext.decode(json)) : pe);			
		},
		
		/**
		 * Store the Payment Estimator results in a cookie to allow it to be restored on
		 * all of the BMO pages
		 * @param {Object} stateObj JSON object that contains the Payment Estimator state
		 */
		setBmoPaymentEstimatorState: function (/** Object */ stateObj) 
		{	
			if (!stateObj) { return; }
			
			var path = ASC.cfg.getContextPath() + '/bmo';		
			var json = (ASC.isObject(stateObj) ? Ext.encode(stateObj) : stateObj);
			ASC.Cookies.set('cf.payest', json, null, path);	
			
			cookieEvents.fireEvent('bmopayest', stateObj);	
		},
		
		/**
		 * Add an event handler for the autodata.cf.payest cookie (fired on set/delete)
		 */
		onBmoPaymentEstimator: function (/**Function*/ handler, /**[Object]*/ scope, /**[Object]*/ options)
		{
			cookieEvents.on('bmopayest', handler, scope, options);
		}
	});
})();

(function () {
	var ACC = ASC.Chrysler.Cookies;
	
	ASC.apply(ASC.Chrysler, {
		/**
		 * Persist a dealer as the user's preferred dealership for 2 years
		 * @param {String} dealerCode The ID of the dealer to be flagged as the preferred dealer
		 */
		setPreferredDealer: function (dealerCode)
		{			
			ACC.setPreferredDealer(dealerCode);
			ASC.deprecated('ASC.Chrylser.setPreferredDealer use ASC.Chrysler.Cookies.setPreferredDealer');
		},
		
		/**
		 * @type String
		 * returns an Object with the Preferred Dealerships information
		 */
		getPreferredDealer: function ()
		{
			return ACC.getPreferredDealer();
			ASC.deprecated('ASC.Chrylser.getPreferredDealer use ASC.Chrysler.Cookies.getPreferredDealer');
		},
		
		/**
		 * Delete the user's preferred dealer cookie
		 */
		removePreferredDealer: function ()
		{
			ACC.removePreferredDealer();
			ASC.deprecated('ASC.Chrylser.removePreferredDealer use ASC.Chrysler.Cookies.removePreferredDealer');
		},
		
		/**
		 * Store the user's zip code to a cookie (session cookie)
		 * @param {String} zipCode U.S. five digit Postal Code	 
		 */
		setZipCode: function (zipCode)
		{
			ACC.setZipCode(zipCode);
			ASC.deprecated('ASC.Chrylser.setZipCode use ASC.Chrysler.Cookies.setZipCode');
		},
		
		/**
		 * Retrieve the user's zip code
		 * @type String
		 */
		getZipCode: function () 
		{
			return ACC.getZipCode();
			ASC.deprecated('ASC.Chrylser.getZipCode use ASC.Chrysler.Cookies.getZipCode');
		}
		
	});
})();



ASC.apply(ASC.Chrysler, {
    formatPhoneNumberUseHyphen: function (phoneStr)
    {
    	var str = null;
    	
    	if(phoneStr == null) { return ''; }
    	if(typeof(phoneStr) == 'string') {
    		str = phoneStr;
    	}
    	else { 
    		str = phoneStr.toString(); 
    	}    	
    	//remove the non numberic chars
    	str = str.replace(/[^\d]/g, '');
    	var sRes = '';
    	if(str.length == 7){
    		sRes = str.substr(0, 3) + '-' + str.substr(3);
    	}else if(str.length == 10){			
    		sRes = str.substr(0, 3) + '-' +  str.substr(3, 3) + '-' + str.substr(6);
    	}else {
    		sRes = '';
    	}
            	
    	return sRes;
    }, 
    
    setBoundPreferredDealer: function( dealerCode ){
    	var preferredDealerCode = ASC.Chrysler.Cookies.getPreferredDealer();
    	if( !preferredDealerCode || preferredDealerCode == 'null' || preferredDealerCode == ''  || (preferredDealerCode && preferredDealerCode != dealerCode)){
	    	//1. set ASC preferred dealer
	    	ASC.Chrysler.Cookies.setPreferredDealer(dealerCode);
	    	//2. set Organic preferred dealer
	    	inBound.setPreferredDealer(dealerCode);
    	}else if( preferredDealerCode == dealerCode ){
    		//1. set ASC preferred dealer
	    	ASC.Chrysler.Cookies.removePreferredDealer(dealerCode);
	    	//2. set Organic preferred dealer
	    	inBound.removePreferredDealer(dealerCode);
    	}
    }
});

/* Ext.override(ASC.Ajax.Response, {
	_failure: function (eRes, ioArgs)
	{
		window.location = ASC.cfg.getContextPath() + '/error.do?msg=' + encodeURIComponent(this.errors.join('\n'));
	}
});
*/


/**
 * Prevent any links that do not have any metrics parameters defined from executing hitbox's _hbSend method
 * If a link is present in the Dom when the window.onload event is executed hitbox will automatically bind to the 
 * click event of the link.  This method will ensure that only links with an lpos defined execute the metrics
 * request
 */
function _hbOnLink(a)
{				
	if (a && (a.getAttribute('name')||'').indexOf('&lpos=') === -1) {
		_hbHalt();
	}
}

ASC.namespace('ASC.Chrysler.Panel');
ASC.Chrysler.Panel = Ext.extend(Ext.Panel, {
		
	constructor: function (config)
	{
		ASC.Chrysler.Panel.superclass.constructor.call(this, config);
	},
	
 	/**
	 * Aligns the window to the specified element
	 * @param {Mixed} element The element to align to.
	 * @param {String} position The position to align to (see {@link Ext.Element#alignTo} for more details).
	 * @param {Array} offsets (optional) Offset the positioning by [x, y]
	 * @return {Ext.Window} this
	 */
	alignTo: function (element, position, offsets)
	{
		var xy = this.el.getAlignToXY(element, position, offsets);
		this.setPagePosition(xy[0], xy[1]);
		
		ASC.log('x: ' + xy[0] + ' y: ' + xy[1]);
		
		return this;
	},
	
	/**
	 * Anchors this window to another element and realigns it when the window is resized or scrolled.
	 * @param {Mixed} element The element to align to.
	 * @param {String} position The position to align to (see {@link Ext.Element#alignTo} for more details)
	 * @param {Array} offsets (optional) Offset the positioning by [x, y]
	 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
	 * is a number, it is used as the buffer delay (defaults to 50ms).
	 * @return {Ext.Window} this
	 */
	anchorTo: function (el, alignment, offsets, monitorScroll, _pname)
	{
		var action = function(){
				this.alignTo(el, alignment, offsets);
		};
		Ext.EventManager.onWindowResize(action, this);
		var tm = typeof monitorScroll;
		if(tm != 'undefined'){
			Ext.EventManager.on(window, 'scroll', action, this, {buffer: tm == 'number' ? monitorScroll : 50});
		}
		action.call(this);
		this[_pname] = action;
		return this;
	}
});
