(function($){ //provide closure to protect namespace
	$.blockUI.defaults.css = {};
	$(document).ready(function(){

		var context = {
			isInit: true,
			categoryWasChosen: false,
			continueDuration: 300,
			fakePreloadingTime: 300,
			slideFade: 300,
			eventNs: 'oly',
			nsInvokers: [],
			maxShownWidths: 4,
			maxColours: 3,
			main: $('#main'),
			dataForm: $('form.slides'),
			mainData: {
				price: $('#price'),
				category: $('#category')
			},
			summary: $('#summary'),
			slides: {},
			category: null,
			confirmBox: $('#category_change_confirm'),
			loader: $('#loader'),
			breadCrumbSteps: null,
			price: 0,
			priceHolder: {
				total: $('#price-holder').find('li.total span'),
				quantity: $('#price-holder').find('li.quantity span'),
				unit: $('#price-holder').find('li.per-unit span')
			},
			validation: {
				rules: {
					base_colour: {
						required: true,
						minlength: 2
					},
					quantity: {
						required: true,
					    digits: true,
						minlength: 2
					},
					width_size: {
						required: true
					},
					print_type: {
						required: true
					},
					print_sides: {
						required: true
					},
					fittings: {
						required: true
					},
					cards: {
						required:  function(){
							return $('#insert_cards').is(':checked');
						}
					},
					insert_cards: {
						required:  false
					}
				},
				messages: {
					base_colour: {
						required: "Please specify your lanyards base colour",
						minlength: "Base colour should be longer then 2 characters"
					},
					width_size: {
						required: "Please specify your lanyards width"
					},
					print_type: {
						required: "Please specify your lanyards printing colours",
						minlength: "Quantity should be more then 9",
						digits: "Quantity value should be digits only"
					},
					quantity:{
						required: "Please specify quantity"
					},
					print_sides:{
						required: "Please specify number of sides for printing"
					},
					fittings:{
						required: "You must select at least one fitting"
					},
					cards: {
						required: "You must select a card holder in order to have insert cards"
					},
					insert_cards: {
						required: "You must select a card holder if you want to have insert cards"
					}
				}
			},
			init: function ()
			{
				context.slides = {
					slide1: $('#slide1'),
					slide2: $('#slide2'),
					slide3: $('#slide3'),
					slide4: $('#slide4'),
					slide5: $('#slide5')
				};
				var slides = context.slides;
				context.controls = {
					quantity : {
						widget: $('.slide').not('.clone').find(".quantity-slider" ),
						input: $('#quantity')
					},
					baseColour: $('#base_colour'),
					width : {
						widget: slides.slide2.find('div.size ul li'),
						input: $('select#width_size')
					},
					printing: {
						types: slides.slide2.find('div.colours div.type-picker'),
						colours: slides.slide2.find('div.colours div.colour-picking')
					},
					printingType : {
						widget: slides.slide2.find('div.colours ul.types li'),
						input: $('select#print_type')
					},
					sides : {
						widget: slides.slide2.find('div.print-sides ul li'),
						input: $('select#print_sides')
					},
					fittings : {
						widget: slides.slide3.find('ul.fittings li').not('.safety-clip, .additional'),
						input: $('select#fittings')
					},
					fittingsAdditional : {
						widget: slides.slide3.find('ul.fittings li.additional'),
						input: $('select#fittings_additional')
					},
					cards : {
						widget: slides.slide4.find('ul.cards li'),
						input: $('select#cards')
					},
					insertCards : {
						widget: slides.slide4.find('div.insert strong.choose'),
						input: $('input#insert_cards')
					},
					urgent : {
						widget: slides.slide5.find('div.urgent ul.input li'),
						input: $('select#urgent')
					}
				};
				var orderSlide = slides.slide5;
				context.review = {
					totalPrice : orderSlide.find('div.total dl dd li.total span.amount'),
					unitPrice : orderSlide.find('div.total dl dd li.unit span.amount'),
					name : orderSlide.find('div.general h3.name'),
					baseColour : orderSlide.find('div.general dd.base-colour'),
					width : orderSlide.find('div.general dd.width span.amount'),
					coloursContainer : orderSlide.find('div.general dd.colours'),
					colourNote : orderSlide.find('div.general strong.note'),
					sides : orderSlide.find('div.general dd.sides'),
					fittingsContainer : orderSlide.find('div.fittings ul.selection'),
					cardHolderContainer : orderSlide.find('div.card-holder ul.selection'),
					insertCards : orderSlide.find('div.card-inserts strong.value')
				};
				
				
				
			},
			
			preloader: function() {
				context.main.block({
					message: context.loader,
	            	blockMsgClass: "loader",
	            	centerX: false, 
//	            	centerY: false,
					overlayCSS: {
						backgroundColor: '#fff', 
						opacity:         0.6 
					}
				});
			},

			stopPreloading: function() {
				context.main.unblock();
			},

			start: function ()
			{
				/*
				 * Intial page select category
				 * The script syncs all animations and ensures no stuck elements
				 * in half way of the animation
				 * 
				 */
				context.review.colourNote.hide();
				context.validator = context.dataForm.validate($.extend({}, context.validation, {
					errorElement: 'p',
					errorContainer: $('div.error'),
					errorPlacement: function(error, element)
					{
						var $errorContainer = $('.slide:visible div.error'),
						$elementErrorContainer = $errorContainer.find(error);
						//init
						if ($elementErrorContainer.length==0) {
							$errorContainer.append(error);
						} else {
							// update error message
							$elementErrorContainer.find('label').replaceWith(error);
						}
					}
				}));
				
				
				var $categoryDescriptions = context.slides.slide1.find('ul#descriptions li'),
				$categoryLinks = $('section#sidebar ul#categories-nav li a'),
				$continueLinks = $categoryDescriptions.find('a'),
				$goBackButton = context.confirmBox.find('button.purple'),
				$continueButton = context.confirmBox.find('button.green');
				$continueLinks.hide();
				$continueLinks.css('visibility','visible');
				
				//center paragraph vertically
				$categoryDescriptions.each(function ()
				{
					var $this = $(this),
					$p = $this.find('p');
					$p.css('margin-top',($this.height()-$p.outerHeight())/2);
				})
//				"Next" buttons
				$continueButton.click(function(e) {
					e.preventDefault();
		            $.unblockUI();
		        }); 
				$goBackButton.click(function(e) {
					e.preventDefault();
		            $.unblockUI({ onUnblock: function(){
						context.chooseCategory(context.confirmBox.data('category'));
		            }});
		        });
				
//				Breadcrumbs
				var $breadCrumb = $('#steps-breadcrumbs'),
				$breadCrumbSteps = $breadCrumb.find('li');
				context.breadCrumbSteps = $breadCrumbSteps;
				
				$breadCrumbSteps.each(function () {
					var $this = $(this),
					$correspondingSlide = $('#'+$this.data('slide'));
					$this.click(function (e) {
						e.preventDefault();
						if (!$this.hasClass('completed-once')) {
							return
						}
						context.completeSlide($('.slide:visible'), $correspondingSlide);
					})
				});
				
				
				
				var continueDuration = context.continueDuration,
				isFirstClickOnCategory = true;
				
				//bind the events
				$categoryLinks.each(function ()
				{
					var $this = $(this),
					$thisCategory = $this.closest('li'),
					continueLinkClass = $thisCategory.clone().removeClass('first').attr('class'),
					$currentDescription = $categoryDescriptions.filter('.'+continueLinkClass),
					$continueLink = $currentDescription.find('a');
					
					var continueClick = function (e)
					{
						context.chooseCategory($thisCategory);
						e.preventDefault();
					}
					
					$continueLink.bind('click.' + context.eventNs, continueClick);
//					context.nsInvokers.push( $continueLink );
					var logoClick = function(e) {
						e.preventDefault();
						if (context.categoryWasChosen) {
							if (context.category.get(0)!=$thisCategory.get(0)) {
								context.confirmBox.data('category',$thisCategory);
					            $.blockUI({
					            	message: context.confirmBox,
					            	blockMsgClass: "go-back block-msg",
					            	 // styles for the overlay 
					                overlayCSS:  { 
					                    backgroundColor: '#5b1f58', 
					                    opacity:         0.64
					                }
					            }); 
							}
							return;
						}
						if ($currentDescription.is('.active:not(.returning)')) {
							return;
						}
						// activate curret category
						$thisCategory.siblings('li').removeClass('active');
						$thisCategory.addClass('active');
						var changeCategoryAnimation = function() {
							var duration = continueDuration;
							if ($currentDescription.hasClass('active')) {
								$currentDescription.dequeue().stop();
								$currentDescription.removeClass('returning');
								var startTime = $.data( this, 'continue.animation.startTime'),
								duration = $.now()-startTime;
							} else {
								$currentDescription.addClass('active');
							}
							$.data($currentDescription.get(0), 'continue.animation.startTime', $.now());
							$currentDescription.animate({ backgroundColor: '#f6daf5' }, duration, function(){
								$.data(this, 'continue.animation.endTime', $.now());
							});
							$continueLink.show('customSlide', {direction: 'right'}, duration);
						}
						// stop all descriptions that are becomming active and set endTime
						$categoryDescriptions.filter(':animated:not(.returning)').each(function ()
						{
							var $description = $(this);
							$description.dequeue().stop();
							$.data(this, 'continue.animation.endTime', $.now());
						});
						//stop and hide currently visible continueLinks
						
						$continueLinks.filter(':visible').dequeue().stop().hide('customSlide', {direction: 'right'}, continueDuration);

						//hide all that started being active 
						var $activeCategoryDescriptions = $categoryDescriptions.filter('.active:not(.returning)'),
						remainingAnimations = $.Deferred();
						$activeCategoryDescriptions.each(function (i)
						{
							var $description = $(this);
								var startTime = $.data( this, 'continue.animation.startTime'),
								continueDurationElapsed = $.data( this, 'continue.animation.endTime')-startTime,
								isLast = $activeCategoryDescriptions.length-1 == i;
								$.data(this, 'continue.animation.startTime', $.now());
								
								$description.addClass('returning');
								$description.animate( {
									backgroundColor : '#d9d9d9'
								}, {
									duration : continueDurationElapsed,
									complete : function ()
									{
										if (isLast) {
											remainingAnimations.resolve();
										}
										$.data(this, 'continue.animation.endTime', $.now());
										$(this).removeClass('active');
										$(this).removeClass('returning');
									}
								} );
							
						});
						if (isFirstClickOnCategory) {
							changeCategoryAnimation();
							isFirstClickOnCategory=false;
						} else {
//							$.when(remainingAnimations.promise()).then(changeCategoryAnimation);
							changeCategoryAnimation();
						}
					}
					
					$this.bind('click.'+context.eventNs, logoClick);
//					context.nsInvokers.push( $this );
				})
				if(typeof ascensorConfig != 'undefined') {
	                if (ascensorConfig['defaults']['categoryClass']) {
	                    $(window).load(function () {
	                        context.chooseCategory($('section#sidebar').find('ul#categories-nav').find('li.'+ascensorConfig['defaults']['categoryClass']));
	                    });
	
	                }
				}
			},
			
			toggleFixedFormHeight: function(isFixed) {
				if ($.type(isFixed)=='undefined') {
					isFixed=false;
				}
				if (isFixed) {
					context.dataForm.height(context.dataForm.height()+'px');
					context.dataForm.css('overflow','hidden');
				} else {
					context.dataForm.css('height','');
					context.dataForm.css('overflow','auto');
				}
			},
			
			getNextSlide: function($currentSlide) {
				return  $currentSlide.next('.slide');
			},
			
			reset: function ()
			{
				context.init();
				var controls = context.controls;
				helper.resetCheckboxControl( controls.insertCards.widget, controls.insertCards.input );
				helper.resetSelectControl( controls.width.widget, controls.width.input );
				helper.resetSelectControl( controls.printingType.widget, controls.printingType.input );
				helper.resetSelectControl( controls.sides.widget, controls.sides.input );
				helper.resetSelectControl( controls.fittings.widget, controls.fittings.input );
				helper.resetSelectControl( controls.fittingsAdditional.widget, controls.fittingsAdditional.input );
				helper.resetSelectControl( controls.cards.widget, controls.cards.input );
				helper.resetSelectControl( controls.urgent.widget, controls.urgent.input );

				helper.resetSlider( controls.quantity.widget, controls.quantity.input );
				
				$.each(context.nsInvokers, function(i, $invoker) {
					$invoker.unbind('.'+context.eventNs);
				});
			},
			
			refreshSlides: function ()
			{
				var $category = context.category,
				record = $category.data('record'),
				controls = context.controls,
				sideControlsOff = false,
				colourControllsOff = false;
				
				//errors
				$('.slide').not('.clone').find('div.error').each(function (e)
				{
					$(this).hide().html('');
				});
				
				//update lanyard description
				context.slides.slide2.find('.description').text(record['description']);
				
				//breadcrumbs
				context.breadCrumbSteps.removeClass('active completed-once');
				context.breadCrumbSteps.eq(0).addClass('active');
				
				//base colour
				controls.baseColour.val("");
				controls.baseColour.rules("remove");
				if (record['requires-base-colour']) {	
					controls.baseColour.rules("add",$.extend(
						{},
						context.validation.rules.base_colour,
						{messages: context.validation.messages.base_colour}
					));	
				}
				
				// show all widths opposite to only 3 of them as the commented code below does
				var availableWidths = record["available-widths"];
				controls.width.widget.removeClass('disabled default');
				controls.width.widget.each(function ()
				{
					var $this=$(this);
					if ($.inArray($this.data('corresponding-value'), availableWidths)<0) {
						$this.addClass('disabled');
					}
				})
				// mark default width control
				var defaultWidthValue = null;
				if(record['defaults'] && record['defaults']['width'] ) {
					defaultWidthValue = record['defaults']['width'];
				} else {
					defaultWidthValue = availableWidths[0];
				}
				controls.width.widget.filter('[data-corresponding-value='+defaultWidthValue+']').addClass('default');
				//show the available widths for this lanyard category				
				/*var	possibleWidths = controls.width.input.find('option').map(function() {
					if ($.trim($(this).attr('value'))!='') {
						  return parseInt($(this).attr('value'));
					}
				}).get(),
				availableWidths = record["available-widths"],
				numberOfDisabledToShow = context.maxShownWidths - availableWidths.length;
								

				controls.width.widget.hide();
				controls.width.widget.removeClass('disabled default');
				controls.width.widget.each(function ()
				{
					var $this=$(this);
					if ($.inArray($this.data('corresponding-value'), availableWidths)>=0) {
						$this.show();
					}
				})
				
				// calculate disabled widths that can be shown
				var 
				startIndex = possibleWidths.indexOf(availableWidths[0]),
				finishIndex = possibleWidths.indexOf(availableWidths[availableWidths.length-1]),
				showDisabled = function($li) {
					$li.addClass('disabled');
					$li.show();
				},
				fillToMax = function ()
				{
					if (numberOfDisabledToShow<=0) {
						return;
					}
					//fill widths from the left
					if (startIndex>0) {
						showDisabled(controls.width.widget.filter('.size'+possibleWidths[startIndex-1]+'mm'));
						numberOfDisabledToShow--;
						startIndex--;
						fillToMax();
						return
					}
					//fill widths from the right
					if (finishIndex+1<possibleWidths.length) {
						showDisabled(controls.width.widget.filter('.size'+possibleWidths[finishIndex+1]+'mm'));
						numberOfDisabledToShow--;
						finishIndex++;
						fillToMax();
						return
					}
				}
				fillToMax();*/
				
				
				
				// colours
				var $colours = context.slides.slide2.find('div.colours'),
				$vynilColours = controls.printingType.widget.filter('.vynil'),
				$fullColour = $vynilColours.siblings('li.fullcolour');

//				refresh to default state
				controls.printing.colours.hide();
				controls.printing.colours.find('li.colour').remove();
				controls.printing.types.show();

				controls.printingType.input.rules("remove");
				if (record['min-colours']=='off' && record['max-colours']=='off') {
					$colours.hide();
					colourControllsOff = true;
				} else {
					$colours.show();	
					controls.printingType.input.rules("add",$.extend(
						{},
						context.validation.rules.print_type,
						{messages: context.validation.messages.print_type}
					));		
				}
				
				// only checks whether is fullcolour or not
				$vynilColours.removeClass('disabled');
				$fullColour.removeClass('free');
				if (record['min-colours']=='fullcolour') {
					$vynilColours.addClass('disabled');
					$fullColour.addClass('free');
				}

				//sides
				var $sides = context.slides.slide2.find('div.print-sides');
				controls.sides.input.rules("remove");
				if (record['side-restriction']==0) {
					$sides.hide();
					sideControlsOff = true;
				} else {
					$sides.show();		
					controls.sides.input.rules("add", $.extend(
						{},
						context.validation.rules.print_sides,
						{messages: context.validation.messages.print_sides}
					));	
				}
				
				controls.sides.widget.removeClass('disabled default free');
				
				if (record['side-restriction']!=null) {
					var enabledSideExpr = '[data-corresponding-value='+record['side-restriction']+']',
					$disabledSide = controls.sides.widget.not(enabledSideExpr),
					$enabledSide = controls.sides.widget.filter(enabledSideExpr);
					$disabledSide.addClass('disabled');
					$enabledSide.addClass('default free');
				} else if(record['defaults'] && record['defaults']['sides'] ) {
					 controls.sides.widget.filter('[data-corresponding-value='+record['defaults']['sides']+']').addClass('default');;
				} else {
					 controls.sides.widget.filter('[data-corresponding-value=1]').addClass('default');;
				}

				//refresh fittings
				var hasDefaultFitting = refreshOneToMany(record, controls.fittings.widget, 'fitting-conditions-type', 'fittings-conditions');
				if (!hasDefaultFitting) {
					controls.fittings.widget.first().addClass('default');
				}

				//refresh additional fittings
				refreshOneToMany(record, controls.fittingsAdditional.widget, 'fitting-conditions-type', 'fittings-conditions');

				//refresh cards
				var hasDefaultCard = refreshOneToMany(record, controls.cards.widget, 'card-holder-conditions-type', 'card-holders-conditions');
				
				
				//hide or show urgent controls
				var $urgentControlDivision  = controls.urgent.widget.closest('div.urgent');
				$urgentControlDivision.hide();
				controls.urgent.widget.removeClass('default free');
				if (record['supports-urgent']) {
					controls.urgent.widget.last().addClass('default free');
					$urgentControlDivision.show();
				}
				
				//restyle .next button if required

				var $nextContainer = context.slides.slide2.find('div.next');
				$nextContainer.removeClass('fit');
				if (sideControlsOff || colourControllsOff) {
					$nextContainer.addClass('fit');
				}
			},

			
			refreshOrderSlide: function ()
			{
				var 
				record = context.category.data('record'),
				controls = context.controls,
				baseColour = controls.baseColour.val(),
				quantity = parseInt(controls.quantity.input.val()),
				width = parseInt(controls.width.input.val()),
				printingType = controls.printingType.input.val(),
				sides = controls.sides.input.val(),
				selectedCardholder = controls.cards.input.val(),
				shouldInsertCards = controls.insertCards.input.prop('checked'),
				review = context.review,
				summary = [],
				$summaryInput = context.summary
				;
				/*
					Colours: colourCount � concatanatedColoursred + yellow + green,
					Quantity: 1000
				*/
				//name 
				summary.push("Lanyard Type: " + record.name);
				review.name.text(context.category.text());
				
				var 
				fittingWidgets = controls.fittingsAdditional.widget.add(controls.fittings.widget),
				selectedFittings = controls.fittingsAdditional.input.val(),
				selectedMainFitting = controls.fittings.input.val(),
				toTextFittings = "Fittings: ";
				if ($.type(selectedFittings)!='array') {
					selectedFittings=[];
				}
				if ($.type(selectedMainFitting)!='undefined' && selectedMainFitting!=null) {
					selectedFittings.push(selectedMainFitting);
				}
				
				//fittings
				review.fittingsContainer.empty();
				var chosenFittingsFragment = document.createDocumentFragment();
				chosenFittingsFragment.appendChild(context.slides.slide3.find('ul.fittings li.safety-clip').clone().get(0) );
				if (selectedFittings.length>0) {
					$.each(selectedFittings, function (i, id) {
						var $fitting = fittingWidgets.filter('[data-corresponding-value='+id+']');
						toTextFittings = toTextFittings + $fitting.data('record').label;
						if (i < selectedFittings.length-1) {
							toTextFittings = toTextFittings + " + "
						}
						chosenFittingsFragment.appendChild( $fitting.clone().get(0) );
					});
				}
				review.fittingsContainer.append(chosenFittingsFragment);
				summary.push( toTextFittings);

				//card holder
				review.cardHolderContainer.empty();
				var $cardHolder = controls.cards.widget.filter('[data-corresponding-value='+selectedCardholder+']'),
				$cardRow = review.cardHolderContainer.closest('div.row.card');
				$cardRow.show();
				if ($cardHolder.length>0) {
					review.cardHolderContainer.append($cardHolder.clone().get(0));
					summary.push("Card Holder: " +$cardHolder.data('record').description);
				} else {
					$cardRow.hide();
				}
				
				
				
				//width
				review.width.text(width);
				summary.push("Width: " + width + 'mm');
				
				//base colour
				var $baseColourDt = review.baseColour.prev('dt');
				if (baseColour) {
					summary.push("Base Colour: " + baseColour);
					review.baseColour.show();
					$baseColourDt.show();
					review.baseColour.text(baseColour);
				} else {
					review.baseColour.hide();
					$baseColourDt.hide();
				}

				//sides
				var $sidesDt = review.sides.prev('dt');
				if (sides) {
					summary.push("Printed Sides: " + sides);
					review.sides.show();
					$sidesDt.show();
					review.sides.text(sides);
				} else {
					review.sides.hide();
					$sidesDt.hide();
				}
				
				//colours

				var $colourContainer = review.coloursContainer,
				$coloursDt = $colourContainer.prev('dt'),
				$fullColour = $colourContainer.find('span.full'),
				$colourList = $colourContainer.find('ul'),
				toStringColours = 'Colours: ';
				
				review.colourNote.hide();
				$fullColour.hide();
				$colourList.hide();
				if (printingType) {
					$coloursDt.show();
					$colourContainer.show();
					if (printingType=='fullcolour') {
						$fullColour.show();
						toStringColours = toStringColours + "Fullcolour"
					} else {
						var $customColours = controls.printing.colours.find('input'),
						hasEmptyInput = false,
						$colourListItems = $colourList.find('li');
						$colourListItems.find('span.value').removeClass('none');
						$colourListItems.hide();
						
						toStringColours = toStringColours + $customColours.length + ' - ';
						
						$customColours.each(function (i)
						{
							var $colour = $(this),
							$colourLi = $colourListItems.filter('.'+$colour.attr('id')),
							$colourValueHolder = $colourLi.find('span.value'),
							value = null,
							trimmedVal = $.trim($colour.val());
							
							if (trimmedVal =="" && !hasEmptyInput) {
								review.colourNote.show();
								hasEmptyInput=true;								
							}
							if (trimmedVal =="") {
								value = "No colour entered";
								$colourValueHolder.addClass('none');
							} else {
								value = $colour.val();
							}
							
							$colourLi.show();
							toStringColours = toStringColours + value;
							if (i < $customColours.length-1) {
								toStringColours = toStringColours + " + ";
							}
							$colourValueHolder.text(value);
						});
						$colourList.show();
					}
				} else {
					$coloursDt.hide();
					$colourContainer.hide();
				}
				summary.push(toStringColours);

				summary.push("Insert Cards: " + (shouldInsertCards ? "Yes" : 'No'));
				summary.push("Quantity: " + context.controls.quantity.input.val());
//				review.insertCards.removeClass('active');
//				if (shouldInsertCards) {
//					review.insertCards.addClass('active');
//					review.insertCards.find('span.text').text('Inludes inserts');
//				} else {
//					review.insertCards.find('span.text').text('No inserts included');
//				}
				
				$summaryInput.val(summary.join(', '));
			},
			loadDefaults: function () {
//				shortcuts
				var $category = context.category,
				record = $category.data('record'),
				controls = context.controls;
				

				//widths
				controls.width.widget.filter('.default').trigger('click.'+context.eventNs);
				
				//check if only fullcolour is supported
				if (record['min-colours']=='fullcolour') {
					var $fullColour = controls.printingType.widget.filter('.fullcolour');
					$fullColour.trigger('click.'+context.eventNs);
				}
				//sides
				controls.sides.widget.filter('.default').trigger('click.'+context.eventNs);
				//fittings
				controls.fittings.widget.filter('.default').trigger('click.'+context.eventNs);
				//cards
				controls.cards.widget.filter('.default').trigger('click.'+context.eventNs);
				//urgency
				controls.urgent.widget.filter('.default').trigger('click.'+context.eventNs);
			},
			
			chooseCategory: function($category) {
				if (!context.categoryWasChosen) {
					context.categoryWasChosen = true;
					context.main.addClass('in-category');
				}
				var $currentSlide = $('.slide:visible'),
//				switchContext = function ()
//				{
//					var record = $category.data('record');
//					var classesToRemoveFromMain = context.main.get(0).className.match(/category-[a-z\-]*/g, '');
//					if (classesToRemoveFromMain!=null) {
//						context.main.removeClass(classesToRemoveFromMain.join(' '));
//					}
//					context.main.addClass('category-'+$category.clone().removeClass('first active last').attr('class'));
//				},
				reform = function ()
				{
					context.category = $category;
					context.mainData.category.val(context.category.data('record').id);
					$category.siblings('li').removeClass('active');
					$category.addClass('active');
					context.confirmBox.find('strong.name').text(context.category.text());
					if (!context.isInit) {
						context.reset();
					} else {
						context.isInit=false;
					}
					context.refreshSlides();
					context.bind();
					context.loadDefaults();
				}
				context.preloader();
				// if the current slide is the second
				context.toggleFixedFormHeight( true );
				if ($currentSlide.get(0)==context.slides.slide1.get(0)) {
					reform();
					var hideProcessingCallback = function (show)
					{
						context.stopPreloading();
						show();
					}

					setTimeout(function() {
						context.switchSlide(context.slides.slide2, hideProcessingCallback);
					},context.fakePreloadingTime);
					return;
				}
				var $slideClone = $currentSlide.clone().addClass('clone');
				var $clonedData = $slideClone.find(':input');
				$clonedData.attr('id','');
				$clonedData.attr('name','');
				context.dataForm.append($slideClone);
//				uncomment the next line if the quantity skips before showing the next slide
//				$slideClone.find(".quantity-slider").slider('option','slide',function(){});
				setTimeout(function() {
					$currentSlide.hide();
					reform();
					var hideProcessingCallback = function (show)
					{
						$slideClone.remove();
						context.stopPreloading();
						show();
					}
					context.switchSlide(context.slides.slide2, hideProcessingCallback);
				}, context.fakePreloadingTime);
				
				// unbind all events
				// reset the slides
				// rebind all slides events
				// change first slide
				// what if on first slide ?
				// clone helper - clone the slide (DO NOT APPEND IT)
				// switch the slide having $originalFirstSlide
				// as toHide and the not yet apppended clone as
				// toShow. Pass a hideProcessingCallback (in remove the hidden element
				// this callback append the clone)
				
				// ...loading...
				// show first slide
				// change all other slides
				
			},
			
			switchSlide: function ($to, hideProcessingCallback)
			{
				context.toggleFixedFormHeight( true );
				context.breadCrumbSteps.removeClass('active');
				context.breadCrumbSteps.filter('.'+$to.attr('id')).addClass('active');
				context.recalculatePrice();

				context.dataForm.animateContentSwitch('.slide:visible', $to, context.slideFade, hideProcessingCallback, function() {
					context.toggleFixedFormHeight( false );
                    var $resizeContainer = (window.opera) ? (document.compatMode=="CSS1Compat"? $('html') : $('body')) : $('html,body')
                    $resizeContainer.animate({scrollTop: 300},300);
				});
			},
			
			completeSlide: function($slide, $goToSlide) {
				if ($slide.find(':input').valid()>0) {
					context.preloader();

					var hideProcessingCallback = function (show)
					{
						if ($goToSlide.get(0)==context.slides.slide5.get(0)) {
							context.refreshOrderSlide();
						}
						$.each(context.slides, function (i, $aSlide)
						{
							if ($goToSlide.get(0)==$aSlide.get(0)) {
								return false;
							}
							context.breadCrumbSteps.filter('.'+$aSlide.attr('id')).addClass('completed-once');
						})
						context.stopPreloading();
						show();
					};
					setTimeout(function() {
						context.switchSlide($goToSlide, hideProcessingCallback);
					}, context.fakePreloadingTime);
					
				}
				// validate fields on page
				// show message if not valid
				// if valid
				// add active class
				// add (go back and edit on breadcrumb) if it doesn't already exist
				
			},
			
			bind: function ()
			{
				
				var controls = context.controls,
                    $category = context.category,
				    record = $category.data('record');

				$.each(context.slides, function(key, $slide) {
					var $nextSlide = context.getNextSlide( $slide );
					if ($.type($nextSlide)=='undefined') {
						return;
					}
					var $nextButton = $slide.find('.next button'),
					$skipSlide = $slide.find('strong.skip');
					$nextButton.bind('click.'+context.eventNs, function (e)
					{
						e.preventDefault();
						context.completeSlide($slide, $nextSlide);
					});
					$skipSlide.bind('click.'+context.eventNs, function (e)
					{
						e.preventDefault();
						context.completeSlide($slide, context.slides[$skipSlide.data('toSlide')]);
					});
					context.nsInvokers.push( $nextButton );
					context.nsInvokers.push( $skipSlide );
				});
										

				

				/*********************************************
				 * Slide 2 - details
				 **********************************************/
				
				/*
				 * Base colour
				 * 
				 */
//				addLanyardImageSelect(
//					context.slides.slide2,
//					'div.base-colour ul.colors li',
//					'select#base_colour'
//				);
				
				
				/*
				 * Quantity Slider 
				 * 
				 */
				var $quantitySliders = $('.slide').not('.clone').find(".quantity-slider" ),
				$quantity = $('#quantity');

                var minQuantity = record['min-quantity']!=null ? record['min-quantity'] : 100;
				$quantitySliders.each(function ()
				{
					var $slider = $(this),
					$sliderAmount = $slider.siblings('span.tooltip.quantity').find('strong.amount');
					$slider.slider( {
						range: "min",
						value : 500,
						min : minQuantity,
						max : 10000,
						step : 50,
						slide:  function ( event, ui )
						{
							$quantity.val(ui.value);
							$quantity.trigger('change.'+context.eventNs, [$slider.get(0)])
							$sliderAmount.text(ui.value);
						} 
					} );
					$sliderAmount.text( $slider.slider( "value" ) );
					$quantity.bind('change.'+context.eventNs, function (e, invokingSlider)
					{
						if (invokingSlider=='undefined') {
							return;
						}
						context.priceHolder.quantity.text($quantity.val());
						context.recalculatePrice();
						$quantitySliders.each(function () {
							if (invokingSlider==this) {
								return;
							}
							var $aSlider = $(this);
							$aSlider.slider('value', $quantity.val());
							$aSlider.siblings('span.tooltip.quantity').find('strong.amount').text($quantity.val());
						});
					});
					context.nsInvokers.push( $quantity );
				});
				$quantity.val($quantitySliders.eq(0).slider( "value" ));
				context.priceHolder.quantity.text($quantity.val());

				
				/*
				 * Size
				 * 
				 */
				addLanyardImageSelect(
					context.slides.slide2,
					'div.size ul li',
					'select#width_size'
				);
				
				/*
				 * Colour priting type
				 * 
				 */
				addLanyardImageSelect(
					context.slides.slide2,
					'div.colours ul.types li',
					'select#print_type'
				);
				
				
				var
				$coloursContainer = context.slides.slide2.find('div.colours'),
				
				$typePicker = $coloursContainer.find('div.type-picker'),
				colorPickersActivator = $typePicker.find('ul.types li.vynil:not(.disabled)'),
				fullcolourActivator = $typePicker.find('ul.types li.fullcolour'),
				
				$colourPicking = $coloursContainer.find('div.colour-picking'),
				$cancelColourPicking = $colourPicking.find('li.cancel'),
				$addColourInput = $colourPicking.find('li.add'),
				$colourInputContainer =$colourPicking.find('ul.input'),
				
				$printColoursPreviewArea = $colourPicking.find('span.preview'),
				$printColoursPreviewText = $printColoursPreviewArea.find('.text')
				;
				
				colorPickersActivator.bind('click.'+context.eventNs, function (e)
				{
					$addColourInput.show();
					$typePicker.hide();
					$addColourInput.trigger('click.'+context.eventNs);
					$colourPicking.show();
				});
				context.nsInvokers.push( colorPickersActivator );
				
				$cancelColourPicking.bind('click.'+context.eventNs, function (e)
				{
					$colourPicking.hide();
					$colourPicking.find('li.colour').remove();
					fullcolourActivator.trigger('click.'+context.eventNs, [true]);
					$typePicker.show();
				});
				context.nsInvokers.push( $cancelColourPicking );
				
				
				$addColourInput.bind('click.'+context.eventNs, function (e)
				{
					var $this = $(this);
					if ($colourInputContainer.find('input').length==3) {
						$this.hide();
					}
					var inputId = 'colour'+($colourInputContainer.find('input').length+1),
					$newInputWidget = $('<li>', {"class": inputId + ' clearfix colour'}),
					$newInput = $('<input>',{
						id: inputId,
						value:'',
						type: 'text',
						name: 'colours[]'
					}),
					$deleteButton = $('<span>',{
						"class": "del",
						"click": function (event)
						{
							event.preventDefault();
							if ($colourInputContainer.find('input').length==1) {
								$cancelColourPicking.trigger('click.'+context.eventNs);
								return;
							}
							$newInputWidget.remove();
							if ($colourInputContainer.find('input').length<3) {
								$addColourInput.show();
							}
							$printColoursPreviewText.text($colourInputContainer.find('input').length+' colours');
							context.recalculatePrice();
						}
					});
					$newInputWidget.append($newInput);
					$newInputWidget.append($deleteButton);
					$newInputWidget.insertBefore($addColourInput);
					var numberOfInputs = $colourInputContainer.find('input').length;
					$printColoursPreviewText.text(numberOfInputs+' colours');
					if (numberOfInputs==3) {
						$this.hide();
					}
					context.recalculatePrice();
				});
				context.nsInvokers.push( $addColourInput );
				/*
				 * Color pickers
				 * 
				 */
//				var $printColoursPreviewArea = $colourPicking.find('span.preview'),
//				$printColoursPreviewText = $printColoursPreviewArea.find('.text'),
//				$inputs = $colourPicking.find('input');
//				addLanyardColorPicker($inputs, $('#colour1'), $printColoursPreviewText, 'c1');
//				addLanyardColorPicker($inputs, $('#colour2'), $printColoursPreviewText, 'c2');
//				addLanyardColorPicker($inputs, $('#colour3'), $printColoursPreviewText, 'c3');
				/*
				 * Print Sides
				 * 
				 */
				addLanyardImageSelect(
					context.slides.slide2,
					'div.print-sides ul li',
					'select#print_sides'
				);
				

				/*********************************************
				 * Slide 3 - fittings
				 **********************************************/
				var $slide3 = context.slides.slide3;
				var $allFittings = $slide3.find('.fittings li');
				$allFittings.each(function ()
				{
					var $aFitting = $(this), altText = $aFitting.find('img').attr('alt');
					$aFitting.append($('<h3>').append(altText));
				});
				addLanyardImageSelect(
					$slide3,
					controls.fittings.widget,
					'select#fittings'
				);
				addLanyardImageSelect(
					$slide3,
					controls.fittingsAdditional.widget,
					'select#fittings_additional'
				);
				

				/*********************************************
				 * Slide 4 - cards
				 **********************************************/
				var $slide4 = context.slides.slide4;
				var $cards = $slide4.find('.cards li');
				$cards.each(function ()
				{
					var $aCard = $(this), altText = $aCard.find('img').attr('alt');
					$aCard.append($('<h3>').append(altText));
				});
				addLanyardImageSelect(
					$slide4,
					'ul.cards li',
					'select#cards'
				);
				addLanyardImageCheckbox($slide4, 'div.insert strong.choose', 'input#insert_cards');
				

				/*********************************************
				 * Slide 5 - review
				 **********************************************/
				var $slide5 = context.slides.slide5;
				var links = [ {
					link: $slide5.find('div.general strong.edit'),
					slide: context.slides.slide2
				},{
					link: $slide5.find('div.fittings strong.edit'),
					slide: context.slides.slide3
				},{
					link: $slide5.find('div.card-holder strong.edit'),
					slide: context.slides.slide4
				},{
					link: $slide5.find('div.card-inserts strong.edit'),
					slide: context.slides.slide4
				}
				];

				addLanyardImageCheckbox($slide5, 'div.card-inserts strong.value', 'input#insert_cards');
				addLanyardImageSelect(
					$slide5,
					'div.urgent ul.input li',
					'select#urgent'
				);
				$.each(links, function (i, goToInfo)
				{
					goToInfo.link.bind('click.'+context.eventNs, function (e)
					{
						context.completeSlide($('.slide:visible'), goToInfo.slide);
					});
	
					context.nsInvokers.push(goToInfo.link)
				});
				
				
				
				
				
				
			},
			recalculatePrice: function ()
			{
				var
				record = context.category.data('record'),
				quantityBasedPriceBands = record['quantity-bands'].slice(),
                priceBand = null,
				baseUnitPrice = 0,
				unitPrice = 0,
				totalPrice = 0,
				controls = context.controls,
				quantity = parseInt(controls.quantity.input.val()),
				width = parseInt(controls.width.input.val()),
				printingType = controls.printingType.input.val(),
				sides = parseInt(controls.sides.input.val()),
				selectedFitting = controls.fittings.input.val(),
				selectedAdditionalFittings = controls.fittingsAdditional.input.val(),
				selectedCardholder = controls.cards.input.val(),
				shouldInsertCards = controls.insertCards.input.prop('checked'),
				urgency = controls.urgent.input.val()
				;
				
//				console.log('quantity', quantity);
//				console.log('width', width);
//				console.log('printingType', printingType);
//				console.log('colourNumber', context.slides.slide2.find('div.colours').find('div.colour-picking').find('input').length);
//				console.log('sides', sides );
//				console.log('selectedFittings', selectedFittings);
//				console.log('selectedCardholder', selectedCardholder);
//				console.log('selectedCardholder', selectedCardholder);
//				console.log('shouldInsertCards', shouldInsertCards);
				
				// get the quantity price band for the current order
				quantityBasedPriceBands.reverse();
				$.each(quantityBasedPriceBands, function (i,start)
				{
					if (quantity>=start) {
						priceBand = start;
						return false;
					}
				});
				if (priceBand==null) {
					priceBand = quantityBasedPriceBands.reverse()[0];
				}
				var priceRange = record['price-ranges'][priceBand.toString()];
				
				//base price is the price for the smalles available width
				baseUnitPrice = parseFloat(priceRange['widths'][record["available-widths"][0]]);
				
				//upgradable fittings added price
				var fittingPrice = 0;
				if ($.type(selectedFitting)!='undefined' && selectedFitting!=null  && selectedFitting!='') {
					var $fitting = controls.fittings.widget.filter('[data-corresponding-value='+selectedFitting+']'),
					fittingRecord =$fitting.data('record'),
					fittingPriceBand = helper.getFirstEqualOrGreaterThen(fittingRecord['quantity-bands'], priceBand) ,
					isFree = $fitting.hasClass('free');
					if ($.type(fittingRecord['price-ranges'])!='undefined' && !isFree) {
						fittingPrice = fittingPrice + parseFloat(fittingRecord['price-ranges'][fittingPriceBand.toString()]['added-price']);
					}
				}

				//additional fittings added price
				var additionalFittingsPrice = 0;
				if ($.type(selectedAdditionalFittings)!='undefined' && selectedAdditionalFittings!=null && selectedAdditionalFittings.length && selectedAdditionalFittings.length>0) {
					$.each(selectedAdditionalFittings, function (i, id) {
						var $additionalFitting = controls.fittingsAdditional.widget.filter('[data-corresponding-value='+id+']'),
						fittingRecord =$additionalFitting.data('record'),
						fittingPriceBand = helper.getFirstEqualOrGreaterThen(fittingRecord['quantity-bands'], priceBand) ,
						isFree = $additionalFitting.hasClass('free');
						if ($.type(fittingRecord['price-ranges'])!='undefined' && !isFree) {
							additionalFittingsPrice = additionalFittingsPrice + parseFloat(fittingRecord['price-ranges'][fittingPriceBand.toString()]['added-price']);
						}
					});
				}
				
				//card holder added price
				var cardHolderPrice = 0;
				if ($.type(selectedCardholder)!='undefined' && selectedCardholder!=null && selectedCardholder!='') {
					var $cardHolder = controls.cards.widget.filter('[data-corresponding-value='+selectedCardholder+']'),
					cardHolderRecord =$cardHolder.data('record'),
					cardHolderPriceBand = helper.getFirstEqualOrGreaterThen(cardHolderRecord['quantity-bands'], priceBand) ,
					isFree = $cardHolder.hasClass('free');
					if (!$.type(cardHolderRecord['price-ranges'])!='undefined' && !isFree) {
						cardHolderPrice = cardHolderPrice + parseFloat(cardHolderRecord['price-ranges'][cardHolderPriceBand.toString()]['added-price']);
					}
				}
				
				
				//width
				var addedWidthPrice = 0;
				if (width != record["available-widths"][0]) {
					addedWidthPrice = parseFloat(priceRange['widths'][width]);
				}
				
				//sides
				var addedSidePrice = 0;
				if (sides==2 && priceRange['both-sides']!=null && !controls.sides.widget.filter('[data-corresponding-value=2]').hasClass('free')) {
					addedSidePrice = parseFloat(priceRange['both-sides']);
				}
				
				//colours
				var additionalColourPrice = 0,
				hasDefinedColourPrice = $.type(priceRange['each-colour'])!='undefined' && priceRange['each-colour']!=null;
				if (printingType!="") {
					if (printingType=='fullcolour') {
						var $control = controls.printingType.widget.filter('.fullcolour');
						if (!$control.hasClass('free') && hasDefinedColourPrice) {
							additionalColourPrice = 4 * parseFloat(priceRange['each-colour']);
						}
					} else if (hasDefinedColourPrice) {
						var $colourInputs = context.slides.slide2.find('div.colours').find('div.colour-picking').find('input');
                        if ($colourInputs.length>=2) {
                            additionalColourPrice = ($colourInputs.length-1) * parseFloat(priceRange['each-colour']);
                        }
					}
				}
				
				
				// pre cut card inserts
				var additionalPreCutInsertsPrice = 0;
				if (shouldInsertCards) {
					additionalPreCutInsertsPrice = parseFloat(controls.insertCards.widget.data('prices')[priceBand.toString()]);
				}
				
				// pre cut card inserts
				var addedExtraQuickUrgency = 0;
				if (urgency && !controls.urgent.widget.filter('[data-corresponding-value='+urgency+']').hasClass('free')) {
					addedExtraQuickUrgency = parseFloat(priceRange['extra-quick']);
				}

				unitPrice = baseUnitPrice + addedWidthPrice + additionalColourPrice + addedSidePrice + fittingPrice + additionalFittingsPrice + cardHolderPrice + addedExtraQuickUrgency;
				totalPrice = (unitPrice * quantity) + additionalPreCutInsertsPrice;
				
//				var fixedPoints = totalPrice>1000 ? 1 : 2;

				context.mainData.price.val(totalPrice);
				var fixedPoints = 2;
				context.priceHolder.total.text(totalPrice.toFixed(fixedPoints));
				context.priceHolder.unit.text(unitPrice.toFixed(2));
				
				context.review.totalPrice.text(totalPrice.toFixed(fixedPoints));
				context.review.unitPrice.text(unitPrice.toFixed(2));
			}
		};


		/*********************************************
		 * START
		 **********************************************/
		
		//prevent the height of form container from collapsing on content change 
		context.dataForm.height(context.dataForm.height()+'px');
		context.dataForm.css('overflow','hidden');
		
		//prevent the height of form container from collapsing on content change 
		context.init();
		context.start();
		



		/*********************************************
		 * PROJECT HELPER FUNCTIONS
		 **********************************************/
		
		
		/*
		 * Add colour picker to input element and preview the colour to .swatch
		 * sibling
		 * 
		 */
		function addLanyardColorPicker($inputs, $input, $previewLabel, previewColourClass) {
			var $swatch = $input.siblings('.swatch');
			$input.ColorPicker({
				onChange: function (hsb, hex, rgb) {
					$input.val(hex);
					$input.trigger('change');
				}
			 });
			
			// reset swatch if no colour
			$input.bind('change.'+context.eventNs, function ()
			{
				var inputVal = $input.val();
				if (inputVal=='') {
					$swatch.css('background','');
					if (!$swatch.hasClass('none')) {
						$swatch.addClass('none');
					}
				} else {
					if ($swatch.hasClass('none')) {
						$swatch.removeClass('none');
					}
					$swatch.css('background', '#' + inputVal);
				}
			});
			context.nsInvokers.push( $input );
			
			// update preview text and preview colours
			var $previewColour = $('<span>', {"class": 'color-swatch '+previewColourClass}).hide();
			var $resetColour = $('<span>', {"class": 'del '});
			$previewLabel.parent().append($previewColour);
			$input.parent().append($resetColour);
			
			$input.bind('change.'+context.eventNs, function ()
			{
				var inputVal = $input.val();
				if (inputVal=='') {
					$previewColour.hide();
				} else {
					$previewColour.show();
					$previewColour.css('background', '#' + inputVal);
				}
				var count = 3-$inputs.filter('[value=""]').length;
				if (count==0) {
					$previewLabel.text('');
				} else {
					$previewLabel.text(count + ' colours');
				}
			});
			$resetColour.bind('click.'+context.eventNs, function ()
			{
				$input.val('');
				$input.trigger('change');
			});
			context.nsInvokers.push( $resetColour );
			
			//check for initial values (usually when page was already visited values remain filled)
			var inputVal = $input.val();
			if (inputVal.length==6) {
				$input.trigger('change');
				$input.ColorPickerSetColor(inputVal);
				$swatch.css('background', '#' + inputVal);
			}
		}
		
		/*
		 * Add select controlled by clicking on images
		 * 
		 */
		function addLanyardImageSelect($slide, imageControls, selectSelector, extractValueFromAttr) {
			var $imageControls = $.type(imageControls) == 'string' ? $slide.find(imageControls) : imageControls,
			$imageControlSelect = context.dataForm.find(selectSelector);
			$imageControls = $imageControls.not('.disabled')
			
			$imageControls.each(function ()
			{
				var $imageControl = $(this),
				optionValue = $imageControl.attr('data-corresponding-value');
				if ($.isFunction(extractValueFromAttr)) {
					optionValue = extractValueFromAttr(optionValue);
				}
				var $option = $imageControlSelect.find("option[value='" + optionValue + "']");
				$imageControl.data('storage',$option);
			});
			var imageControlEvents = {
				click: function (e)
				{
					var $imageControl = $(this), $option = $imageControl.data('storage');
					if (!$imageControlSelect.prop('multiple') && !$imageControl.hasClass('active')) {
						$imageControls.removeClass('active');
						$option.siblings('option').removeAttr('selected');
					}
					if (!$imageControl.hasClass('active')) {
						$imageControl.addClass('active');
						$option.attr('selected', true);
						$imageControlSelect.trigger('change');
					} else {
						if($imageControl.hasClass('constant')){
							return;
						}
						if($imageControlSelect.prop('multiple') || $imageControlSelect.hasClass('unselectable')){
							$imageControl.removeClass('active');
							$imageControlSelect.trigger('change');
							$option.removeAttr('selected');
						}
					}
					if ($slide.is(':visible')) {
						$imageControlSelect.valid();
						context.recalculatePrice();
					}
				}
			}
			$imageControls.bind('click.'+context.eventNs, imageControlEvents.click);
			context.nsInvokers.push( $imageControls );
		}
		
		/*
		 * Add select controlled by clicking on images
		 * 
		 */
		function addLanyardImageCheckbox($slide, imageControlSelector, inputSelector) {
			var $imageControl = $slide.find(imageControlSelector),
			$imageControlInput = context.dataForm.find(inputSelector);
			$imageControl.data('storage',$imageControlInput);
			var imageControlEvents = {
				click: function (e)
				{
					if (!$imageControl.hasClass('active')) {
						$imageControl.addClass('active');
						$imageControlInput.attr('checked', true);
					} else {
						$imageControl.removeClass('active');
						$imageControlInput.removeAttr('checked');
					}
					$imageControlInput.trigger('change.'+context.eventNs);

					if ($slide.is(':visible')) {
						$imageControlInput.valid();
						context.recalculatePrice();
					}
					
				}
			}
			$imageControl.bind('click.'+context.eventNs, imageControlEvents.click);
			$imageControlInput.bind('change.'+context.eventNs, function (e)
			{
				if ($(this).prop('checked')) {
					$imageControl.addClass('active');
				} else {
					$imageControl.removeClass('active')
				}
				if ($slide.is(':visible')) {
					context.recalculatePrice();
				}
			});
			context.nsInvokers.push( $imageControl );
			context.nsInvokers.push( $imageControlInput );
		}
		
		/*
		 * Add select controlled by clicking on images
		 * 
		 */
		function refreshOneToMany(record, $collection, relationTypeMappedBy, conditionsMappedBy) {
			var $disabled = $collection, hasCustomDefault = false;
			$disabled.removeClass('free default constant');
			if (record[relationTypeMappedBy]=='include') {
				$disabled.addClass('disabled');
				$.each(record[conditionsMappedBy],function (id, conditions){
					var $fitting = $disabled.filter('[data-corresponding-value='+id+']');
					
					$fitting.removeClass('disabled');
					if (conditions['is-selected']) {
						$fitting.addClass('default');
						if (conditions['is-included-in-price']) {
							$fitting.addClass('free');
						}
						if (conditions['is-unselectable']) {
							$fitting.addClass('constant');
						}
					}
				});
			} else {
				$disabled.removeClass('disabled');
			} 
			
			if (record[relationTypeMappedBy]=='exclude') {
				$.each(record[conditionsMappedBy],function (id, conditions) {
					$disabledFittings.filter('[data-corresponding-value='+id+']').addClass('disabled');
				});
			}
			return hasCustomDefault;
		}

		/*********************************************
		 * GENERAL HELPER FUNCTIONS
		 **********************************************/
		
		var helper =  {
			getFirstEqualOrGreaterThen: function(array, against) {
				var first = null;
				$.each(array, function (i, val)
				{
					if (val>=against) {
						first = val;
						return false;
					}
				})
				return first;
			},
			resetSelectControl: function ($widget, $input)
			{
				$widget.removeClass('active');
                if ($.browser.msie && $.browser.version<8) {
                    $input.find('option').attr('selected','false');
                    $input.attr('selectedIndex', '-1');
                } else {
                    $input.find('option').removeAttr('selected');
                }

			},
			resetCheckboxControl: function ($widget, $input)
			{
				$widget.removeClass('active');
				$input.removeAttr('checked');
			},
			resetSlider: function ($widget, $input)
			{
				var destroySlider = function (container)
				{
					container.slider('destroy');
				}
				
				if ($widget.length>1) {
					$widget.each(function ()
					{
						destroySlider($(this));
					})
				} else {
					destroySlider($widget);
				}
				$input.val('');
			}
		}

		//mailto if contact for account is clicked
		$('#account-button').click(function(event){
			event.stopPropagation();
			event.preventDefault();
			var mailtoStr = 'mailto:orders@onlylanyards.co.uk';
				mailtoStr  += '?subject=New Account Signup';
				mailtoStr  += '&body=' + $("input[name='summary']").val();
			window.location = mailtoStr;
		});

		//same details
		$('#same_details').change(function(){
			if( $(this).is(':checked') ){
				$('#delivery-fields li.hideable').hide();
			}
			else {
				$('#delivery-fields li.hideable').show();
			}
			billingShippingSame(); //tansfer billing input values to delivery inputs
		})
		//trigger change on page load
		.trigger('change');

		//billing shipping same when submit form (if ticked), transfer values
		$('#checkout-form').submit(function(){
			if( $('#billingdeliverysame').is(':checked') ){
				billingShippingSame();
			}
		});

		//terms button
		$('#pay-now').hide();
		$('#agreement').change(function(){
			if( $(this).is(':checked') ){
				$('#pay-now').show();
			}
			else {
				$('#pay-now').hide();
			}
		});

		//update totals labels when delivery selected
		$('#delivery_option').change(function(){
			var val = this.value;
			if(val == ''){
				var deliveryPrice = 0.00,
					deliveryVat = 0.00,
					deliveryPriceLabel = "0.00";
			}
			else {
				var deliveryPrice = parseFloat( $("input[name='delivery_opt_" + val + "_price']").val() ),
					deliveryVat = parseFloat( $("input[name='delivery_opt_" + val + "_vat']").val() ),
					deliveryPriceLabel = deliveryPrice.toFixed(2);
			}

			var totalVat = parseFloat( $("input[name='lanyard_vat']").val() ),
				grandTotal = parseFloat( $("input[name='lanyard_total']").val() );

			$('#delivery-price-label').html(deliveryPriceLabel);
			$('#total-vat-label').html( (totalVat + deliveryVat).toFixed(2) );
			$('#grand-total-label').html( (grandTotal + deliveryPrice).toFixed(2) );

		})
		.trigger('change'); //trigger onload

		
		$('#checkout-form').submit(function(){
			billingShippingSame();
		});
		
		//validate checkout form
		$('#checkout-form').validate({
			rules: {
				billingfirstname: {
					required: true
				},
				billinglastname: {
					required: true
				},
				billingaddress1: {
					required: true
				},
				billingcity: {
					required: true
				},
				billingcounty: {
					required: true
				},
				billingpostcode: {
					required: true
				},
				billingcountry: {
					required: true
				},
				billingemailaddress: {
					required: true,
					email: true
				},
				billingtelephone: {
					required: true
				},
				deliveryfirstname: {
					required: function(){
						return ($('#same_details').is(':checked')) ? false : true;
					}
				},
				deliverylastname: {
					required: function(){
						return ($('#same_details').is(':checked')) ? false : true;
					}
				},
				deliveryaddress1: {
					required: function(){
						return ($('#same_details').is(':checked')) ? false : true;
					}
				},
				deliverycity: {
					required: function(){
						return ($('#same_details').is(':checked')) ? false : true;
					}
				},
				deliverycounty: {
					required: function(){
						return ($('#same_details').is(':checked')) ? false : true;
					}
				},
				deliverypostcode: {
					required: function(){
						return ($('#same_details').is(':checked')) ? false : true;
					}
				},
				deliverycountry: {
					required: function(){
						return ($('#same_details').is(':checked')) ? false : true;
					}
				},
				deliverytelephone: {
					required: function(){
						return ($('#same_details').is(':checked')) ? false : true;
					}
				},
				delivery : {
					required: true
				}
			}
		});



	});




})(jQuery);

//transfer billing details input values to delivery details inputs
function billingShippingSame()
{
	var billingdetails = $('#billing-details :input');
	billingdetails.each(function(){
		var val = this.value,
			name = this.name.replace('billing','delivery');
		$("[name='" + name + "']").val(val);
	});
}
