(function($) {
    if (typeof $.Aloha === 'undefined') {
        $.Aloha = {}
    }
	/**
	 * This object is used to keep track of the abn state for phone/plan.
	 * Our datastructure is a hashmap of hashmap. The second hashmap is used to store
	 * all values.
	 * The key is an category name(carrier, feature, phone price) and the value is a binName. 
	 * For example, for Feature(featureBluetooth, featureWebBrowsing).
	 * We also use this data structure to store key/value pair.
	 */
	var AbnState = (function() {
	    
	    var mapHash = {};
	    
	    /**
	     * Clear the abn state object.
	     */
	    function clearState() {
	        mapHash = {};
	    }
	    
	    /**
	    * Add an element to abn state where cat is the key and binName is the value.
	    * @param {Object} cat - this is the name of the category. For example, (carrier, feature..) 
	    * @param {Object} binName -- this is the bin name of the category. For example. (For Feature, 
	    * featureBluetooth, featureWebBrowsing).
	    */
	    function addElement(cat, binName) {
	        if (typeof binName !== 'undefined' && binName !== ''){
	            var categoryHashTable = mapHash[cat];
	            if (typeof categoryHashTable === 'undefined') {
	                categoryHashTable = {};
	            }
	            categoryHashTable[binName] = "";
	            mapHash[cat] = categoryHashTable;
	        }
	    }

	    function removeCategory(category) {
		delete mapHash[category];
	    }
	    
	    /**
	     * This is the opposite of addElement.
	     * We attempt to remove a binName from our hash of hash where cat is the key
	     * @param {Object} cat - this is the key to the hash. 
	     * @param {Object} binName - this is the value to be removed. 
	     */
	    function removeElement(cat, binName) {
	        var categoryHashTable = mapHash[cat];
	        if (typeof categoryHashTable !== 'undefined') {
	            delete categoryHashTable[binName];
	            mapHash[cat] = categoryHashTable;
	        }
	    }
	    
	    /**
	     * Given a hashtable, we go through and append all the values in the 
	     * hashtable into a string.
	     * @param {Object} hashTable
	     */
	    function hashTableToString(hashTable) {
	        var array = [], el;
	        for (el in hashTable) {
	            array.push(el);
	        }
	        return array.toString();
	    }
	
	    /**
	    * We turn the values in our abnstate into String format that can send
	    * back to the server. The data is in key/value pair format where & is the separator. 
	    */
	    function toString() {
	        var result = [], category, categoryHashTable;
	        for (category in mapHash) {
	            categoryHashTable = mapHash[category];
		    result.push(category + "=" + hashTableToString(categoryHashTable));
	        }
	        return result.join("&");
	    }
	    /**
	     * This is our public methods to the world.
	     */
	    return {
	        clearState: clearState,
	        addElement: addElement,
	        removeElement: removeElement, 
		removeCategory: removeCategory,
	        toString: toString
	    };
	})();

	/**
	 * This class is used for both phone and plan abn.
	 * It contains methods that can be shared by both abns.
	 */
	var Browse = (function() {
	    
	    // Constants
	    var CHANGE_ZIP_SELECTOR = '#changeZip';
	    var CHANGE_ZIP_HIDDEN_WRAPPER = '#input-zip-wrapper';
	    var ZIP_CODE = '#zip-code-submit';
	    var HOVER = 'hover';
	    var CHECKED = 'checked';
	    var KEYWORDS = 'keywords';
	    var NODE_ID = 'nodeID';
	    var CARRIER = 'categoryCarrier';
	    var CHECKBOX_SPAN = 'span.checkbox';
	    var AJAX_PATH = '/searchRequest';
	    //indicates that there is an active ajax call that comes from clicking on the abn.
	    var isActiveAbnAjaxCall = false;
	    
		var Util = $.Aloha.Util;
		var AjaxUtil = $.Aloha.AjaxUtil;
       
	/**
	 * This method is used to determine whether the category in the abn is checked.
	 * @param {Object} abnCategoryObj - an jquery object that has "li span"
	 * elements for the checkbox
	 */
        function containsCheckedAbnCheckBox(abnCategoryObj) {
        var hasCheckedCheckBox = false;
            var abnCategorySpanObj = abnCategoryObj.find("li span");
            abnCategorySpanObj.each(function(i, spanEl) {
                var spanElObj = $(spanEl);
                if(spanElObj.hasClass(CHECKED)) {
                hasCheckedCheckBox = true;
                //this is to break out of the for each loop
                return true;
		}
	    });
	    return hasCheckedCheckBox;
	}
        /**
         * This method is used to clear each category in the abn phone and plan page everytime
         * the user clicks on the clear link on the abn page.
         * Everytime we clear a checkbox, we also remove its value from out AbnState object. 
         * @param {Object} abnCategoryWrapperObj - expects a Jquery object that contains the 
         * abn category data.
         */
        function clearAbnCategoryCheckBox(abnCategoryWrapperObj) {
            var abnCategorySpanObj = abnCategoryWrapperObj.find("li span");
            abnCategorySpanObj.each(function(i, spanEl) {
                var spanElObj = $(spanEl);
                if(spanElObj.hasClass(CHECKED)) {
                    //remove the checked box
                    spanElObj.removeClass(CHECKED);
                    var category = spanElObj.attr("name");
                    var value = spanElObj.attr("value");
                    AbnState.removeElement(category, value);
                }
            });
        }
	    /**
	     * This is a utility method that is used to do Ajax call for Browse.
	     * All this does is calling Util.ajaxCall. We also write requestData to
	     * hidden input value to the html. This is later used when the back button is invoked.
	     * @param {Object} path - the url of our server.
	     * @param {Object} requestData - data to pass back to the server.
	     * @param {Object} successCallBack - a callback method when ajax is successful.
	     * @param {Object} errorCallBack - a callback method when ajax failed.
	     */
	    function ajaxCall(path, requestData, successCallBack, errorCallBack) {
            //writes out the abn query into our html. This is picked up later on
			//when the user clicks the back button.
            $("#historyHidden").find('input[name="abnHistory"]').val(requestData);
	        AjaxUtil.ajaxCall(path, requestData, successCallBack, errorCallBack);
	    }
	    
	    
	    /**
	     * cancel any previous pending ajax call.
	     */
	    function cancelActiveAjaxCall() {
	        AjaxUtil.cancelActiveAjaxCall();
	    }
	    
        /**
         * return all the abn data for browse that can be used to send back to the server.
         */
	    function getBrowseSearchRequestQuery() {
	        return AbnState.toString() + "&" + searchRequestData.toString();
	    }
	 
        var searchRequestData = (function() {
	        var abnSearchData = {
			getKeywords: function() {
				return $.url.param(KEYWORDS) || "";
			},
			getNodeId: function() {
				return $.url.param(NODE_ID) || window.location.pathname.match(/\d+/) || "";
			},
			getPageSize: function() {
				return $("div #pageSize").attr("value") || "";
			},
			getRank: function() {
				return $("#rank").attr("value") || "";
			}
		   };
		  	var abSearchKeyFunctionMap = {"keywords":abnSearchData.getKeywords,"nodeID":abnSearchData.getNodeId,
							"pageSize":abnSearchData.getPageSize,"rank":abnSearchData.getRank};
	
			var keyEntries = (function(){
				var k = {}, v;
				for (v in abSearchKeyFunctionMap) {
					k[v] = "";
				}
				return k;
			})();
			var abnSearchToString = (function() {
				var k, func, result = [];
				for (k in abSearchKeyFunctionMap) {
					func = abSearchKeyFunctionMap[k];
					result.push(k + "=" + func());
				}
				return result.join("&");
			})();
			return {
				toString: function() {
					return abnSearchToString;
				},
				getKeys: function() {
					return keyEntries;
				}
			};
        })();
	  
	   /**
	    * This method is used to register event handlers to clear abn category
	    * We are expecting that there is a hidden field that is a silbing of 
	    * .abnClear class that would describe what we should clear.
	    * @param {Object} ajaxSuccessCallBack
	    * @param {Object} ajaxErrorCallBack
	    */
        function registerClearAbnEventHandlers(ajaxSuccessCallBack, ajaxErrorCallBack) {
	        $('#abn #phones-abn .abnClear').each(function(i, trigger) {
	            var trigger = $(trigger);
	            trigger.unbind('click').bind('click', function() {
	                var classToClear = trigger.parent().find('input[name="classToClear"]').val();
	                var objToClear = $(classToClear);
	                var isContainCheckedCheckbox = containsCheckedAbnCheckBox(objToClear);
	                if (isContainCheckedCheckbox) {
	                    clearAbnCategoryCheckBox(objToClear);
	                    var query = getBrowseSearchRequestQuery();
	                    ajaxCall(AJAX_PATH, query, ajaxSuccessCallBack, ajaxErrorCallBack);
	                }
			return false;
	            });
	        });
        }
        function registerZipCodeHandlers() {
           $(CHANGE_ZIP_SELECTOR).bind('click', function(){
                $(CHANGE_ZIP_HIDDEN_WRAPPER).removeClass('hidden'); return false;
            })
        }
	    /**
	     * Pagination event 
	     * @param {Object} ajaxSuccessCallBack
	     * @param {Object} ajaxErrorCallBack
	     */
	    function registerPaginationHandlers(ajaxSuccessCallBack, ajaxErrorCallBack) {
	        var NAV_PREVIOUS_PAGE = '.previous-page';
	        var NAV_NEXT_PAGE = '.next-page';
	        var NAV_TOP_PAGINATION = '#search-nav-top .pagination';
	        var NAV_BOTTOM_PAGINATION = '#search-nav-bottom .pagination';
	        var NAV_CURRENT_PAGE = '.current-page';
	        var NAV_PENDING_PAGE = '.pending-page';
	        var DISABLED = 'disabled';
	        
	        //util functions for next/previous page.
	        var pageGuidance = {
	            incr: function (value) {
	                return value + 1;
	            },
	            decr: function(value) {
	                return value - 1;
	            }
	        }
	        /**
	         * We have a concept of a pending-page and current-page.
	         * Current page is a page that is currently being displayed to the user.
	         * The page number is bold and black.
	         * Pending page is a page that is currently being requested by Ajax.
	         * It is being represented in the front end by a light background color.
	         */
	        /**
	         * This function is used to control both previous and next link
	         * on the navigation var.
	         * @param {Object} paginationObj - the navigation object.
	         * @param {Object} navPageStr - the css class name for navigation page.
	         * @param {Object} nextPageGuidanceFnc - given a the current page number, this
	         * function would returns the next page.
	         * @param {Object} disableClassStr - this string represents a css class
	         * when to disable itself. For example (last-page 
	         * is for Next while first-page is for Previous).
	         * @param {Object} ajaxSuccessCallBack
	         * @param {Object} ajaxErrorCallBack
	         */
	        function pagMove(paginationObj, navPageStr, nextPageGuidanceFnc, disableClassStr, ajaxSuccessCallBack, ajaxErrorCallBack) {
	            var navObj = paginationObj.find(navPageStr);
	            navObj.unbind('mousedown').bind('mousedown', function() {
	                var trigger = $(this);
	                if (!trigger.hasClass(DISABLED)) {
	                    var currentPendingPageNum = paginationObj.find(NAV_PENDING_PAGE).attr('value');
	                    var currentPageNum = paginationObj.find(NAV_CURRENT_PAGE).attr('value');
	                    //get the next pending page.
	                    var newPendingPage = nextPageGuidanceFnc(parseInt(currentPendingPageNum || currentPageNum));
	                    var elNewPendingPageObj = paginationObj.find('.page' + newPendingPage);
	                    //if there is currently a pending page, we would remove this class.
	                    if (!isNaN(currentPendingPageNum)) {
	                        paginationObj.find('.page' + currentPendingPageNum).removeClass('pending-page');
	                    }
	                    //set new pending page.
	                    elNewPendingPageObj.addClass('pending-page');
	                    //check to see if we should disable Next or Previous link.
	                    if (elNewPendingPageObj.hasClass(disableClassStr)) {
	                        navObj.addClass(DISABLED);
	                    } else {
	                        //the user is requesting page [2 - n-1].
	                        //our Next and Previous links should be enabled.
	                        var nextPageObj = paginationObj.find(NAV_NEXT_PAGE);
	                        if (nextPageObj.hasClass(DISABLED)) {
	                            nextPageObj.removeClass(DISABLED);
	                        }
	                        var previousPageObj = paginationObj.find(NAV_PREVIOUS_PAGE); 
	                        if (previousPageObj.hasClass(DISABLED)) {
	                            previousPageObj.removeClass(DISABLED);
	                        }
	                    }
	                    //if the new requested page (newPendingPage) is equal to 
	                    //the current page, we cancel the previous ajax call. 
	                    if (currentPageNum == newPendingPage) {
	                        //if there is currently a pending abn ajax call
	                        //we do not cancel
	                        if (!isActiveAbnAjaxCall) {
                                //remove the curent pending page
                                paginationObj.find('.page' + currentPageNum).removeClass('pending-page');
	                            cancelActiveAjaxCall();
	                        }
	                    } else {
	                        var query = getBrowseSearchRequestQuery() + "&pageNumber=" + newPendingPage;
	                        ajaxCall(AJAX_PATH, query, ajaxSuccessCallBack, ajaxErrorCallBack);
	                    }
	                }
	                return false;
	            });
	        }
		     //invoking pagination 
		    (function() {
		        var topPaginationObj = $(NAV_TOP_PAGINATION);
		        var bottomPaginationObj = $(NAV_BOTTOM_PAGINATION);
		        //top pagination.
		        pagMove(topPaginationObj, NAV_NEXT_PAGE, pageGuidance.incr, "last-page", ajaxSuccessCallBack, ajaxErrorCallBack);
		        pagMove(topPaginationObj, NAV_PREVIOUS_PAGE, pageGuidance.decr, "first-page", ajaxSuccessCallBack, ajaxErrorCallBack);
		        //bottom pagination.
		        pagMove(bottomPaginationObj, NAV_NEXT_PAGE, pageGuidance.incr, "last-page", ajaxSuccessCallBack, ajaxErrorCallBack);
		        pagMove(bottomPaginationObj, NAV_PREVIOUS_PAGE, pageGuidance.decr, "first-page", ajaxSuccessCallBack, ajaxErrorCallBack);
		    })();
	
	        /**
	         * registering page numbers on pagination.
	         */
	        function pageNumbers() {
	            //registering the page number on pagination.
	            $('.page-numbers a').each(function(i, trigger) {
	                var trigger = $(trigger);
	                trigger.unbind('click').bind('click', function() {
	                    var paginationObj = $(".pagination");
	                    //grab the page that the user clicks on.
	                    var requestPageNum = trigger.text();
	                    //remove any pending page.
	                    paginationObj.find(NAV_PENDING_PAGE).removeClass('pending-page');
	                    //grab the pending page object.
	                    var requestPageObj = paginationObj.find('.page' + requestPageNum);
	                    if (requestPageObj.hasClass('last-page')) {
		                    //if it is the last page, then Next is disabled.
		                    //previous is enabled.
	                        paginationObj.find(NAV_NEXT_PAGE).addClass(DISABLED);
	                        var previousPageObj = paginationObj.find(NAV_PREVIOUS_PAGE); 
	                        if (previousPageObj.hasClass(DISABLED)) {
	                            previousPageObj.removeClass(DISABLED);
	                        }
	                    } else if (requestPageObj.hasClass('first-page')) {
	                        //if it is the first page, then Next is enabled.
	                        //previous is disabled.
	                        paginationObj.find(NAV_PREVIOUS_PAGE).addClass(DISABLED);
	                        var nextPageObj = paginationObj.find(NAV_NEXT_PAGE); 
	                        if (nextPageObj.hasClass(DISABLED)) {
	                            nextPageObj.removeClass(DISABLED);
	                        }
	                    } else {
	                        //when the page requested for is from [2 - n-1], next page
	                        //link and previous page link should be enabled.
	                        var nextPageObj = paginationObj.find(NAV_NEXT_PAGE);
	                        if (nextPageObj.hasClass(DISABLED)) {
	                            nextPageObj.removeClass(DISABLED);
	                        }
	                        var previousPageObj = paginationObj.find(NAV_PREVIOUS_PAGE);
	                        if (previousPageObj.hasClass(DISABLED)) {
	                            previousPageObj.removeClass(DISABLED);
	                        }
	                    }
	                   //if the request page is the same as the current page,
	                    //we should cancel any active ajax calls.
	                    if (requestPageObj.hasClass('current-page')) {
	                        //if there is currently a pending abn ajax call
	                        //we do not cancel
	                        if (!isActiveAbnAjaxCall) {
	                            cancelActiveAjaxCall();
	                        }
	                    } else {
	                        requestPageObj.addClass('pending-page');
	                        var query = getBrowseSearchRequestQuery() + "&pageNumber=" +  requestPageNum;
	                        ajaxCall(AJAX_PATH, query, ajaxSuccessCallBack, ajaxErrorCallBack);
	                    }
	                    return false;
	                });
	            });
	        }
	        //invoking pageNumbers 
	        (function() {
	            pageNumbers();
	        })();
	    }
	    /**
	     * this method is responsible for the abn of both plan and phone pages.
	     * @param {Object} triggerSelector
	     * @param {Object} ajaxSuccessCallBack
	     * @param {Object} ajaxErrorCallBack
	     */
	    function registerAbnEventHandlers(triggerSelector, ajaxSuccessCallBack, ajaxErrorCallBack) {
	        
	        //This is just a proxy class that allows us to know when the callback happens.
	        //We need this function to set the isActiveAbnAjaxCall.
	        function _ajaxSuccess(_ajaxSuccessCallBack) {
	            var ajaxSuccessCallBack = _ajaxSuccessCallBack;
	            return {
	                callBackHandler: function(json) {
	                    isActiveAbnAjaxCall = false;
	                    ajaxSuccessCallBack(json);
	                }
	            }
	        }
	        
	        function _ajaxError(_ajaxErrorCallBack) {
	            var ajaxErrorCallBack = _ajaxErrorCallBack;
	            return {
	                callBackHandler: function(xhr, textStatus, errorThrown) {
	                    isActiveAbnAjaxCall = false;
	                    ajaxErrorCallBack(xhr, textStatus, errorThrown);
	                }
	            }
	        }

	    /**
	     * Give a span where there is aname and value attribute.
	     * We grab those values, save it into our abn state. 
	     * @param {Object} span
	     */
	    function insertSpanValuesIntoAbnState(span) {
	        var attrName = span.attr("name");
	        var attrValue = span.attr("value");
	        if (span.hasClass(CHECKED)) {
	            AbnState.addElement(attrName, attrValue);
	        } else {
	            AbnState.removeElement(attrName, attrValue);
	        }
	    }

	        //registering abn. This is shared for both phone and plan.
	        $(triggerSelector).each(function(i, trigger) {
	            var trigger = $(trigger);
	            var span = $(this).find(CHECKBOX_SPAN);
	            //try to grab the checked values 
	            if (span.hasClass("checked")) {
	                var attrName = span.attr("name");
	                var attrValue = span.attr("value");
	                AbnState.addElement(attrName, attrValue);
	            }
	            trigger.unbind('click').bind('click', function() {
	                if (!span.hasClass("notclickable")) {
	                    span.toggleClass(CHECKED);   
	                    span.removeClass(HOVER);
	                    insertSpanValuesIntoAbnState(span);
	                    var browseABNState = getBrowseSearchRequestQuery();
	                    //wrapping callback objects so that we have more control of 
	                    //when ajax is done.
	                    var ajaxSucess = new _ajaxSuccess(ajaxSuccessCallBack);
	                    var ajaxError = new _ajaxError(ajaxErrorCallBack);
	                    ajaxCall(AJAX_PATH, browseABNState, ajaxSucess.callBackHandler, ajaxError.callBackHandler); 
	                    isActiveAbnAjaxCall = true;
	                }
	                return false;
	            });
	        });
	       	
	    }
       
        //These are the categories that should not be saved into our AbnState.
        var categoryNotIncludedInAbnState = (function() {
            var keys = searchRequestData.getKeys();
            keys["pageNumber"] = "";
	       return keys;
        })();
		/**
		 * Given a query data, we parse through this object and insert it
		 * into our abnState singleton object. We only save data that are part of the abn attributes.
		 * @param {Object} queryData - This query is expected to be in 
		 * the form of (pageSize=30&carrier=att)
		 */
        function handleAbnPageLoad(queryData) {
		    //clearing our current abn state if there is any.
			//the new queryData is going to be our new abn state.
		    AbnState.clearState();
		    //use to indicate which category in queryData is present.	    
            var categoryHash = {};
            if (queryData) {
                //contains an array of data in the format of pageSize=3&carrier=att,verizon
                var categoryDataArray = queryData.split("&");
                var n = 0, m = 0, l = 0, categoryValuesArray = [], categoryData,
                categoryNameValuesPair, categoryName, categoryValue; 
                for (n = 0, l = categoryDataArray.length; n < l; ++n) {
					//each categoryData is in the format of pageSize=3
					//or carrier=att,verizon
                    categoryData = categoryDataArray[n];
					//first element is pageSize. second element is 3. or
					//first element is carrier. Second elemnt is att, verizon
                    categoryNameValuesPair = categoryData.split("=");
                    //make sure that there are only two elements in our array.
                    if (categoryNameValuesPair.length == 2) {
                        categoryName = categoryNameValuesPair[0];
						//check to make sure that what we can save this category into
						//our AbnState.
                        if (typeof categoryNotIncludedInAbnState[categoryName] === 'undefined') {
	                        categoryValuesArray = categoryNameValuesPair[1].split(",");
	                        //go through and insert category values into a category name.
	                        for (m = 0, l < categoryValuesArray.length; m < l; ++m) {
	                            categoryValue = categoryValuesArray[m];
	                            AbnState.addElement(categoryName, categoryValue);
	                            categoryHash[categoryValue] = true;
	                        }
                        }
                    }
                }
            checkCategoryValuesCheckbox(categoryHash);
            }
        }
        function checkCategoryValuesCheckbox (catValuesHash) {
		    $('div#abn ul li').each(function(i, trigger) {
		        var trigger = $(trigger);
		        var span = trigger.find(CHECKBOX_SPAN);
		            var attrValue = span.attr('value');
		            if (catValuesHash[attrValue]){
		              span.addClass(CHECKED);
		            } else {
		              span.removeClass(CHECKED);
		        }
		    });
    }

        /**
        * This is our public methods to the world.
        */
        return {
			registerAbnEventHandlers: registerAbnEventHandlers,
			registerPaginationHandlers: registerPaginationHandlers,
			registerZipCodeHandlers: registerZipCodeHandlers,
			registerClearAbnEventHandlers: registerClearAbnEventHandlers,
			ajaxCall: ajaxCall,
			getBrowseSearchRequestQuery: getBrowseSearchRequestQuery,
			handleAbnPageLoad: handleAbnPageLoad
        };
	})();
	    
	var BrowsePhone = (function() {
	    
	    // Constants
	    var ABN_TRIGGER_SELECTOR = 'div#abn div#phones-abn ul li';
	    var NODE_ID = '684177011';
	    var TIME_OUT = 'timeout';
        var AjaxUtil = $.Aloha.AjaxUtil;
	    var AJAX_SEARCH_URL ="/searchRequest";
	    /**
	    * Initializes this object.
	    */
	    function initialize() {
	        registerEventHandlers();
	    }
	    function refreshPage(requestData) {
			Browse.handleAbnPageLoad(requestData);
			Browse.ajaxCall(AJAX_SEARCH_URL, requestData, handleAjaxSuccess, handleAjaxError);
		}
	    /**
	     * registering event handlers for Phone page.
	     */
	    function registerEventHandlers() {
	        //check to make sure that we are on the phone page.
	        if ($(ABN_TRIGGER_SELECTOR).length > 0) {
	            Browse.registerAbnEventHandlers(ABN_TRIGGER_SELECTOR, handleAjaxSuccess, handleAjaxError);
	            Browse.registerPaginationHandlers(handleAjaxSuccess, handleAjaxError);
				Browse.registerZipCodeHandlers();
				Browse.registerClearAbnEventHandlers(handleAjaxSuccess, handleAjaxError);
	        }
	    }
	    
	    function handleAjaxSuccess(json) {
	        $('#center-3').html(json.searchResultHtml);
	        $('#center-2').html(json.navTopResultHtml);
	        $('#center-4').html(json.navBottomResultHtml);
	        Browse.registerPaginationHandlers(handleAjaxSuccess, handleAjaxError);
	    }
	    
	    function handleAjaxError(xhr, textStatus, errorThrown) {
	    	AjaxUtil.showAjaxCallError(xhr, textStatus, errorThrown);
	    }
	    /**
        * extending Jquery
        */
        if (typeof $.Aloha === 'undefined') {
            $.Aloha = {}
        }
		if (typeof $.Aloha.BrowsePhone == 'undefined') {
            $.Aloha.BrowsePhone = {
                initialize: initialize,
				refreshPage: refreshPage
        }

		}
	})();
	
	var BrowsePlan = (function() {
	    
	    var ADD_TO_CART = '.add-to-cart';
	    var ABN_TRIGGER_SELECTOR = 'div#abn div#plans-abn ul li';
	    var CHECKBOX_ATT = '<span name="categoryCarrier" value="carrierAtt" class="checkbox"></span><a href="/b/684182011?categoryCarrier=carrierAtt">AT&T</a>';
	    var CHECKBOX_VERIZON = '<span name="categoryCarrier" value="carrierVerizon" class="checkbox"></span><a href="/b/684182011?categoryCarrier=carrierVerizon">Verizon</a>';
	    var CHECKBOX_SPAN = 'span.checkbox';
	    var AJAX_SEARCH_URL ="/searchRequest";
        var Util = $.Aloha.Util;
        var AjaxUtil = $.Aloha.AjaxUtil;
		
	    function initialize() {
	        registerAddPlanToCartEventHandlers();
	        registerEventHandlers();
	    }      

	    /**
	     * Registering the event handler for add to cart buttons on plan page.
	     */
	    function registerAddPlanToCartEventHandlers() {
	        $(ADD_TO_CART).each(function(i, trigger) {
	            var trigger = $(trigger);
	            trigger.unbind('click').bind('click', function() {
	                var securityTokenQuery = Util.getSecurityTokenQuery();
	                var asinQuery = "&asin=" + $(this).attr("value") || "";
	                var operation = "&operation=ADD_SERVICE";
	                var query = securityTokenQuery + asinQuery + operation;
	                Browse.ajaxCall('/alohaCartRequest', query, handleAddPlanToCartAjaxSuccess, handleAjaxError);
	                return false;
	            })
	        });
	    }
	    /**
	     * registering the event handlers for plan page.
	     */
	    function registerEventHandlers() {
	        //make sure that it's the plan page that we're on.
	        if ($(ABN_TRIGGER_SELECTOR).length > 0) {
	            Browse.registerAbnEventHandlers(ABN_TRIGGER_SELECTOR, handleAjaxSuccess, handleAjaxError);
	            Browse.registerPaginationHandlers(handleAjaxSuccess, handleAjaxError);
				Browse.registerZipCodeHandlers();
	        }
	    }
	    /**
	     * handles when add to cart on plan page is successful.
	     * @param {Object} json - the json object that is passed back whenever
	     * an ajax call is successful.
	     */
	    function handleAddPlanToCartAjaxSuccess(json) {
	        //show plan added in smartcart
	        window.scrollTo(0,0);
	        $.Aloha.SmartCart.updateExpandedSmartCart(json);
	        Util.showWorkflowErrorOnFailure(json);
	    }
	    /**
	     * handles abn ajax success. When the user uses the abn on plan page,
	     * this method is called everytime the ajax call is successful.
	     * @param {Object} json - json object that is passed back when the ajax
	     * call is successful on plan abn.
	     */
	    function handleAjaxSuccess(json) {
	        $('#center-3').html(json.searchResultHtml);
	        $('#center-2').html(json.navTopResultHtml);
	        /*need to reattach the event handler after inserting new html*/
	        registerAddPlanToCartEventHandlers();
	    }
	    /**
	     * goes through and uncheck carrier checkboxes.
	     * This is called when the user tries to remove a phone on the plan page.
	     */
	    function uncheckCarrierCheckBoxes() {
	        AbnState.clearState();
	        $(ABN_TRIGGER_SELECTOR).each(function(i, trigger) {
	            var trigger = $(trigger);
	            var span = $(this).find(CHECKBOX_SPAN);
	            var attrName = span.attr('name');
	            var attrValue = span.attr('value');         
	            if (attrName === "categoryCarrier") {    
	                if (attrValue === "carrierVerizon") {
	                    span.parent().removeClass("disabled").empty().html('').append(CHECKBOX_VERIZON);
	                } else if (attrValue === "carrierAtt") {
	                    span.parent().removeClass("disabled").empty().html('').append(CHECKBOX_ATT);
	                }   
	            }
	        });
			//everytime we update the html, the event handlers are gone.
	        //needs to re-register the event handlers.
	        initialize();
	    }
	    function refreshPage() {
	        uncheckCarrierCheckBoxes();
	        Browse.ajaxCall(AJAX_SEARCH_URL, Browse.getBrowseSearchRequestQuery(), handleAjaxSuccess, handleAjaxError);
	    }
	    /**
	     * this gets call when there is an ajax error on plan page.
	     * @param {Object} xhr
	     * @param {Object} textStatus
	     * @param {Object} errorThrown
	     */
	    function handleAjaxError(xhr, textStatus, errorThrown) {
	    	AjaxUtil.showAjaxCallError(xhr, textStatus, errorThrown);
	    }
	    
	    /**
	    * This is our public methods to the world.
	    */
        if (typeof $.Aloha === 'undefined') {
            $.Aloha = {}
        }
        if (typeof $.Aloha.BrowsePlan === 'undefined') {
			$.Aloha.BrowsePlan = {
				initialize: initialize,
				refreshPage: refreshPage
			}
		}
	})();
})(jQuery)

/**
 * This onload is used when our users clicked on the Back button to the 
 * phone abn page.
 * Onload is an event that gets invoked when the user clicks on the back button.
 */
$(window).load(function() {
    var abnHistoryValue = $("#historyHidden").find('input[name="abnHistory"]').val();
    if (abnHistoryValue && typeof $.Aloha !== 'undefined' && typeof $.Aloha.BrowsePhone !== 'undefined') {
        $.Aloha.BrowsePhone.refreshPage(abnHistoryValue);
    }
});
