(function($) {
	
    if (typeof $.Aloha === 'undefined') {
        $.Aloha = {};
    }
    //these are the skins that we use to construct the smart cart.
	var SmartCartHtmlSkins = {
		smartCartEmptyBaseMinimize: 
	                   '<div id="smart-cart-wrapper" class="workflow workflow-phone smart-cart-outer"> \
							<div class="border-bottom"></div> \
							<div class="rounded-corner bottom-left"/> \
							<div class="rounded-corner bottom-right"/> \
							<h4 id="cart-header">Your Cart \
								<div class="rounded-corner top-left"/> \
								<div class="rounded-corner top-right"/> \
								<span class="cart-header-zip-code">| ZIP Code: <span class="zip-code"></span></span> \
								<span class="cart-header-open-close" id="cart-open-close">Open Cart</span> \
							</h4> \
							<div class="smart-cart-collapsed" id="smart-cart-collapsed" style="display: none;"> \
								<div class="rounded-corner top-left"></div> \
								<div class="rounded-corner top-right"></div> \
							</div> \
							<div class="smart-cart-expanded" id="smart-cart-expanded" style="display: block;"></div> \
						</div>',
		smartCartEmptyBaseExpanded:
	                           '<div> \
									<div class="smart-cart-inner"> \
										<ol> \
											<li class="phone-section"> \
												<span class="image-replaced"></span> \
												<span class="check-mark"/> \
                                        <div class="rounded-corner top-left"></div> \
                                        <div class="rounded-corner top-right"></div> \
                                        <div class="rounded-corner bottom-left"/> \
                                        <div class="rounded-corner bottom-right"/> \
												<h4 class="section-header">1. Phone <span class="header-note">(1 selected)</span></h4> \
											</li> \
											<li class="plan-section"> \
												<div class="rounded-corner top-left"/> \
												<div class="rounded-corner top-right"/> \
												<div class="rounded-corner bottom-left"/> \
												<div class="rounded-corner bottom-right"/> \
												<h4 class="section-header">2. Plan <span class="header-note">(1 selected)</span></h4> \
												<p class="noPlan">Phone Only (No Plan)</p> \
							                </li> \
									        <li class="service-options-section"> \
												<div class="rounded-corner top-left"/> \
												<div class="rounded-corner top-right"/> \
												<div class="rounded-corner bottom-left"/> \
												<div class="rounded-corner bottom-right"/> \
							                	<h4 class="section-header">3. Service Options <span class="header-note"></span></h4> \
												<p class="noPlan">Phone Only (No Options)</p> \
									        </li> \
								    </ol> \
									</div> \
									<a class="image-replaced proceed-to-checkout" class="" style="display: none;"></a> \
									<span id="bundler-price-wrapper"> </span> \
									<span id="bundler-footnote-outer-wrapper"> </span> \
									<div class="clear-fix"></div> \
								</div>',
		optionsBase:	'<div> <div class="rounded-corner bottom-left"/> \
					<div class="rounded-corner top-right"/> \
					<div class="rounded-corner top-left"/> \
					<div class="rounded-corner bottom-right"/> \
					<span class="check-mark"/> \
					<h4 class="section-header">3. Service Options <span class="header-note">(3 selected)</span></h4> \
					<h5> Selected for:</h5> \
					<h4 class="bundler-product-title"></h4> \
					<ul> \
					</ul> \
					<div class="add-or-remove"> \
	                	<span class="editOptions"> \
	                		<a href="/options">Edit</a> options \
	                	</span> \
	                </div> \
	              	<h4 class="success-header">You have successfully added service options to your cart.</h4> \
				</div>',
		optionsElementExpanded:	'<li><span class="monthly-price-wrapper"><span class="monthly-price"></span> per month</span> \
						</li>',
		optionsSeparatorElementExpanded:'<li id="optionsSeparator"></li> <div class="clear-fix"></div>',
		optionsSubtotalElementExpanded:	'<li id="optionsSubtotal"><span class="monthly-price-wrapper"><span class="monthly-price"></span> per month</span> <span class="subtotalHeader"> </span> \
						</li>',					
		optionsSectionCollapsed: '<div> \
									<li class="service-options-section">3. Service Options</li>\
								</div>',
		optionsCompletedCollapsed: '<li class="service-options-section completed"> \
									<span class="check-mark"/> \
										<strong>3. Service Options</strong> <span class="header-note-options"></span> \
							 	</li>',				
		optionsSelectNextButton: '<a class="image-replaced" id="select-service-options" href="#">Next, select service options</a> \
									<div class="clear-fix"/>',							
		planCurrentCollapsed: '<li class="plan-section current"> 2. Plan\
								</li>',	
		planMonthlyPrice: "Due Monthly: <span class='bundler-price'>",
		planExtraMonthlyPrice: "Extra Due Monthly: <span class='bundler-price'>",
		planCompletedCollapsed: '<li class="plan-section completed"> \
									<span class="check-mark"/> \
										<strong>2. Plan</strong> (1 selected) \
							 	</li>',					
		planSectionExpanded: '<div id="plan-section-inner"> \
								<span class="image-replaced"></span> \
	                			<h4 class="bundler-product-title"></h4> \
	                			<div class="main-price-wrapper"> \
		                			<span \
										class="bundler-price-wrapper"> \
										<span \
		                                	class="sale-price price-column"> \
		                                </span> \
		                                <span \
		                                	class="price-label">Price per month: \
		                                </span> \
									</span> \
								</div> \
	                			<div class="add-or-remove"> \
	                				<span class="removePlan"> \
	                					<a href="#">Remove</a> plan from cart \
	                				</span> \
	                			</div> \
	                			<h4 class="success-header">You have successfully added a plan to your cart.</h4> \
								<span class="success-note"></span> \
	            			</div>',
		planSelectNextButton:  '<a id="select-a-plan" class="image-replaced" href="#">Next, select a plan</a> \
								<div class="clear-fix"/>',						
		phonePrice: "Phone Price: <span class='bundler-price'>",
		phoneSectionExpanded: '<div id="phone-section-inner"> \
									<img class="bundler-product-image" \
	                                	src="" \
	                                	alt="" /> \
	                				<h4 class="bundler-product-title"></h4> \
	                				<div class="main-price-wrapper"> \
	                					<span class="bundler-list-price-wrapper"> <span class="slashed-price price-column"> </span> \
	                					<span class="price-label">List Price:</span> </span> \
	                					<span class="bundler-price-wrapper"> \
	                					<span class="sale-price price-column"></span> \
	                					<span class="price-label">Price:</span> </span>\
	                                </div> \
	                				<div class="add-or-remove"> \
	                					<span class="removePhone">\
	                						<a href="#">Remove</a> from cart</div> \
	                					</span> \
	                					<h4 class="success-header">You have successfully added a phone to your cart.</h4> \
	                					<span class="success-note"></span> \
	            				</div>',
		phoneSelectedCollapsed: '<li class="phone-section completed"> \
									<span class="image-replaced"></span> \
									<span class="check-mark"/> \
										<strong>1. Phone</strong> (1 selected) \
								</li>',
		checkMarkSpan: '<span class="check-mark"></span>',
		bundlerPriceWrapper: '<div> \
								<span id="bundler-price-wrapper"> \
							  	</span> \
							  </div>',
		clearFix: '<div class="clear-fix"/>',
		emptyCart: '<div class="empty-cart"> \
						<div class="rounded-corner top-left"></div> \
						<div class="rounded-corner top-right"></div> \
						<p id="cart">Your Cart <span class="cartdesc"> (empty)</span></p> \
				   </div>',
		topLeftCorner: '<div class="rounded-corner top-left"></div>',
		topRightCorner: '<div class="rounded-corner top-right"></div>',
		existingPlanWhyLink: "<a id='existingplanWhy' onclick=\"window.open(this.href,'_blank','toolbar=auto,location=0,statusbar=0,menubar=0,resizable=0,width=750,height=300,left=326,top=302'); return false;\" href=\"/help/200333430/ref=existPlan_sc_dp?applicationLayoutId=2\"> why?</a>"
	}
	//text messages to display status on smart cart.
	var SmartCartMessages = {
		PhoneSuccessNoteUpgrade: 'We\'ll ask you for your current carrier account information during checkout.',
		PhoneSuccessNoteNew: 'Want to keep your current phone number? We\'ll ask you for your information during checkout.',
		PlanSuccessNoteExistingPlan: 'Upgrading as part of a family account requires you keep your current family plan.',
		BundlerSuccessNoteDefault: 'Per month charge does not include taxes and surcharges, which will be added to your monthly charge.',
		BundlerSuccessNoteExistingPlan: 'Per month charges for your existing family plan will remain unchanged.',
		BundlerSuccessNoteAddALine: 'Estimated price may change based on your current plan.'
	}
    //namespace objects.
	var Util = $.Aloha.Util;
	var AjaxUtil = $.Aloha.AjaxUtil;

    
    //bundle next step status.
    var NextStep = {
        SELECT_PLAN : 'SELECT_PLAN',
        SELECT_OPTIONS : 'SELECT_OPTIONS',
        SELECT_ADDALINE_PLAN : 'SELECT_ADDALINE_PLAN',
        CHECK_OUT : 'CHECKOUT',
        NONE : 'NONE'
    }
    //util function for our smart cart.
    var SmartCartUtil = new function() {
        this.hasUnhandledInternalBundleChange = false;
		var VERIZON = 'VERIZON';
		var CINGULAR = 'CINGULAR';
		var TMOBILE = 'VOICESTREAM';
		var NEXTEL = 'NEXTEL';
		var ATT = 'ATT';
		var VERIZON_LOGO_SMALL = 'verizon-logo-small';
		var ATT_LOGO_SMALL = 'att-logo-small';
		var TMOBILE_LOGO_SMALL = 'tmobile-logo-small';
        /**
         * returns the next step of the bundle.
         * @param {Object} json
         */
        function getBundleNextStep(json) {
            return json.bundleBuildStates[0];
        }
        /**
         * use to update the small provider logo in our smart cart.
         * @param {Object} provider - the name of the provider.
         * @param {Object} htmlObj - a jquery object to be inserted into
         * @param {Object} attr - the attribute in the htmlObj to be replaced. 
         */
        function updatePhoneSmallLogo(provider, htmlObj, attr) {
            var phoneSectionImageSpan = htmlObj.find(attr);
			//get the image logo css class.
            var imageLogoClass = (function(provider) {
                var imageLogo = "";
                if (typeof provider !== 'undefined') { 
                    if (provider === VERIZON){
                        imageLogo = VERIZON_LOGO_SMALL; 
                    } else if (provider === CINGULAR || provider === NEXTEL || provider === ATT) { //TODO: NEXTEL is a hack
                        imageLogo = ATT_LOGO_SMALL;
                    } else if (provider === TMOBILE) {
                    	imageLogo = TMOBILE_LOGO_SMALL;
                    }
                }
                return imageLogo;   
            })(provider);       
            phoneSectionImageSpan.addClass(imageLogoClass);
            return htmlObj;
        }
        /**
         * insert a $ dollar infront of the string price.
         * @param {Object} priceStr
         */
        function getPrice(priceStr) {
            return "$ " + Util.getPrice(priceStr);
        }
		
        function addClass(htmlObj, toClass, className) {
            return  htmlObj.find(toClass).addClass(className).parent();
        }
        /**
         * get the transaction type from the json.
         * @param {Object} json
         */
        function getTransactionType(json) {
            var transactionType = "";
            if (typeof json.bundle.transaction !== 'undefined') {
                transactionType = json.bundle.transaction;
            }
            return transactionType;			
		}
        /**
         * get the monthly plan charge from the json.
         * @param {Object} json
         */
		function getPlanMonthlyCharge(json) {
            //json.bundle.service.monthlyCharge 
            var monthlyCharge = "";
            var bundle = json.bundle;
            if (typeof bundle.service !== 'undefined' && typeof bundle.service.monthlyCharge !== 'undefined') {
                monthlyCharge = bundle.service.monthlyCharge;
            }
            return Util.getPrice(monthlyCharge);
		}
        /**
         * this method returns a boolean to indicate whether the user decided
         * to keep an existing plan. This is indicated by anytime minutes == 0 
         * and plan monthly charge == "0.00"
         * @param {Object} json
         */
		function getIsKeepExistingPlan(json) {
            var planAnytimeMinutes = (function(json) {
                var anytimeMinutes = -1;
                var bundle = json.bundle;
                if (typeof bundle.service !== 'undefined' && typeof bundle.service.anytimeMinutes !== 'undefined'){
                    anytimeMinutes = bundle.service.anytimeMinutes;
                }
                return anytimeMinutes;
            })(json);
            var keepExistingPlan = false;
			var planMonthlyCharge = getPlanMonthlyCharge(json);
            if (planAnytimeMinutes === 0 && planMonthlyCharge === "0.00") {
                keepExistingPlan = true;
            }
            return keepExistingPlan;			
		}
		/**
		 * determines if the bundle provider is empty.
		 * @param {Object} json
		 */
        function getIsProviderEmpty(json) {
            var isProvideEmpty = true;
            if (typeof json.bundle.provider !== 'undefined' && typeof json.bundle.provider.name !== 'undefined') {
                isProvideEmpty = false;
            }    
            return isProvideEmpty;
        }
		return {
			getIsKeepExistingPlan: getIsKeepExistingPlan,
			getPlanMonthlyCharge: getPlanMonthlyCharge,
			getTransactionType: getTransactionType,
			addClass: addClass,
			getPrice: getPrice,
			updatePhoneSmallLogo: updatePhoneSmallLogo,
			getBundleNextStep: getBundleNextStep,
			getIsProviderEmpty: getIsProviderEmpty
		};
    }
    /**
     * The phone section of the smart cart.
     */
	var PhoneSection = function() {
		var BUNDLER_PRODUCT_IMAGE_CLASS = '.bundler-product-image';
		var PHONE_SECTION_LOGO_LI = 'span.image-replaced';
        var NEW = "NEW";
		
		function updateCollapsed(json, htmlObj) {
			if (typeof json.bundle.lines !== 'undefined' && json.bundle.lines.length > 0){
				var phoneHtmlObj = $(SmartCartHtmlSkins.phoneSelectedCollapsed);
				if (!SmartCartUtil.getIsProviderEmpty(json)) {
					var provider = json.bundle.provider.name;
					SmartCartUtil.updatePhoneSmallLogo(provider, phoneHtmlObj, PHONE_SECTION_LOGO_LI);
				}
				//phone collapsed is completed.
				htmlObj.append(phoneHtmlObj.parent().html());
			} else {
				//phone collapsed is disabled.
				htmlObj.append(SmartCartUtil.addClass($(SmartCartHtmlSkins.phoneSectionCollapsed), '.service-options-section', 'completed').html());				
			}
		}
		
		function updateExpanded(json, htmlObj) {
			var phoneHtmlObj = $(SmartCartHtmlSkins.phoneSectionExpanded);
	    
	    	//get phone image url
	    	var jsonPhoneImageURL = json.bundle.lines[0].device.thumbnailImage.URL;
	    	phoneHtmlObj.find(BUNDLER_PRODUCT_IMAGE_CLASS).empty().attr("src",jsonPhoneImageURL);
	   
			//get phone title
	    	var jsonPhoneTitle = json.bundle.lines[0].device.title;
	    	phoneHtmlObj.find(".bundler-product-title").empty().html(jsonPhoneTitle);
	    
	    	//get phone list price
	    	var jsonPhoneListPrice = json.bundle.lines[0].device.listPrice;
	    	phoneHtmlObj.find(".slashed-price").empty().html(SmartCartUtil.getPrice(jsonPhoneListPrice));
	    
	    	//get phone price
	    	var jsonPhonePrice = json.bundle.lines[0].device.price;	
	    	phoneHtmlObj.find(".sale-price").empty().html(SmartCartUtil.getPrice(jsonPhonePrice));
	    
	    	//get the transaction type
	    	var transactionType = SmartCartUtil.getTransactionType(json);
			if (transactionType === NEW) {
				phoneHtmlObj.find(".success-note").empty().html(SmartCartMessages.PhoneSuccessNoteNew);
			} else {
				phoneHtmlObj.find(".success-note").empty().html(SmartCartMessages.PhoneSuccessNoteUpgrade);
			}
	    	
			htmlObj.find("li.phone-section").append(phoneHtmlObj.html());
	
			//updating the small provider logo in the phone section.
			if (!SmartCartUtil.getIsProviderEmpty(json)) {
				var provider = json.bundle.provider.name;
				SmartCartUtil.updatePhoneSmallLogo(provider, htmlObj.parent(), PHONE_SECTION_LOGO_LI);
			}		


			var transactionType = SmartCartUtil.getTransactionType(json);
			if (transactionType === "NEW_PHONE") { 
				htmlObj.find(".phone-section .success-note").remove();
			} else {
				htmlObj.find(".noPlan").remove();
			}
			return htmlObj;		
		}
		
		return {
			updateExpanded: updateExpanded,
			updateCollapsed: updateCollapsed
		};
	}();		
    
	/**
	 * The plan section of the smart cart.
	 */
	var PlanSection = function() {
		var PLAN_SECTION_SMALL_LOGO_ID = 'span.image-replaced';
		function updateCollapsed(json, htmlObj) {

			var transactionType = SmartCartUtil.getTransactionType(json);
			if (transactionType === "NEW_PHONE") { 
				htmlObj.append(SmartCartHtmlSkins.planCurrentCollapsed);				
				htmlObj.find(".plan-section").addClass("disabled");
				return; 
			}
			var nextStepState = SmartCartUtil.getBundleNextStep(json).name;		
			if (nextStepState === NextStep.SELECT_PLAN || nextStepState === NextStep.SELECT_ADDALINE_PLAN) { //current
				htmlObj.append(SmartCartHtmlSkins.planCurrentCollapsed);				
			} else if (nextStepState === NextStep.SELECT_OPTIONS) { //completed
				htmlObj.append(SmartCartHtmlSkins.planCompletedCollapsed);
			} else if (nextStepState === NextStep.CHECK_OUT){ //completed
				htmlObj.append(SmartCartHtmlSkins.planCompletedCollapsed);
			}
		}
		
		function updateExpanded(json, htmlObj) {
			
			var nextStepState = SmartCartUtil.getBundleNextStep(json).name;		
			var transactionType = SmartCartUtil.getTransactionType(json);
			if (transactionType === "NEW_PHONE") { 
				htmlObj.find(".plan-section").addClass("disabled");
				htmlObj.find("li.plan-section .header-note").empty();
				return; 
			}
			if (nextStepState === NextStep.SELECT_PLAN || nextStepState ===NextStep.SELECT_ADDALINE_PLAN) {
				var planBtnHtml = SmartCartHtmlSkins.planSelectNextButton;
				htmlObj.find("li.plan-section").append(planBtnHtml);
				htmlObj.find("li.plan-section .header-note").empty();
				htmlObj.find("li.plan-section #select-a-plan").attr("href",SmartCartUtil.getBundleNextStep(json).url);
			} else {
				//add check mark
		    	htmlObj.find("li.plan-section h4.section-header").before(SmartCartHtmlSkins.checkMarkSpan);
				var planHtmlObj = $(SmartCartHtmlSkins.planSectionExpanded);
		    	
				//get plan title
		    	var jsonPlanTitle = json.bundle.service.title;
		   
				//get plan price
				var planPrice = SmartCartUtil.getPlanMonthlyCharge(json); 
		    	
		    	//determine whether family plan. this indicates Keep My Existing Plan.
				var isKeepExistingPlan = SmartCartUtil.getIsKeepExistingPlan(json);
				//this indicates that it is a family plan and we need to display "no changes" for price
				//and not display the remove link
				if (isKeepExistingPlan) {
					planPrice = " no change";
					planHtmlObj.find(".sale-price").css('font-size','12px');
					planHtmlObj.find(".sale-price").css('font-weight','normal');
					planHtmlObj.find(".price-column").css('width','74px');
					planHtmlObj.find(".add-or-remove .removePlan").remove();
					planHtmlObj.find(".success-note").empty().html(SmartCartMessages.PlanSuccessNoteExistingPlan);
		    		planHtmlObj.find(".bundler-product-title").empty().html(jsonPlanTitle + SmartCartHtmlSkins.existingPlanWhyLink);
					//fix for smartcart layout issue of ie6 and ie7 at family upgrade case
					htmlObj.find("li.service-options-section").css('margin-top','0px');
				} else {
					planPrice = SmartCartUtil.getPrice(planPrice);
		    		planHtmlObj.find(".bundler-product-title").empty().html(jsonPlanTitle);
				}
		    	planHtmlObj.find(".sale-price").empty().html(planPrice + '*');
		    	if(transactionType === "ADD_A_LINE"){
		    		planHtmlObj.find(".price-label").empty().html("Extra due monthly: ");
		    	}
		    	
				htmlObj.find("li.plan-section").append(planHtmlObj.html());
				if (!SmartCartUtil.getIsProviderEmpty(json)) {
					var provider = json.bundle.provider.name;
					SmartCartUtil.updatePhoneSmallLogo(provider, htmlObj, PLAN_SECTION_SMALL_LOGO_ID);
				}		    									
			}				
			return htmlObj;
		}
		return {
			updateExpanded: updateExpanded,
			updateCollapsed: updateCollapsed
		};	
	}();
    /**
     * The options section of the smart cart.
     */
	var OptionSection = function() {
		var SELECT_SERVICE_OPTIONS = '.image-replaced#select-service-options';
		var SERVICE_OPTIONS_SECTION_HEADER = 'li.service-options-section h4.section-header';
		function updateCollapsed(json, htmlObj) {

			var nextStepState = SmartCartUtil.getBundleNextStep(json).name;
			var transactionType = SmartCartUtil.getTransactionType(json);
			if (transactionType === "NEW_PHONE") { 
				htmlObj.append(addClassToOptionsSection('disabled'));				
				htmlObj.find(".service-options-section").addClass("disabled");
				return; 
			}
			if (nextStepState === NextStep.SELECT_PLAN || nextStepState === NextStep.SELECT_ADDALINE_PLAN) { //disabled
				htmlObj.append(addClassToOptionsSection('disabled'));				
			} else if (nextStepState === NextStep.SELECT_OPTIONS) { //current
				htmlObj.append(addClassToOptionsSection('current'));
			} else if (nextStepState === NextStep.CHECK_OUT) { //completed						
				var optionsLength = json.bundle.lines[0].options.length;
				var optionsObj = $(SmartCartHtmlSkins.optionsCompletedCollapsed);
				optionsObj.find('.header-note-options').empty().html('(' + optionsLength + ' selected)');
				htmlObj.append(optionsObj.parent().html());						
			}		
		}
		function updateExpanded(json, htmlObj) {
			var transactionType = SmartCartUtil.getTransactionType(json);
			if (transactionType == "NEW_PHONE") { 
				htmlObj.find(".service-options-section").addClass("disabled");
				return; 
			}
			var nextStepState = SmartCartUtil.getBundleNextStep(json).name;
			if (nextStepState === NextStep.SELECT_PLAN || nextStepState === NextStep.SELECT_ADDALINE_PLAN) {
				htmlObj.find(".service-options-section").addClass("disabled");
			} else if (nextStepState === NextStep.SELECT_OPTIONS) {
				htmlObj.find(SERVICE_OPTIONS_SECTION_HEADER).after(SmartCartHtmlSkins.optionsSelectNextButton);
				htmlObj.find(SELECT_SERVICE_OPTIONS).attr("href", SmartCartUtil.getBundleNextStep(json).url);
				//fix for smartcart layout issue of ie6 when next step is select option and cart is expanded
                htmlObj.find("li.service-options-section").css('margin-bottom','-3px');	
			} else {
				htmlObj.find("li.service-options-section h4.section-header").before(SmartCartHtmlSkins.checkMarkSpan);
				var optionsHtmlObj = $(SmartCartHtmlSkins.optionsBase);
				//if (optionsLength > 0) {
				var jsonPhoneTitle = json.bundle.lines[0].device.title;
				var optionsLength = json.bundle.lines[0].options.length;
				optionsHtmlObj.find('.header-note').empty().html('(' + optionsLength + ' selected)');
				optionsHtmlObj.find('.bundler-product-title').empty().html(jsonPhoneTitle);
				var optionsSubtotal = 0.0;
				
				var optionElement;
				var option;
				var title;
				var monthlyCharge;
				var i = 0;
				for (; i < optionsLength; ++i){
					//var option = new String(SmartCartHtmlSkins.optionsElementExpanded);
					optionElement =  $(SmartCartHtmlSkins.optionsElementExpanded);
					option = json.bundle.lines[0].options[i];
					title = option.title;
					monthlyCharge = option.monthlyCharge;
					optionsSubtotal += parseFloat(Util.getPrice(monthlyCharge));
					optionElement.find('.monthly-price-wrapper').after(title);
					optionElement.find('.monthly-price').empty().html(SmartCartUtil.getPrice(monthlyCharge));
					optionsHtmlObj.find('ul').append(optionElement.parent().html());
				}		
				//if there is no options added, do not show the line separator		
				if (optionsLength > 0) {
					optionsHtmlObj.find('ul').append(SmartCartHtmlSkins.optionsSeparatorElementExpanded);
				}
				//this it to append the subtotal
				var optionSubtotalElement = $(SmartCartHtmlSkins.optionsSubtotalElementExpanded); 
				optionSubtotalElement.find('.subtotalHeader').empty().html("Subtotal of selected options: ");
				optionSubtotalElement.find('.monthly-price').empty().html("$ " + optionsSubtotal.toFixed(2));
				optionsHtmlObj.find('ul').append(optionSubtotalElement.parent().html());
								
				//}
				htmlObj.find("li.service-options-section").empty().append(optionsHtmlObj.html());
				//fix for smartcart layout issue of ie6 when there are options selected, cart is expanded
				htmlObj.find("li.service-options-section").css('margin-bottom','-1px');
			}
		}
		
	    function addClassToOptionsSection (className) {
	    	return  $(SmartCartHtmlSkins.optionsSectionCollapsed).find('.service-options-section').addClass(className).end().html();
	    }
		
		return {
			updateExpanded: updateExpanded,
			updateCollapsed: updateCollapsed
		};	
	}();	
	/**
	 * Display the bundle price. This is only when the cart is expanded.
	 */
	var BundlePriceSection = function() {
		var BUNDLER_PRICE_WRAPPER_ID = '#bundler-price-wrapper';
		var BUNDLER_FOOTNOTE_OUTER_WRAPPER_ID = '#bundler-footnote-outer-wrapper';
		
		/**
		 * The sum of all the options in our bundle.
		 * @param {Object} json
		 */
		function getOptionsPriceSum(json) {
	        var sum = 0.0;
	        if (typeof json.bundle.lines != 'undefined') {
                var lines = json.bundle.lines;
	            for (var i = 0; i < lines.length; ++i) {
	                var line = lines[i];
	                if (typeof line.options !== 'undefined') {
	                    sum += getLineOptionsSum(line.options);
	                }
	            }
	        }
	        if (typeof json.bundle.options !== 'undefined') {
	            //sum += SmartCartUtil.getOptionsSum(json.bundle.options);          
	        }
	        return sum;
            
		}
		/**
		 * returns the sum of a line in our bundle.
		 * @param {Object} options
		 */
		function getLineOptionsSum(options) {
	        var sum = 0.0;
            if (typeof options !== 'undefined') {
				for (var i = 0; i < options.length; ++i) {
					var option = options[i];
					var price = Util.getPrice(option.monthlyCharge);
					if (!isNaN(price)) {
						sum += parseFloat(price);
					}
				}
			}
	        return sum;
		}
		
		function updateExpanded(json, htmlObj) {
	    	//get phone price
	    	if(typeof json.bundle !== 'undefined'){
	    		var jsonPhonePrice = json.bundle.lines[0].device.price;
				var bundlerPriceObj = htmlObj.find(BUNDLER_PRICE_WRAPPER_ID).empty();
				var bundlerFootnoteOuterObj = htmlObj.find(BUNDLER_FOOTNOTE_OUTER_WRAPPER_ID).empty();

				var transactionType = SmartCartUtil.getTransactionType(json);
				if (transactionType === "NEW_PHONE") {
					htmlObj.find(BUNDLER_FOOTNOTE_OUTER_WRAPPER_ID).remove();
				}

				if (typeof json.bundle.service !== 'undefined') {
					var jsonPlanPrice = json.bundle.service.monthlyCharge;
                    var keepExistingPlan = SmartCartUtil.getIsKeepExistingPlan(json);
					//only display bundler due monthly price if it is not existing plan.
                    if (!keepExistingPlan && (transactionType !== "NEW_PHONE")) {
						var monthlyPrice = getOptionsPriceSum(json) + parseFloat(Util.getPrice(jsonPlanPrice));	
					    monthlyPrice = monthlyPrice.toFixed(2);
					    if (transactionType === "ADD_A_LINE"){
					    	bundlerPriceObj.html(SmartCartHtmlSkins.planExtraMonthlyPrice + "$ " + monthlyPrice + "*</span> / ");
				    	}
					    else{
					    	bundlerPriceObj.html(SmartCartHtmlSkins.planMonthlyPrice + "$ " + monthlyPrice + "*</span> / ");
				    	}
                    }
                    bundlerPriceObj.append(SmartCartHtmlSkins.phonePrice + SmartCartUtil.getPrice(jsonPhonePrice) + "</span>");
				    var bundlerFootnote = $('<span id="bundler-footnote-wrapper"></span>');
				    if (keepExistingPlan) {
					   bundlerFootnote.html("* " + SmartCartMessages.BundlerSuccessNoteExistingPlan);
				    } else if (transactionType === "ADD_A_LINE"){
				    	bundlerFootnote.html("* " + SmartCartMessages.BundlerSuccessNoteAddALine);
				    } else {
					   bundlerFootnote.html("* " + SmartCartMessages.BundlerSuccessNoteDefault);
				    }
		    		bundlerFootnoteOuterObj.html(bundlerFootnote.parent().html());
				} else {
		    		bundlerPriceObj.html(SmartCartHtmlSkins.phonePrice + SmartCartUtil.getPrice(jsonPhonePrice) + "</span>");
				}
	    	}	
			return htmlObj;
		}	
		return {
			updateExpanded: updateExpanded
		};
	}();
	
	var ButtonClass = {
		PROCEED_TO_CHECKOUT : '.proceed-to-checkout'
	};
    //determines whether we should display the checkout button.
	var CheckOutButtonSection = function() {
		/**
		 * use to expand the smart cart and show the checkout button
		 * @param {Object} json 
		 * @param {Object} htmlObj - the htmlObj that is this method used to
		 * work on. 
		 */
		function updateExpanded(json, htmlObj) {
			var nextStepState = SmartCartUtil.getBundleNextStep(json).name;
			if (nextStepState === NextStep.CHECK_OUT) {
				var proceedCheckOutObj = htmlObj.find(ButtonClass.PROCEED_TO_CHECKOUT);
				proceedCheckOutObj.attr("href","/checkout?" + Util.getCheckoutSecurityTokenQuery()).show();
				proceedCheckOutObj.attr("style", ""); // this is a hack for Safari. The above line insert style="display:inline" in Safari which causes it to not show the proceed to checkout button
			}
			return htmlObj;
		}
		/**
		 * public methods to the world.
		 */
		return {
			updateExpanded: updateExpanded
		};
	}();
	
	var SmartCart = function() {
	//constants.
		var SMART_CART_WRAPPED_ID = '#smart-cart-wrapper';
		var FULLY_EXPANDED = 'smart-cart-expanded';
		var SMART_CART_COLLAPSED_ID = '#smart-cart-collapsed';
		var SMART_CART_CONTENT = '.smart-cart-content';
		var EMPTY_CART_ID = 'div#smart-cart .empty-cart';
	    //constant for remove phone/plan
	    var REMOVE_PHONE_ACTION = "DELETE_LINE";
	    var SHIPPING_ADS_ID = "div#ship-ads";
	    var EXPANDED_BORDER_BOTTOM_ID = 'div#smart-cart-wrapper .border-bottom';
		var PLAN_NODE_ID = '684182011';
		var AJAX_CART_URL = "/alohaCartRequest";
		var AJAX_SEARCH_URL = "/searchRequest";
		var BUYBOX = $('#buy-box-wrapper');
		var EXTERNAL_BUYBOX = $('#external-buy-box-wrapper');
	    var BROWSE_SECURITY_TOKEN = '';
        var SMART_CART_OPEN_CLOSE_ID = "#cart-open-close";
		var smartCartJson = '';
	    
		/**
		 * everything in smart cart starts here.
		 */
		function initialize() {
			BROWSE_SECURITY_TOKEN = $.Aloha.Util.getSecurityTokenQuery();
			registerEventHandlers();
			var query = "operation=GET_BUNDLE&" + BROWSE_SECURITY_TOKEN;
			showLightBoxIfErrorCodeFound();
			markPageAsDitry();
			//only load the content when the collapsed cart has content.
			if ($(SMART_CART_WRAPPED_ID).length > 0){
				AjaxUtil.ajax (AJAX_CART_URL, 
	                       query, 
	                       function (json) {
	                           smartCartJson = json; 
				   showExpandedSmartCartIfBundleInvalidErrorCodeFound(smartCartJson);
	                           // because we do not want to empty the cart
	                           // due to killed asins until the user opens
	                           // the cart, but the internal changed flag
	                           // will be lost in a future GET_BUNDLE ajax
	                           // query, we store the internal change
	                           // status in a less-transient variable
	                           SmartCartUtil.hasUnhandledInternalBundleChange
	                               = json.didInternalBundleChangeOccur;
	                       }, 
	                       function (xhr, textStatus, errorThrown) {});
			}
		}

                function showExpandedSmartCartIfBundleInvalidErrorCodeFound(json) {
                        if (containsBundleInvalidErrorCodeInHtml()) {
                                updateExpandedSmartCart(json);
                        }
                }
                
                function showLightBoxIfErrorCodeFound() {
                        var isPageDirty = getIsPageDirty();
                        var errorCodeHTML = getErrorCodeInHTML();
                        if (errorCodeHTML && !isPageDirty) {
                                Util.showPopoverWithDefaultErrorTitle(errorCodeHTML);
                        }
                }
 		
		function getErrorCodeInHTML(){
                        return $("div#error-string").html();
                };

                function containsBundleInvalidErrorCodeInHtml() {
                        return ($("div#is-bundle-valid").html() === "false")
                }
        		/**
        		 * mark the page as dirty so that we know when the back button is invoked.
        		 */
        		function markPageAsDitry() {
                    $("div#is-page-dirty").find('input[name="is-page-dirty"]').val("yes");

        		}
        		function getIsPageDirty() {
        			return ($("div#is-page-dirty").find('input[name="is-page-dirty"]').val() === "yes");
        		}		
		/**
		 * ajax method for smart cart.
		 * @param {Object} query
		 */
		function ajaxCall(query) {
			AjaxUtil.ajaxCall(AJAX_CART_URL, query, handleAjaxSuccess, handleAjaxError);	
		}
		
		/**
		 * register click on/out smartcart to expand/collapse event
		 */
		function registerEventHandlers() {
            var REMOVE_PLAN_ACTION = "DELETE_SERVICE";
		
			$(document).unbind('click').bind('click', function(event){
			
	                // check to see if the user is trying to navigate away
                    if ($(event.target).is(ButtonClass.PROCEED_TO_CHECKOUT)) {
	                    refreshAndCheckForBundleChangeBeforeRedirect 
	                        ('/checkout?'
	                         + Util.getCheckoutSecurityTokenQuery());
	                    return false;
	                } else if ($(event.target).parents().is(SMART_CART_WRAPPED_ID)){
                        //when the user clicks inside of the smart cart. We need to expand the smart cart unless Close Cart was clicked.
                       
                        //if Open/Close Cart was clicked, open/close the cart
                        if ($(event.target).is(SMART_CART_OPEN_CLOSE_ID)) {
                            if ($(SMART_CART_COLLAPSED_ID).is(':hidden')) {
                                updateCollapsedSmartCart(smartCartJson);
                            } else {
                                updateExpandedSmartCart(smartCartJson);
                            }

                            return false;
                        }

	                    //user clicks on remove phone
	                    if ($(event.target).parent().hasClass('removePhone')){
	                        removeFromCart(REMOVE_PHONE_ACTION);
	                        return false;
	                    }				 
	                    //clicks on remove plan
	                    else if ($(event.target).parent().hasClass('removePlan')){
	                        removeFromCart(REMOVE_PLAN_ACTION);				
	                        return false;
	                    }
	                    else { //the user clicks anywhere inside of the smart cart. Expanding the smart cart.
	                        //if there is no json to work with, call into the server
	                        if (smartCartJson === ''){
	                            ajaxCall("operation=GET_BUNDLE&" + BROWSE_SECURITY_TOKEN);
	                        } else {
	                            //if it is already expanded, do not need to do an update.
							
	                            //if the smart cart is not already expanded, we will try to expand it.
	                            if (!$(this).hasClass(FULLY_EXPANDED)){
	                                updateExpandedSmartCart(smartCartJson);
	                            }
	                        }
	                    }
	                } else { //the user clicks outside of the smart cart. We need to collapse the smart cart.
	                    //if the collapsed version is hidden, that means we need to show it. 
	                    if ($(SMART_CART_COLLAPSED_ID).is(':hidden')) {				
	                        updateCollapsedSmartCart(smartCartJson);
	                    }		    
	                }
	            });
		}
		
		/** 
		 * to be called before advancing away from a page, this will
		 * refresh the bundle one more time to see if the asins in the
		 * bundle are still valid.  this will close the cart and display
		 * an error message if necessary
		 *
		 * @param targetUrl the url that we should be redirected to
		 */
		function refreshAndCheckForBundleChangeBeforeRedirect(targetUrl) {
			var query = "operation=GET_BUNDLE&validation=BUNDLE&" + BROWSE_SECURITY_TOKEN;
			AjaxUtil.ajax (AJAX_CART_URL, 
	                   query, 
	                   function (json) {
				var isWorkflowError = Util.showWorkflowErrorOnFailure(json);
				if (isWorkflowError) {
					updateExpandedSmartCart (json);
                                 }
	                       else if (json.didInternalBundleChangeOccur === false) {
	                           window.location = targetUrl;
	                       }
	                       else {
	                           updateExpandedSmartCart (json);
	                       }
	                   }, 
	                   function (xhr, textStatus, errorThrown) {});
		}
		/**
		 * Collapse the smart cart.
		 * @param {Object} json - use to collapse the smart cart with.
		 */
		function updateCollapsedSmartCart(json) {
		
			// Unhide the buy box
			BUYBOX.fadeIn("slow");
			EXTERNAL_BUYBOX.fadeIn("slow");
			
			//this for the border bundler section. We need to hide this section when cart is collapsed.
			$(EXPANDED_BORDER_BOTTOM_ID).hide();
			//since the smartcart state is fully expanded, the json has already been retrieved.
			//var nextStepState = SmartCartUtil.getBundleNextStep(json).name;
			
			//updating the phone, plan and option section for collapsed cart.
			var htmlObj = $('<ol></ol>');
	        PhoneSection.updateCollapsed(json,htmlObj);
	        PlanSection.updateCollapsed(json,htmlObj);
	        OptionSection.updateCollapsed(json,htmlObj);
		
			var smartCartContent = htmlObj.parent().html();
			if (smartCartContent === null){
				smartCartContent = '<ol>' + htmlObj.html() + '</ol>';
			}
			$('#smart-cart-expanded').slideUp('fast', function() {
				//add the collapsed class to smart cart. 
	        	$(SMART_CART_WRAPPED_ID).removeClass('workflow').removeClass('workflow-phone').removeClass('smart-cart-outer').addClass('collapsed');
	        	$('#smart-cart-collapsed').slideDown('fast', 
					function() {
						smartCartContent = SmartCartHtmlSkins.topLeftCorner + SmartCartHtmlSkins.topRightCorner + smartCartContent + SmartCartHtmlSkins.clearFix
						$(SMART_CART_COLLAPSED_ID).html(smartCartContent);
						$(SMART_CART_OPEN_CLOSE_ID).html("Open Cart");
					});
	    	});	
		}
		
		var updateZipCode = (function(json, htmlObj) {
			if (typeof json.zipCodeResult !== 'undefined') {
				htmlObj.find(".cart-header-zip-code span.zip-code").empty().append(json.zipCodeResult.zipCode);
			}
			return htmlObj;
		});
        /**
         * depending on the next step state, we hide or show the 
         * bottom part of our smart cart, shipping ads, proceed 
         * to check out button.
         * @param {Object} json
         * @param {Object} htmlObj
         */
		function hideAndShow(json, htmlObj) {
			var nextStepState = SmartCartUtil.getBundleNextStep(json).name;		
			$(EXPANDED_BORDER_BOTTOM_ID).show();
			//hide the 2 days free shipping ads			
			$(SHIPPING_ADS_ID).hide();				
			if (nextStepState === NextStep.SELECT_PLAN || nextStepState === NextStep.SELECT_ADDALINE_PLAN) { 
				//hide the empty cart
				$(EMPTY_CART_ID).hide();
				//hide the proceed to checkout button.
				$(ButtonClass.PROCEED_TO_CHECKOUT).hide();
			} else if (nextStepState === NextStep.SELECT_OPTIONS) {
							//hide the proceed to checkout button.
				$(ButtonClass.PROCEED_TO_CHECKOUT).show();
			}			
		}
		
		/**
		 * Expand the smart cart.
		 * @param {Object} json - use to expand the smart cart with.
		 */
		function updateExpandedSmartCart(json) {
			//save json to cache.
			smartCartJson = json;
	
			var smartCartHtmlObj = $(SmartCartHtmlSkins.smartCartEmptyBaseExpanded);
			var nextStepState = SmartCartUtil.getBundleNextStep(json).name;
			
			//this is when the cart is empty.
			if ($('#smart-cart-wrapper').length == 0) {
				var smartCartBaseObj = updateZipCode(json,$(SmartCartHtmlSkins.smartCartEmptyBaseMinimize));
				$('#smart-cart').append(smartCartBaseObj.parent().html());
			}
			 //show empty cart.
			if (nextStepState === NextStep.NONE){
				//hide smart cart content so that we can just show the empty cart.
				$(SMART_CART_WRAPPED_ID).remove();				
				if ($(EMPTY_CART_ID).is(':hidden')) {
					$(EMPTY_CART_ID).show();
				} else {
					smartCartHtmlObj = $(SmartCartHtmlSkins.emptyCart);
					$('#smart-cart').empty().html(smartCartHtmlObj.parent().html());				
				}	
				//the cart is now empty. Show the 2 days shipping ads.
				$(SHIPPING_ADS_ID).show();
				BUYBOX.fadeIn("slow");
				EXTERNAL_BUYBOX.fadeIn("slow");
			} else {
				// Hide the buy box, if it can be found
				BUYBOX.fadeOut("slow");
				EXTERNAL_BUYBOX.fadeOut("slow");
				 
				PhoneSection.updateExpanded(json, smartCartHtmlObj);
				PlanSection.updateExpanded(json, smartCartHtmlObj);
				OptionSection.updateExpanded(json, smartCartHtmlObj);		
				BundlePriceSection.updateExpanded(json, smartCartHtmlObj);
				CheckOutButtonSection.updateExpanded(json, smartCartHtmlObj);
				hideAndShow(json, smartCartHtmlObj);
			}
			
		    $('#smart-cart-collapsed').slideUp('fast', function() {
		        $(SMART_CART_WRAPPED_ID).addClass('workflow').addClass('workflow-phone').addClass('smart-cart-outer').removeClass('collapsed');
		        $('#smart-cart-expanded').slideDown('fast', function() {
                    $("#smart-cart-expanded").empty().html(smartCartHtmlObj.html());
                    $(SMART_CART_OPEN_CLOSE_ID).html("Close Cart");
                });
		    });
			//need to reattach the event handlers after the html has been updated.
			registerEventHandlers();
	
	        if (json.didInternalBundleChangeOccur === true
	            || SmartCartUtil.hasUnhandledInternalBundleChange === true) {
				Util.showPopoverError ("Updated Cart", 
	                              "One or more of the items in you cart was removed due to a "
	                              + "change in availability.  Depending on the items removed, you may need to "
	                              + "select new items before being able to proceed to checkout.  We apologize "
	                              + "for the inconvenience.");
	            smartCartJson.didInternalBundleChangeOccur = false;
	            SmartCartUtil.hasUnhandledInternalBundleChange = false;
	        }
		}
		/**
		 * send ajaxcall to remove phone or plan from cart. 
		 * @param removeAction should be either DELETE_LINE or DELETE_SERVICE
		 */
		 function removeFromCart (removeAction) {
		 		//AJAX request		
				//var securityTokenQuery = Util.getSecurityTokenQuery(Util.SECURITYDIV);
				var operation = "&operation=" + removeAction;
				var query = BROWSE_SECURITY_TOKEN + operation;
				//a proxy to refresh plan page.
				//this is used when the customer is on the plan page and removes a 
				//phone. We refresh the plan page when this happened.
				//we need to let the ajax for remove phone done executing.
				//on the ajax success call back, we then call into our backend ask
				//for a new plan page.
                function _ajaxSuccess(_ajaxSuccessCallBack) {
                    var ajaxSuccessCallBack = _ajaxSuccessCallBack;
                    return {
                        callBackHandler: function(json) {
                        $.Aloha.BrowsePlan.refreshPage();
                        ajaxSuccessCallBack(json);
                        }
                    }
                }
				var nodeId = window.location.pathname.match(/\d+/) || "";
				var ajaxSuccessHandler = handleAjaxSuccess;
				if (removeAction === REMOVE_PHONE_ACTION && nodeId.toString() === PLAN_NODE_ID) {
					//we only create this wrapper when we are on the plan page and user tries to remove a phone.
					var ajaxSuccess = new _ajaxSuccess(handleAjaxSuccess);	
					ajaxSuccessHandler = ajaxSuccess.callBackHandler;		
				}
				AjaxUtil.ajaxCall(AJAX_CART_URL, query, ajaxSuccessHandler, handleAjaxError);
		 }
		 
		 /**
	      * Handles case where ajax request/response was successful.
	      * @param json Response from server
	      */
		function handleAjaxSuccess(json) {	
			updateExpandedSmartCart(json);
			Util.showWorkflowErrorOnFailure(json);
			smartCartJson = json;
		}
	
		/**
		 * Handles case where ajax request/response failed.
		 */
		function handleAjaxError(xhr, textStatus, errorThrown) {
			AjaxUtil.showAjaxCallError(xhr, textStatus, errorThrown);
		}
		/**
		 * public methods to the world.
		 */
		$.Aloha.SmartCart = {
	        initialize: initialize,
	        handleAjaxSuccess: handleAjaxSuccess,
	        handleAjaxError: handleAjaxError,
	        updateExpandedSmartCart: updateExpandedSmartCart,
	        updateCollapsedSmartCart: updateCollapsedSmartCart
        } 
	}();
	

	$(function() {
        $.Aloha.SmartCart.initialize();
	});
})(jQuery)


jQuery.fn.preventDoubleSubmit = function() {
  jQuery(this).submit(function() {
    if (this.beenSubmitted)
      return false;
    else
      this.beenSubmitted = true;
  });
};

var YourAccountViewOrderDetail = {
	ACTIVATION_BUTTON: 'form#activationForm input#activationSubmitButton',
	ACTIVATION_FORM: 'form#activationForm',
	disableActivationButton: function() {
		jQuery(YourAccountViewOrderDetail.ACTIVATION_FORM).preventDoubleSubmit();
		$(YourAccountViewOrderDetail.ACTIVATION_BUTTON).attr("disabled","");
		$(YourAccountViewOrderDetail.ACTIVATION_BUTTON).attr("style","cursor:text;opacity:0.4");
	}
}

