/*
 * jQuery Price Calculator 1.4
 * http://benmartinstudios.com.au/
 * 27 October 2011
 *
 * Copyright 2011, Ben Martin
 * Must not be used without permission
 * Contact ben@benmartinstudios.com.au for more details
 *
 */

(function($){

	$.fn.bSlider = function(){
		return this.each(function(index, value){
			var elem = $(this);
			var attr = $.parseJSON(elem.attr('data-slider'));
			elem.slider(attr);
		});
	}
	
	$.fn.hasAttr = function(attr){
		return $(this).is('['+attr+']');
	}

	//function to float an object within it's parent as the window scrolls
	function floatInParent(elem, margin){
		if(typeof margin === 'undefined'){
			margin = 20;
		}
		if (elem.length === 0){ return false; }
		var parent = elem.parent();
		elem.css('top', 0);
		var minY = elem.offset().top - margin,
			maxY = parent.offset().top + parent.height() - elem.height(),
			pPosInit = parent.offset().top,
			origPos = elem.css('position');
	
		var positionElem = function(){
			var pPos = parent.offset().top;
			var scroll = $(window).scrollTop() - (pPos - pPosInit);
			//console.log(pPos, scroll, minY, maxY);
			if(scroll > minY && scroll < maxY){
				elem.css('position', 'fixed')
					.css('margin-top', margin+'px');
			} else {
				elem.css('position', origPos)
					.css('margin-top', '0');
			}
		}
		$(window).scroll(positionElem);
		positionElem();
    
	}
	
	/*
	http://www.merlyn.demon.co.uk/js-maths.htm#RecTS
	modified to accept thousands parameter
	*/
	function RComma(S,T) {
		S = String(S);
		var RgX = /^(.*\s)?([-+\u00A3\u20AC]?\d+)(\d{3}\b)/;
		return S == (S = S.replace(RgX, "$1$2"+T+"$3")) ? S : RComma(S, T);
	}
	
	//function to initialize jquery ui sliders and numeric spinners
	function instantiateElements(elem){
		elem.find('[data-slider], [data-spinner]').each(function(index, value){
			var elem = $(this);
			var attr = '';
			if(elem.hasClass('spinner')){
				attr = $.parseJSON(elem.attr('data-spinner'));
				elem.spinner(attr);
			} else {
				attr = $.parseJSON(elem.attr('data-slider'));
				elem.removeAttr('data-slider');
				attr.value = elem.data('default');
				elem.hide();
				if(elem.is('input')){
					elem = elem.after('<div data-default="'+attr.value+'" data-cost="'+elem.data('cost')+'"/>').next();
				}
				elem.after('<span class="sl-amount">'+attr.value+'</span>');
				attr.slide = function(event, ui){
					var elem = $(this);
					elem.next('.sl-amount').text(ui.value);
					elem.prev(':input').val(ui.value);
				}
				elem.slider(attr);
			}
		});
	}

	var BPrice = function(elem, options){	
	
		var formatPrice = function(price){
			return settings.signBefore+RComma(price.toFixed(2).replace('.', settings.decimalSep), settings.thousandsSep)+settings.signAfter;
		}
	
		var getPrice = function(elem){
			elem = getActualElem(elem);
			cost = 0;
			if(elem.hasClass('slider')){
				val = elem.data('sVal');
				if(typeof val === 'undefined'){
					val = elem.data('default');
				}
				cost = parseFloat(elem.data('cost'), 10) * parseFloat(val, 10);
			} else if (elem.hasClass('spinner')){
				cost = parseFloat(elem.data('cost'), 10) * parseFloat(elem.val(), 10);
			} else if (elem.is('select')){
				//iterate over the result set, as more than one option can be selected for multi selects
				elem.find('option:selected').each(function(i){
					cost += parseFloat($(this).data('cost'), 10);
				});
			} else if (elem.is('option')){
				cost += parseFloat(elem.data('cost'), 10);
			} else {
				cost = elem.data('cost');
			}
			if(typeof cost === 'undefined'){
				cost = 0;
			}
			if(isNaN(parseFloat(cost, 10))){
				cost = 0;
			}
			return parseFloat(cost, 10);
			
		
		}
		
		var getVal = function(elem, text){
			elem = getActualElem(elem);
			var val = null;
			if(elem.hasClass('slider')){
				val = elem.data('sVal');
			} else {
				//elem = elem.find(':selected');
				if(text){
					val = elem.parent().clone();
					val.find('.bprice-price').remove();
					if(val.is('select')){
						val = elem;
					}
					val = $.trim(val.text());
				} else {
					val = elem.val();
				}
			}
			if(elem.parent().hasClass('check-rad')){
				val = elem.parent().parent().clone();
				val.find('.bprice-price').remove();
				val = val.text();
			}
			return val;
		
		}
		
		var calculatePrice = function(elements, quantities){
			var total = 0;
			
			//add each element cost
			elements.each(function(){
				var elem = $(this);
				total += getPrice(elem);
			});
			
			//deal with quantity fields
			quantities.each(function(){
				var elem		= $(this),
					quantity	= getVal(elem),
					fields		= elem.data('quantity'),
					subTotal	= 0;
				
				//return early if the quantity is empty
				if($.trim(fields) === ''){
					return;
				}	
				//return if the quantity is not a number, if it is 1, or if it is empty
				if(isNaN(quantity) || quantity === 1 || elem.val() === ''){
					return;
				}
					
				//get each element for the quantity					
				$.each(fields.split(','), function(index, value){
					elements.filter('[name="'+$.trim(value)+'"]').each(function(){
						subTotal += getPrice($(this));
					});
				});
				
				//multiply by the quantity (subtract 1, as each element has already been added), and add to the total
				total += subTotal*(quantity-1);
				
			});
			
			subDiv.find('.total span').text(formatPrice(total));
			
				$("#final_price").val(Math.round(total)); 
		}
	
		var showHidePrices = function(show){
			if(typeof show === 'undefined'){
				show = !settings.showPrices;
			} else if (typeof show !== 'boolean'){
				show = true;
			}
			var prices = optionsDiv.find('.bprice-price');
			if(show){
				prices.stop().fadeTo(settings.pricesFadeTime, 1);
			} else {
				prices.stop().fadeTo(settings.pricesFadeTime, 0);
			}
		}
		
		var updatePrices = function(elements){
			optionsDiv.find(':input').each(function(){
				var elem = $(this);
				var priceTag = elem.nextAll('.bprice-price');
				if(elem.is('textarea') || elem.attr('data-cost') === 'null'){
					if(elem.next().is('.bprice-price')){
						elem.next().remove();
					}
				}
				if(elem.is('select') && elem.is('.bform')){
					priceTag = elem.parent().nextAll('.bprice-price');
				}
				if(priceTag.length !== 0){
					if(priceTag.is(':empty')){
						priceTag.append(' - <span></span>');
					}
					price = getPrice(elem);
					fPrice = formatPrice(price);
					if(price === 0){
						if(settings.showZeroAs === false){
							priceTag.empty();
						} else {
							fPrice = settings.showZeroAs;
							if(parseFloat(fPrice, 10) === 0){
								fPrice = settings.signBefore+price.toFixed(2)+settings.signAfter;
							}
						}
					}
					priceTag.children('span').text(fPrice);
				}
			});
		}
		
		var getActualElem = function(elem){
			aElem = elem;
			/*
			if(elem.is('select')){
				aElem = elem.find(':selected');
			}
			*/
			return aElem;
		}
		
		var getElements = function(optionsDiv){
		
			//get all appropriate elements
				//any selected option elements or checked radio buttons/checkboxes
			var	elems = optionsDiv.find(':selected, :checked');
				//any text input
				elems = elems.add(optionsDiv.find('input:text'));
				
			//remove any quantity fields
			elems = elems.not('[data-quantity]');
			
			//remove any disabled inputs
			elems.not('[disabled]');
			
			return elems;
		
		}
		
		var getQuantities = function(optionsDiv){
			return optionsDiv.find('[data-quantity]');
		}
		
		var itemize = function(elements, quantities){
			if(settings.itemize){
				//add any sliders to the list
				var elems = elements.add(quantities),
					items = new Array(),
					keys = new Array();
				elems.each(function(index, value){
					rawElem = $(this);
					elem = getActualElem(rawElem);
					var def = elem.attr('data-default');
					
					//if the element is a default, ignore it when itemizing
					if(def === 'true' || def === true){	return true; }
					
					id = '';
					if(elem.is('option')){
						elem = elem.parents('select');
					}
					if(elem.hasAttr('name')){
						id = elem.attr('name');
					} else if (elem.hasAttr('id')){
						id = elem.attr('id');
					} else if (elem.is('.ui-slider')) {
						//element is ui slider and has neither a name nor an id, get the id of it's input fallback
						id = elem.prev(':input').attr('id');
					} else {
						return false;
					}
					
					//if no label is defined, return early
					if(typeof settings.items[id] === 'undefined'){
						return;
					}
					
					var isQ = elem.hasAttr('data-quantity');
					
					var val = '';
					if(elem.is('select')){
						val = getVal(rawElem, !isQ);
					} else {
						if(elem.is('.spinner') || (elem.is('[type="text"]'))){
							val = getVal(elem);
						} else {
							val = getVal(elem, !isQ);
						}
					}
					if(typeof val !== 'undefined'){
						if(typeof items[settings.items[id]] === 'undefined'){
							items[settings.items[id]] = new Array();
							keys.push(settings.items[id]);
						}
						items[settings.items[id]].push(val);
					}
				});
				var text = '';
				$.each(keys, function(index, value){
					text += '<p><strong>'+value+': </strong>';
					value = items[value];
					if(value.length === 1){
						text += value[0]+'</p>';
					} else {
						text += '</p>';
						text += '<ul>';
						$.each(value, function(index2, value2){
							text += '<li>'+value2+'</li>'; 
						});
						text += '</ul>';
					}
				});
				if(keys.length === 0){
					text = settings.emptySummaryText;
				}
				subDiv.find('.itemize > div').html(text);
			}
		}
	
		var settings = $.extend({
			floatSub:			false,
			subSelector:		'',
			subAlign:			'right',
			showPrices:			true,
			showPricesOption: 	true,
			showZeroAs:			false,
			signBefore:			'$',
			signAfter:			' USD',
			pricesFadeTime:		600,
			itemize:			false,
			items:				[],
			decimalSep:			'.',
			thousandsSep:		',',
			emptySummaryText:	'<p>Please configure your order...</p>'
		}, options || {});
		
		/*
		
		Initialize
		
		*/
		
		var element = $(elem),
			selector = element.attr('id');
		element.addClass('bprice');
		
		element.wrapInner('<div class="options"/>');
		if(settings.subSelector === ''){
			element.append('<div class="sub"/>');
		}
		element.append('<div style="clear: both;"/>');
		
		//initialize any sliders or numeric spinners
		instantiateElements(elem);
		
		var optionsDiv = element.children('.options'),
			selectedSub = $(settings.subSelector).first(),
			subDiv = ((settings.subSelector === '' && selectedSub.length === 0) ? element.children('.sub') : selectedSub.addClass('sub')),
			priceDiv = subDiv.append('<div class="total-price"/>').find('.total-price');
		
		if(settings.subSelector !== ''){
			if(subDiv.length === 0){
				alert('options.subSelector is invalid');
			}
		}
		
		if(settings.itemize){
			var itemDiv = subDiv.append('<div class="itemize"><p>Summary:</p><div></div></div>').find('.itemize');
		}
		
		if(settings.showPricesOption){
			var confDiv = subDiv.append('<div class="conf"/>').find('.conf');
		}
		
		if(settings.subAlign === 'bottom'){
			element.addClass('bottom');
		} else {
		
			if(settings.subSelector === ''){
			
				var optionsWidth = element.width() - parseFloat(subDiv.outerWidth(), 10)
									- ((settings.subAlign === 'left') ? parseFloat(subDiv.css('margin-right'), 10) : parseFloat(subDiv.css('margin-left'), 10));
				
				optionsDiv.css('width', optionsWidth+'px');
				
				
			
				if(settings.subAlign === 'left'){
					element.addClass('left');
					subDiv.css('margin-left', '0');
				} else if(settings.subAlign === 'right'){
					element.addClass('right');
					subDiv.css('margin-left', (optionsDiv.outerWidth() + parseFloat(subDiv.css('margin-left'), 10))+'px');
				}
				
			}
		
		}
				
		priceDiv.append('<p class="total">Total: <span>...</span> Per Month</p>');
		
		if(settings.showPrices || settings.showPricesOption){
			optionsDiv.find(':input').not('.slider').each(function(){
				var elem = $(this);
				elem.parent().append('<span class="bprice-price"> - <span></span></span>');
			});
			optionsDiv.find('div.ui-slider').each(function(){
				var elem = $(this);
				elem.parent().append('<span class="bprice-price slider">Megabytes - <span></span></span>');
				elem.bind('slide', function(ev, ui){
					//elem.next().find('span:first').text(ui.value);
				});
				elem.nextAll('.bprice-price.slider').find('span:first').text(elem.slider('value'));
			});
		}
		
		if(settings.showPricesOption){
			checked = '';
			if(settings.showPrices){
				checked = ' checked="checked"';
			}
			confDiv.append('<p><label><input type="checkbox" name="bprice-showPrices"'+checked+' /> Show Prices</label></p>');
			confDiv.find('[name="bprice-showPrices"]').change(function(){
				if($(this).prop('checked')){
					showHidePrices(true);
				} else {
					showHidePrices(false);
				}
			});
			
			confDiv.append('<br /><p><img src="2co2.jpg"></p>');
			
		}
		
		var change = function(ev, ui){
			var elements 	= getElements(optionsDiv),
				quantities 	= getQuantities(optionsDiv);
			calculatePrice(elements, quantities);
			updatePrices(elements);
			itemize(elements, quantities);
		}
		
		optionsDiv.find(':input').change(change);
		optionsDiv.find('.ui-slider').bind('slide', function(ev, ui){
			$(this).data('sVal', ui.value).prev('input').data('sVal', ui.value);
			change(ev, ui);
		});
		
		/*
		
		Calculate Price
		
		*/
		
		change();
		floatInParent(subDiv);
		
	}

	$.fn.bPrice = function(options) {
		return this.each(function(){
			var element = $(this);
			var elem = this;
			// Return early if this element already has a plugin instance
			if (element.data('bprice')) return;
			// Pass options to plugin constructor
			var bPrice = new BPrice(element, options);
			// Store plugin object in this element's data
			element.data('bprice', bPrice);
			
			
			
				
		});
	};

})(jQuery);
