$(document).ready(
	function(){
		
		//need to round decimals for label prices, but not all browsers support toFixed
		if (!Number.toFixed) {
			Number.prototype.toFixed = function(x) {
   			var temp = this;
   			temp = Math.round(temp*Math.pow(10,x))/Math.pow(10,x);
   			return temp;
			};
		}
		
		// round down to two decimal places
		function r2(n) {
		  ans = n * 1000;
		  ans = Math.round(ans /10) + "";
		  while (ans.length < 3) {ans = "0" + ans;}
		  len = ans.length;
		  ans = ans.substring(0,len-2) + "." + ans.substring(len-2,len);
		  return ans;
		} 
		
		function getScrollHeight()	{
   		var h = window.pageYOffset ||
        document.body.scrollTop ||
        document.documentElement.scrollTop; 
   		return h ? h : 0;
		}
		
		
		function fFixInt(i) {
			x = parseInt(i,10);
			y = isNaN(x) ? "" : x;
			return y;
		}
		
		function fFixPrice(f) {
			bDecimal = f.indexOf('.');
			iDollars = isNaN(parseInt(f,10)) ? "" : parseInt(f,10);
			iRawCents = bDecimal > 0 ? f.slice(bDecimal+1,bDecimal+3) : "";
			if (iRawCents == "00") {
				iCents = "00";
			} else if (iRawCents.charAt(0) == "0") {
				iCents = isNaN( parseInt(iRawCents.charAt(1),10)) ? "0" : "0"+ iRawCents.charAt(1);
			} else {
				iCents = isNaN(parseInt(iRawCents,10)) ? "" : parseInt(iRawCents,10);
			}
			fixed = bDecimal > 0 ? iDollars+"."+iCents : iDollars;
			return fixed;
		}
		
		function fSetMark(e,v,min,max) {
			if (!isNaN(v) && v <= max && v >= min) {
				e.removeClass('mark');
			} else {
				e.addClass('mark');
			}
		}
		
		function fIntSetter(e,t) {
			var min = e.attr("min") ? parseInt( e.attr("min") ) : "0";
			var max = e.attr("max") ? parseInt( e.attr("max") ) : "1000000";
			var original = e.attr("original") ? parseInt ( e.attr("original") ) : "0";
			e.focus(
				function() {
					e.select();
				}
			).keyup(
				function() {
					e.val( fFixInt( e.val() ) );
					v = parseInt(e.val());
					fSetMark(e,v,min,max);
					t ? e.trigger(t) : false;
				}
			).blur(
				function() {
					e.val() == "" ? e.val(original) : false;
					v = parseInt(e.val());
					fSetMark(e,v,min,max);
					t ? e.trigger(t) : false;
				}
			);
		}
		
		function fPriceSetter(e,t) {
			var min = e.attr("min") ? parseFloat( e.attr("min") ) : "0";
			var max = e.attr("max") ? parseFloat( e.attr("max") ) : "1000000";
			var original = e.attr("original") ? e.attr("original") : "0";
			e.focus(
				function() {
					e.select();
				}
			).keyup(
				function() {
					e.val( fFixPrice(e.val() ) );
					v = parseFloat(e.val());
					fSetMark(e,v,min,max)
					t ? e.trigger(t) : false;
				}
			).blur(
				function() {
					e.val() == "" ? e.val(original) : e.val(r2(parseFloat(e.val())));
					v = parseFloat(e.val());
					fSetMark(e,v,min,max)
					t ? e.trigger(t) : false;
				}
			);
		}
		
		// pass data from an ajax cart update, will update DOM with new items
		function fUpdateCatalog(data) {
			// create temp container to put newly returned data into
			
			$('#content').after("<div id='tempbox' style='display:none'>"+data+"</div>")
			
			fBBCorners( $('#tempbox .bb_corners') );
			
			// grab every new row from the temp box and replace the existing row with it
			fReplaceItemPops = function(set) {
				fBringAttention(set);
				set.each(
					function() {
						sku = $(this).attr('sku');
						$('div.catalog_line_item table .itempop[sku='+sku+']').replaceWith($(this));
						eNewLine = $('div.catalog_line_item table .itempop[sku='+sku+']');
						eNewInput = eNewLine.find('input.inc');
						eNewInput.each(
							function(){
								fPrepWidgets( $(this) );
								$(this).trigger('update-widgets');
							}
						)
						fAddPop(eNewLine);
					}
				)
			}
			
			// remove any models that don't have any items in them
			fRemoveEmptyRows = function() {	
				$('div.catalog_line_item').each(
					function() {
						foo = $(this).find('table .itempop td');
						if (foo.length == 0) {
							$(this).remove();
						} 
					}
				);
			}
			
			// if we're updating the cart page, then do stuff
			eOldCartSidebar = $('#content div.cart_sidebar');
			eNewCartSidebar = $('#tempbox div.cart_sidebar');
			if ( eOldCartSidebar.length > 0 && eNewCartSidebar.length > 0) {
				fReplaceItemPops( $('#tempbox table.cart_temprows .itempop') )
				fRemoveEmptyRows();
				eOldCartSidebar.replaceWith(eNewCartSidebar);
				var foo = $('#content div.cart_sidebar .bb_corners');
				fBringAttention(foo);
				$('#content .cartup_checkout').replaceWith( $('#tempbox .cartup_checkout') );
			}
			
			// if we're updating the catalog page, then do stuff
			eOldRecentCart = $('#content div.recent_cart');
			eNewRecentCart = $('#tempbox div.recent_cart');
			if ( eOldRecentCart.length > 0 && eNewRecentCart.length > 0) {
				fReplaceItemPops( $('#tempbox table.catalog_temprows .itempop') );
				eOldRecentCart.replaceWith(eNewRecentCart);
				var foo = $('#content div.recent_cart .bb_corners');
				fBringAttention(foo);
				fPrepBiggerLink(eNewRecentCart);
				eNewRecentCart.find('.itempop').each(
					function(){
						fAddPop($(this));	
					}
				);
			}
			
			// clean up and get everything updated
			$('#tempbox').remove();
			fUpdateArrays();
			fUpdateSubmit();
			fUpdateSetZero();
			
		}
		
		function fPrepWidgets(e) {
			
			fIntSetter(e, 'update-widgets' );
			e.bind(
				'update-widgets', function() {
					fUpdateWidgets(e);
					fUpdateSubmit();
					fUpdateSetZero();
				}
			).bind(
				'click', function() {
					return false;
				}
			).siblings().bind(
			'click',function(){
					var ee = $(this);
					if (ee.hasClass('sub1')) {
						parseInt(e.val(),10) > 0 ? e.val(parseInt(e.val(),10) - 1) : false;
					} else if (ee.hasClass('add1')) {
						e.val(parseInt(e.val(),10) + 1);
					} else if (ee.hasClass('set0')) {
						e.val(0);
					} else if (ee.hasClass('reset')) {
						i = e.attr('original');
						e.val(i);
					}
					fUpdateWidgets(e);
					fUpdateSubmit();
					fUpdateSetZero();
					return false;
				}
			);
		}
		
		function fAddPop(e) {
			e.find('a:first').replaceWith('<p>'+e.find('a:first').html()+'</p>');
			e.bind(
				'click', function() {
					hideContent();
					fPopUpItem(e.attr('sku'));
					return false;
				}
			).hoverIntent(
				function() {
					e.stop().animate({backgroundColor: sHoverColor}, 150).css("cursor","pointer");
				}, function() {
					// stupid firefox bug makes background color kill bottom border, so must change style attribute
					e.stop().animate({backgroundColor: 'transparent'}, 300, "linear", function(){e.attr('style','background-color:transparent')});
				}
			);
		}
		
		function fCartupAjax(e) {
			$.post( "/item", e.serialize(), function(data) { fUpdateCatalog(data) }, 'html' );
		}
		
		function fBringAttention(e) {
			e.slowEach(
				150, function() {
					$(this).stop().animate({backgroundColor: sActiveColor}, 300).animate({backgroundColor: "#ffffff"}, 2500);
				}
			);
		}
		
		// ############ BEGIN CATALOG ROW ELEMENT HANDLING ####################################################################
		
		function fUpdateWidgets(e) {
		
			eDec = e.siblings('.sub1');
			eInc = e.siblings('.add1');
			eZero = e.siblings('.set0');
			eReset = e.siblings('.reset');
		
			iOrg = parseInt(e.attr("original"),10);
			iCur = parseInt(e.val(),10);
			iAva = parseInt(e.attr("max"),10);
		
			if (iCur == "0") {
				eDec.addClass('disabled');
				eZero.addClass('disabled');
			} else {
				eDec.removeClass('disabled');
				eZero.removeClass('disabled');
			}
			if (iOrg != iCur) {
				e.attr('changed','1');
				e.addClass('active');
				eReset.removeClass('disabled');
			} else {
				e.attr('changed','0');
				e.removeClass('active');
				eReset.addClass('disabled');
			}
			if (iCur > iAva) {
				e.addClass('mark')
			} else {
				e.removeClass('mark')
			}
		}
		
		// find if any items are in a changed state, and update submit button and reset button to reflect
		function fUpdateSubmit() {
			var iChangedItems = 0;
			aItemInputSet.each(
				function() {
					$(this).attr('changed') == "1" ? iChangedItems += 1 : false
				}
			)
			if (iChangedItems > 0) {
				s = iChangedItems > 1 ? "s" : "";
				$('.cartup_submit')
					.attr("disabled","")
					.removeClass('disabled')
					.unbind('click')
					.click(
						function(){
							$("form.cartup").submit();
							return false;
						}
					)
					.children('span.page_num')
					.html(""+iChangedItems+" Item"+s+" to Update</span>");
				$(".cartup_reset").removeClass('disabled');
				
			} else {
					$('.cartup_submit')
					.attr("disabled","disabled")
					.addClass('disabled')
					.unbind('click')
					.click(
						function(){
							return false;
						}
					)
					.children('span.page_num')
					.html("No Items to Update</span>");
				$(".cartup_reset").addClass('disabled');
			}
		}

		// supply an element, it will be kept in the viewport properly
		function fKeepPopInPlace(e) {
			
			var fWinHeight = $('#body-wrapper').height()
			var fPopHeight = $(e).height()
			var fNewOffset = getScrollHeight() > 120 ? 	getScrollHeight() - 90 : 30;
			
			fNewOffset = (fNewOffset + 170) > (fWinHeight - fPopHeight) ? fWinHeight - fPopHeight - 170 : fNewOffset
			
			e.css('top',fNewOffset+'px');
		}

		// provide a fixed page element, will put it in place and bind handler for window scrolling
		function fMakePopFixed(e) {
			fKeepPopInPlace(e)
			$(window).bind(
				'scroll', function() {
					fKeepPopInPlace(e);
				}
			);
		}
		
		// find if any items are more then zero, and update all-zero button to reflect
		function fUpdateSetZero() {
			var iNonZeroItems = false;
			aItemInputSet.each(
				function() {
					if (parseInt($(this).val(),10) > 0) {
						iNonZeroItems = true;
					}	
				}
			);
			iNonZeroItems == true ? $('.cartup_setzero').removeClass('disabled') : $('.cartup_setzero').addClass('disabled');
		}
		
		function fUpdateArrays() {
			aItemInputSet = $('span.inc input.inc')
		}
		
		var bAnyItems = "disabled";
		var aItemInputSet;
		
		// wrap widget elements around row inputs, bind handlers to all widget elements, set innital widget states
		$('input.inc').each(
			function() {
				e = $(this);
				fPrepWidgets(e);
				// if any element has a value, then set bAnyItems to true so set-zero widget element starts enabled
				parseInt(e.val(),10) > 0 ? bAnyItems = "" : false;
				// bind handler to text input element
				fIntSetter(e, 'update-widgets'  );
			}
		);
		
		// set the innitial state of the catalog element arrays
		fUpdateArrays();
		// get the zero-all button innitialized
		fUpdateSetZero();
		
		
		// ############ BEGIN CATALOG SUBMIT ELEMENT HANDLING ####################################################################
		
		// have form processes updates with ajax instead of conventional submit
		
		$("form.cartup").submit(
			function() {
				d = $(this).find('input.inc[changed=0]');
				d.attr('disabled','disabled');
				fCartupAjax($(this));
				d.removeAttr('disabled');
				return false;
			}
		);
		
		// when clicked, set all input elements to zero, update their widgets, then update submit and all-zero buttons
		$('.cartup_setzero').click(
			function() {
				aItemInputSet.each(
					function() {
						$(this).val(0);
						fUpdateWidgets($(this));
					}
				);
				$('.cartup_setzero').addClass('disabled');
				fUpdateSubmit();
				return false;
			}
		);
		
		// when clicked, set all input elements to starting value, update their widgets, and then udpate submit and set-zero buttons
		$('.cartup_reset').click(
			function() {
				aItemInputSet.each(
					function() {
						$(this).val($(this).attr('original'));
						fUpdateWidgets($(this));
					}
				);
				fUpdateSubmit();
				fUpdateSetZero();
				return false;
			}
		);
		
		// ############ BEGIN AJAX POPUP HANDLER/LAUNCHER ################################################################
		
		
		// creates pop up window, fetches url, and binds handlers to later remove popup elements
		fPopUpItem = function(sku) {
			$("#content").prepend("<div id='ajax_item'><a href='#' title='close this popup' style='position:absolute;top:-6px;right:-8px;z-index:120'><img src='/images/layout/icon_bigclose.png'/></a><div id='ajax_item_content'></div> <div class='bbb_tl'></div><div class='bbb_tr'></div><div class='bbb_bl'></div><div class='bbb_br'></div></div>");
			
			$('#ajax_item > a').click(
				function(){
					$("#hidecontent, #ajax_item").animate({opacity: 0},300, function(){ $(this).remove(); });
					return false;
				}
			)
			
			fMakePopFixed($('#ajax_item'));
			
			$('#ajax_item_content').load("/item/"+sku);
				
			$("#hidecontent").css("cursor","pointer");
			$("#hidecontent").click(
				function(){
					$("#hidecontent, #ajax_item").remove();
				}
			);
		};
		
		// bind popup handler to each itempop class object on page load
		$('.itempop').each(
			function(){
				fAddPop($(this));
			}
		);
		
		// ############ BEGIN AJAX POPUP #################################################################################
		
		
		// call function as callback when ajax item finishes loading
		fPopUpPrep = function() {
			
			// handle next / previous sku links
			$('a[sku]').bind(
				'click',function(){
					$("#ajax_item").remove();

					fPopUpItem( $(this).attr('sku') );
					return false;
				}
			)
			
			
			
			
			
			// set labeling to manual, set input focus, and mark active when manual label table cell clicked
			$('#manual_label_td').click(
				function(){
					$(this)
						.addClass('active')
						.removeClass('label');
					$('#auto_label_td')
						.removeClass('active')
						.addClass('label');
					$('#ajax_label_costbased').val('1');
					$('#ajax_label_manual').select();
				}
			);
			
			// set labeling to auto, set inptu focus, and mark active when cost based labeling table cell clicked
			$('#auto_label_td').click(
				function(){
					$(this)
						.addClass('active')
						.removeClass('label');
					$('#manual_label_td')
						.removeClass('active')
						.addClass('label');
					$('#ajax_label_costbased').val('0');
					$('#ajax_label_cost').select();
				}
			);
			
			// supply label price and base price, markup is returned
			function fCalcMargin(dPrice, dBase) {
				iMargin = ( (dPrice / dBase) * 100 ) - 100 ;
				iMargin = parseInt(iMargin);
				return iMargin;
			}
			
			// supply markup and base price, label price returned
			function fCalcPrice(iMargin, dBase) {
				dPrice = ( (iMargin + 100) / 100 ) * dBase ;
				dPrice = r2(dPrice);
				return dPrice;
			}
			
			// set the mark on labeling elements if current price is below wholesale wholesale price
			function fCheckBelowCost(dPrice, dBase) {
				if (dPrice < dBase) {
					$('#ajax_label_cost, #ajax_label_manual').addClass('mark');
				} else {
					$('#ajax_label_cost, #ajax_label_manual').removeClass('mark');
				}
			}
			
			// calculate and update margin when price is changed, called by trigger
			$('#ajax_label_manual').bind(
				"update-margin", function(){
					dBase = parseFloat($('#ajax_label_cost').attr('baseprice'));
					iMargin = fCalcMargin( parseFloat($(this).val()), dBase );
					!isNaN(iMargin) ? $('#ajax_label_cost').val(iMargin) : $('#ajax_label_cost').val("0");
					fCheckBelowCost( parseFloat($(this).val()), dBase );
				}
			);
			
			// calculate and update price when margin is changed, called by trigger
			$('#ajax_label_cost').bind(
				"update-price", function(){
					dBase = parseFloat($(this).attr('baseprice'));
					dPrice = fCalcPrice( parseInt($(this).val()), dBase );
					!isNaN(dPrice) ? $('#ajax_label_manual').val(dPrice) : $('#ajax_label_manual').val(dBase);
					fCheckBelowCost( parseFloat(dPrice), dBase );
				}
			);
			
			// add select, keyup, and blur event handlers for pricing elements
			fPriceSetter( $('#ajax_label_manual'),'update-margin');
			fIntSetter( $('#ajax_label_cost') ,'update-price');
			
			
			// set active cart quantity setting to manual when any manual table cell clicked
			$('.manual_cart_td').click(
				function(){
					$('.manual_cart_td')
						.addClass('active')
						.removeClass('label');
					$('#auto_cart_td')
						.removeClass('active')
						.addClass('label');
					$('#cartup_manual').val('1');
					$(this).find('input').focus();
				}
			);
			
			// set active cart quantity handling to automatic when auto table cell clicked
			$('#auto_cart_td').click(
				function(){
					$(this)
						.addClass('active')
						.removeClass('label');
					$('.manual_cart_td')
						.removeClass('active')
						.addClass('label');
					$('#cartup_manual').val('0');
					$(this).find('input').focus();
				}
			);
			
			// change color of label and cart update buttons when hovered over
			$("input.update")
				.height($('#auto_cart_td').height())
				.hover(
					function(){
						$(this).addClass('hover');
					},
					function(){
						$(this).removeClass('hover');
					}
			);
			
			// bind submit handler to form so posts are handled by ajax
			$("#ajax_item form.cartup").submit(
				function() {
					fCartupAjax($(this));
					$("#hidecontent, #ajax_item").remove();
					return false;
				}
			);
			
			// bind focus, keyup, and blur events to quantity boxes
			$('.manual_cart_td :text, #auto_cart_td :text').each(
				function(){
			 		fIntSetter( $(this) );
				}
			);
			
		};
		

	}
);