(function($) {
    if (typeof $.Aloha === 'undefined') {
        $.Aloha = {}
    }

    /**
     * A utility class that can be shared among our javascript code.
     */
    var Util = function() {
        var SORRY_ERROR_MESSAGE_TITLE = "Sorry! We were unable to process your request.";
        var SORRY_ADD_ERROR_MESSAGE_TITLE = "Sorry! We are unable to add items to your cart.";
        var SELECT_ALL_PHONES = '<p><span class="carat">></span> <a href="/b/684177011">See all phones</a></p>';
        var SEE_PLANS = '<p><span class="carat">></span> <a href="/b/684182011">See plans</a></p>'
        var SEE_COMPATIBILE_PLANS = '<p><span class="carat">></span> <a href="/b/684182011">See compatible plans</a></p>'
        var SEE_SERVICE_OPTIONS = '<p><span class="carat">></span> <a href="/options">See Service Options</a></p>'
        /**
        * Given a Jquery Security Token object, this method returns
        * a security string that can be returned to the server.
         * @param {Object} securityTokenObj
         */
        function getSecurityToken(securityTokenObj) {
            var securityObj = securityTokenObj;
            var appActionToken = securityObj.find("input[name='appActionToken']").val() || "";
            var appAction = securityObj.find("input[name='appAction']").val() || "";
            return "appActionToken=" + appActionToken + "&appAction=" + appAction;
        }
        
        /**
        * This method returns a Security Token String that can be
        * used by the server to check for the validity of the request.
        */
        function getSecurityTokenQuery() {
            return getSecurityToken($("div#securityToken"));
        }
        
        /**
         * Returns a Checkout Security Token String that can be used when the 
         * user wants to checkout.
         */
        function getCheckoutSecurityTokenQuery() {
            return getSecurityToken($("div#purchaseSecurityToken"));		
        }
        
        /**
        * this method extract a float out of a String.
        * @param {Object} price - this is a string.
        */
        function getPrice(price) {
            var priceRE = /\d*\.\d+/;
            var priceResult = '';
            if (typeof price !== 'undefined' && price !== '' && price !== null) {
                priceResult = price.match(priceRE)[0];	
            }
            return priceResult;
        }
        /**
        * Display a lightbox error message if there is a workflow error 
        * @param {Object} json - the json to check.
        */	
        function showWorkflowErrorOnFailure(json) {
            if (typeof json.workflowResult !== 'undefined' && json.workflowResult.resultCode === "FAILURE") {
                var errorStr = "<ul>";
                var errorTitle = SORRY_ERROR_MESSAGE_TITLE;
                
                var noService = false;
                var noLines = false;

                var jsonErrors = json.workflowResult.errors;
                if (typeof jsonErrors !== 'undefined') {
                    for (i = 0; i < jsonErrors.length; ++i) {
                        var error = jsonErrors[i];
                        
                        if (error.errorType === "NO_SERVICE") noService = true;
                        if (error.errorType === "NO_LINES") noLines = true;
                        errorStr += "<li>" + jsonErrors[i].errorString + "</li>";
                    }
                }
                
                if (noLines) {
                    errorStr =
                          "<p>At this time, a phone must first be added to your cart.</p>" + SELECT_ALL_PHONES;                        
                    errorTitle = SORRY_ADD_ERROR_MESSAGE_TITLE;
                } else if (noService) {
                    errorStr =
                          "<p>At this time, a plan must first be added to your cart.</p>" + SEE_PLANS;                    
                    errorTitle = SORRY_ADD_ERROR_MESSAGE_TITLE;
                } else {
                    errorStr += "</ul>";
                }
                
                showPopoverError(errorTitle, errorStr);
                return true;
            }
            return false;
        }
		/**
		 * show a lightbox error message.
		 * @param {Object} boxMessage
		 */
		function showPopoverWithDefaultErrorTitle(boxMessage) {
			showPopoverError(SORRY_ERROR_MESSAGE_TITLE, boxMessage);
		}
		/**
		 * Use to display a lightbox as an error message.
		 * @param {Object} boxTitle - lightbox title
		 * @param {Object} boxMessage - lightbox error message content.
		 */
		function showPopoverError(boxTitle, boxMessage) {
			if (typeof boxTitle === 'undefined') {
				boxTitle = "";
			}
			if (typeof boxMessage === 'undefined') {
				boxMessage = "";
			}		
	        var ie6 = jQuery.browser.msie && parseInt(jQuery.browser.version) <= 6;
	        var skinType = ie6 ? "classic" : "default";
			jQuery.AmazonPopover.displayPopover({
	                literalContent: boxMessage,
	                title: boxTitle,
	                showCloseButton: true,            
	                modal: true,        
	                skin: skinType,
	                centered: true
			});
	    }
		
		/**
		 * Check a value is not empty or empty
		 * @param value
		 * @return true/false
		 */
		function validateIsNotEmpty(value) {
			if(value === null && typeof value !== 'undefined') {
				return false; 
			}
		  	return jQuery.trim(value)!=='' ? true : false;
		}
		
		/**
		 * Check email is valid or not
		 * @param email
		 * @return true/false
		 */
		function validateEmail(email) {
	        if (email == null) {
	            return false;
	        }
	        if (email.match (/^.*@.*@.*$/)) {
	            return false;
	        }
	        return email.match (/^.+@.+\..+$/) ? true : false;
	    }
		/**
		 * public methods to the world.
		 */
        if (typeof $.Aloha.Util === 'undefined') {
            $.Aloha.Util = {          
	            showPopoverError: showPopoverError,
	            showPopoverWithDefaultErrorTitle: showPopoverWithDefaultErrorTitle,
	            showWorkflowErrorOnFailure: showWorkflowErrorOnFailure,
	            getSecurityTokenQuery: getSecurityTokenQuery,
	            getCheckoutSecurityTokenQuery: getCheckoutSecurityTokenQuery,
	            getPrice: getPrice,
	            validateIsNotEmpty: validateIsNotEmpty,
	            validateEmail: validateEmail
            }
        }
	}();
	
	/**
	 * Ajax utility class
	 */
	var AjaxUtil = function() {
		var ajaxHandler = null;
		var timeout = 15000;
		var TIME_OUT = "timeout";
		var Util = $.Aloha.Util;
		var ErrorMessage500 = "Please refresh your page and try again.";
		var ErrorMessage404 = "Please enable cookies in your web browser to continue.<br/><br/>Once you have enabled cookies, please refresh the page and continue shopping.";
		var ErrorMessage404Title = "Important Message";
		
		/**
		 * This method is used to for ajax. It has the ability to cancel any
		 * previous pending ajax calls that the user made through calling this function.
		 * This is very useful for our abn pages. Everytime our usr clicks on a checkbox
		 * in the abn page, we fire off an ajax call. If the customer selects very quickly,
		 * we would like to cancel any previous active ajax calls.
		 * @param {Object} path - the server path.
		 * @param {Object} requestData - data to pass back to the server.
		 * @param {Object} successCallBack - a callback function when ajax call is successful.
		 * @param {Object} errorCallBack - a callback function when ajax call failed.
		 */
		function ajaxCall(path, requestData, successCallBack, errorCallBack) {
			cancelActiveAjaxCall();
			ajaxHandler = ajax(path, requestData, successCallBack, errorCallBack);
		}
		
		/**
		 * This method is used to cancel any active ajax calls that was made 
		 * from calling ajaxCall.
		 */
		function cancelActiveAjaxCall() {
			if (ajaxHandler) {
				ajaxHandler.abort();
			}
	    }
		/**
		 * This method does an ajax call and also passes back an ajax handler.
		 * It doesn't cancel any of its ajax calls.
		 */
	    function ajax(path, requestData, successCallBack, errorCallBack) {
			return $.ajax({
					url: path,
					type: 'POST',
					dataType: 'json',
					timeout: timeout,
					data: requestData,
					error: function(xhr, textStatus, errorThrown) {
						errorCallBack(xhr, textStatus, errorThrown);
					},
					success: function(json){
						successCallBack(json);
					}
				});
		}
	    /**
	    * Display appropriate error message when ajax failed.
	    */ 
	    function showAjaxCallError(xhr, textStatus, errorThrown) {
			//It is important to check for the readyState.
			//If the readyState is 0, looking at the xhr.status throws an exception.
            /*500 mostly means Internal Server Error due to Security Token*/
	        if (xhr.readyState !== 0) {
	            if (xhr.status === 500) {
	                Util.showPopoverWithDefaultErrorTitle(ErrorMessage500);
	            } else if (xhr.status === 404) {
	                Util.showPopoverError(ErrorMessage404Title, ErrorMessage404);
	            }
		    }
	    }
		/*
		 * public methods 
		 */
	    if (typeof $.Aloha.AjaxUtil === 'undefined') {
	        $.Aloha.AjaxUtil = {          
	            ajax: ajax,
	            ajaxCall: ajaxCall,
	            cancelActiveAjaxCall: cancelActiveAjaxCall,
		    showAjaxCallError: showAjaxCallError
	        }
	    }
	}();
    
})(jQuery)

