(function($) {
	/**
	 * This data structure is used to support our options page
	 * price dynamic update. We use two hashtables.
	 * One hash table to store all the prices that you use has selected
	 * and removed. The other is for all the asins.
	 */
	var PriceCategoryState = function(){
		//store the prices.
		//The key for options that are radio buttons is its option category.
		//only one of this category can exist.
		//they key for options that are checkboxes is its asin.
		var mapHash = {}; 
		//store all the asins.
		var asinHash = {};

		/**
		 * add an element into our map and asin hash.
		 * @param {Object} cat - the category name.
		 * @param {Object} price
		 * @param {Object} asin
		 */
		function addElement(cat, price, asin){
			if (typeof price !== 'undefined' && price !== '') {
				mapHash[cat] = price;
			}
			if (typeof asin !== 'undefined' && asin !== '') {
				asinHash[cat] = asin;
			}
		}
		/**
		 * remove the category both from our asinhash and maphash.
		 * @param {Object} cat
		 */
		function removeElement(cat){
			if (typeof cat !== 'undefined') {
				delete mapHash[cat];
				delete asinHash[cat];
			}
		}
		
		/**
		 * returns an array of asins.
		 */
		function getAsins(){
			var array = [], asin;
			for (asin in asinHash) {
				array.push(asinHash[asin]);
			}
			return array;
		}
		
		/**
		 * returns an array of prices.
		 */
		function getPrices(){
			var array = [], cat, asin;
			for (cat in asinHash) {
				asin = asinHash[cat];
				array.push(asin);
			}
			return array;
		}
		/**
		 * The sum of the prices.
		 */
		function sumPrices(){
			var sum = 0.0, cat;
			for (cat in mapHash) {
				sum += mapHash[cat];
			}
			return sum;
		}
		
		return {
			addElement: addElement,
			removeElement: removeElement,
			getAsins: getAsins,
			getPrices: getPrices,
			sumPrices: sumPrices
		};
	}();
	
	var Options = function(){
		//constants
		var TOTAL_PRICE_ID = '.service-options-total .total-price';
		var OPTIONS_SECTION_LI = 'div.options-section li input';
		var ADDITIONAL_SERVICES_PREFIX = 'additional_services';
		var ADD_TO_CART = '.service-options-total input.add-to-cart-button';
		var Util = $.Aloha.Util;
		var AjaxUtil = $.Aloha.AjaxUtil;
		
		//entry to Options.
		function initialize(){
			registerEventHandlers();
		}
		
		/**
		 * Everytime the user clicks on an option in the Option page,
		 * this method is called to save the option state into our 
		 * PriceCategoryState.
		 * @param {Object} trigger
		 */
		function saveState(trigger){
			var price = parseFloat(Util.getPrice(trigger.attr('value')));
			var category = trigger.attr('name');
			var asin = trigger.attr('id');
			if (!isNaN(price)) { //price has to be a number
				if (category.toLowerCase().match(ADDITIONAL_SERVICES_PREFIX) !== null) {
					//we will use asin as the category
					if (trigger.is(":checked")) {
						PriceCategoryState.addElement(asin, price, asin);
					}
					else {
						PriceCategoryState.removeElement(asin);
					}
				}
				else {
					PriceCategoryState.addElement(category, price, asin);
				}
			}
		}
		/**
		 * Options ajaxCall.
		 * All options ajax call should go through here.
		 * @param {Object} path
		 * @param {Object} requestData
		 * @param {Object} successCallBack
		 * @param {Object} errorCallBack
		 */
		function ajaxCall(path, requestData, successCallBack, errorCallBack){
			AjaxUtil.ajaxCall(path, requestData, successCallBack, errorCallBack);
		}
		
		/**
		 * The event handlers for option page.
		 * This method attaches event handlers to each option in the option page.
		 * also the add the cart button.
		 */
		function registerEventHandlers(){
			//the options
			$(OPTIONS_SECTION_LI).each(function(i, trigger){
				var trigger = $(trigger);
				//we save the fields that are checked into our PriceState.
				if (trigger.is(":checked")) {
					saveState(trigger);
				}
				trigger.unbind('click').bind('click', function(){
					saveState($(this));					
					$(TOTAL_PRICE_ID).html("$" + PriceCategoryState.sumPrices().toFixed(2));
				});
			})
			//register add to car button.
			$(ADD_TO_CART).unbind('click').bind('click', function(){
				var securityTokenQuery = Util.getSecurityTokenQuery();
				var asinQuery = "&asins=" + PriceCategoryState.getAsins();
				var operation = "&operation=SET_LINE_OPTIONS";
				var lineID = "&line=" + $('div#lineID input').attr('value');
				var query = securityTokenQuery + asinQuery + operation + lineID;
				var smartCart = $.Aloha.SmartCart;
				ajaxCall('/alohaCartRequest', query, smartCart.handleAjaxSuccess, smartCart.handleAjaxError);
			});
		}
		/**
		 * public interface to the world.
		 */
        if (typeof $.Aloha === 'undefined') {
            $.Aloha = {}
        }
        if (typeof $.Aloha.BrowseOptions == 'undefined') {
			$.Aloha.BrowseOptions = {
				initialize: initialize
			}
		}
	}();
	
	$(function() {
		$.Aloha.BrowseOptions.initialize();
	});
})(jQuery)