	$(document).ready(function()
	{
		//hide the forum link if the facebook div is found
		if ($('#viewFbTnCs').length > 0)
		{
			$('.productDiscussion').hide();
			$('#viewForums').bind('click', function(e) {
				e.preventDefault();
				$('.productDiscussion').slideToggle('slow');
			});

			$('#fbTnCs').hide();
			$('#viewFbTnCs').bind('click', function(e) {
				e.preventDefault();
				$('#fbTnCs').slideToggle('slow');
			});

		}

		// bundles
		$.fn.openBundleInfo = function()
		{
			$(this)
				.removeClass('closed')
				.addClass('open')
				.find('.toggle')
					.addClass('close')
					.html('Hide bundle details');

			$(this)
				.find('.bundleInfoContent')
				.stop(true, true)
				.slideDown();

			return false;
		}

		$.fn.closeBundleInfo = function(forceQuick)
		{
			if (forceQuick)
			{
				$(this)
					.find('.bundleInfoContent')
						.stop(true, true)
						.hide();
			}
			else
			{
				$(this)
					.find('.bundleInfoContent')
						.stop(true, true)
						.slideUp();
			}

			$(this)
				.removeClass('open')
				.addClass('closed')
				.find('.toggle')
					.removeClass('close')
					.html('Show bundle details');

			return false;
		}

		$('#bundlesContainer').find('.bundleInfo').each(function()
		{
			$(this).closeBundleInfo(true);
		});

		$('#bundlesContainer').find('.bundleInfo .toggle').click(function(e)
		{
			e.preventDefault();

			var bundleInfo = $(this).parent();

			if (bundleInfo.hasClass('closed'))
			{
				bundleInfo.openBundleInfo();
			}
			else
			{
				bundleInfo.closeBundleInfo(false);
			}

			return false;
		});

		function overlayClose()
		{
			var overlay = $('#overlayContainer');

			if (overlay)
			{
				overlay
					.fadeOut('fast')
					.html('');
			}
		}

		function overlayOpen()
		{
			var overlay = $('#overlayContainer');

			if (overlay)
			{
				overlay
					.append('<div id="overlayClose">')
					.fadeIn('slow');

				$('#overlayClose')
					.attr('title', 'Click to close')
					.bind('click', function(e)
					{
						overlayClose();
					});
			}
		}

		function scrollFromTop(offset)
		{
			$('html:not(:animated),body:not(:animated)')
				.animate({scrollTop: offset}, 500);
		}

		function openTab(hashName)
		{
			$('ul.tabs li')
				.removeClass('active');

			$('.tab_content')
				.hide();

			$('#' + hashName + '-tab-li')
				.addClass('active')
				.show();

			$('#' + hashName)
				.show();
		}

		// Tab click events
		$('ul.tabs').find('li').click(function(e)
		{
			e.preventDefault();

			$('ul.tabs')
				.find('li')
				.removeClass('active');

			$(this)
				.addClass('active');

			$('.tab_content')
				.hide();

			var activeTab =
				$(this)
					.find('a')
					.attr('href');

			$(activeTab)
				.fadeIn();

			return false;
		});

		// reset all tabs
		$('ul.tabs')
			.find('li')
			.removeClass('active');

		$('.tab_content')
			.hide();

		// Determine the initially selected tab
		if (isOutOfStock() || isDiscon())
		{
			openTab('alternatives');
		}
		else
		{
			var hash       = window.location.hash;
			var bundleHash = '';

			// special offers hash extension
			if (hash.substring(0,16) == '#special-offers-')
			{
				bundleHash = hash;
				hash       = '#special-offers';
			}

			if (hash.length > 0 && $(hash + '.tab_content').length > 0)
			{
				if (bundleHash != '')
				{
					openTab('special-offers');

					var bundleAnchor = $(bundleHash);

					if (bundleAnchor.length > 0)
					{
						scrollFromTop(bundleAnchor.offset().top);

						bundleAnchor
							.parent()
							.find('.bundleInfo')
								.openBundleInfo();
					}
				}
				else
				{
					openTab(hash.substring(1, hash.length));
				}
			}
			else
			{
				openTab('overview');
			}
		}

		if (bundleLink())
		{
			$('#sideBundleBlockViewAll').click(function(e)
			{
				e.preventDefault();

				openTab('special-offers');
				scrollFromTop($(window.location.hash + '-tab-li').offset().top);

				return false;
			});

			$('#sideBundleBox').find('.bundleLink').click(function(e)
			{
				e.preventDefault();

				var bundleAnchor = $($(this).attr('href'));

				openTab('special-offers');

				scrollFromTop(bundleAnchor.offset().top);

				bundleAnchor
					.parent()
					.find('.bundleInfo')
						.openBundleInfo();

				return false;
			});
		}

		/*
		 * Overlay container
		 */
		var overlay = $('#overlayContainer');

		/*
		 * FLASH ROTATOR
		 */
		var intRotatorProductId = $('a#playFlashRotator').attr('product');

		if (overlay && intRotatorProductId)
		{
			$('a#playFlashRotator').bind('click', function(e)
			{
				e.preventDefault();

				strRotatorContent = '<div id="flashRotatorContainer">'
				                  +   '<div id="flashRotatorContent"></div>'
				                  + '</div>';

				// gotta love this..
				strRotatorContent += '<div id="flashRotatorMask">'
				                   +   '<div id="maskTop"></div>'
				                   +   '<div id="maskLeft"></div>'
				                   +   '<div id="maskRight"></div>'
				                   +   '<div id="maskBottom"></div>'
				                   + '</div>';

				overlay.html(strRotatorContent);

				var so = new SWFObject('http://image.ebuyer.com/UK/ProductViewer-live.swf', 'rotator', '700', '450', '9', '#FFFFFF');
				so.addParam('wmode', 'transparent');
				so.addVariable('id', intRotatorProductId);
				so.addVariable('type', 'rotator');
				so.addParam('allowScriptAccess', 'always');
				so.write('flashRotatorContent');

				overlayOpen();

				return false;
			});

			$('#playFlashRotator').attr('href', '#');
		}

		/*
		 * Zoom help
		 */
		var zoomHelp = $('#zoomHelp');

		if (zoomHelp)
		{
			zoomHelp.addClass('zoomHelp');
		}

		/*
		 * Out of stock
		 */
		var outOfStockForm = $('#stockNotificationForm');

		if (outOfStockForm)
		{
			var oosEmailField = $("#stockNotificationForm input[name='notificationRecipient']");

			var strDefaultText = 'Enter your email..';
			oosEmailField.val(strDefaultText);

			oosEmailField.focus(function()
			{
				if ($(this).val() == strDefaultText)
				{
					$(this).val('');
				}
			});

			oosEmailField.blur(function()
			{
				if (!$(this).val())
				{
					$(this).val(strDefaultText);
				}
			});

			function handleFormResponse(objJson)
			{
				if (objJson.backInStockNotification.result == 'Added' || objJson.backInStockNotification.result == 'Toggled')
				{
					setOosFormSuccess('Thank you for your interest! We will let you know when we have more of this product back in stock.');
				}
				else if (objJson.backInStockNotification.result == 'Exists')
				{
					setOosFormSuccess('You are already signed up for an email notification to be sent when this product is back in stock.');
				}
				else if (objJson.backInStockNotification.errorHandle == 'INVALID_EMAIL')
				{
					setOosFormError('Please enter a valid email address');
				}
				else
				{
					alert('An error occurred, please try again');
				}
			}

			function setOosFormError(strText)
			{
				$('#oosFormError')
					.hide()
					.html(strText)
					.fadeIn('fast');
			}

			function setOosFormSuccess(strText)
			{
				$('#oosFormError')
					.hide();

				$('#stockNotificationForm')
					.hide();

				$('#oosMessage')
					.hide()
					.html(strText)
					.fadeIn('fast');
			}

			function validateBeforeSubmit(formData, jqForm, options)
			{
				var bolSubmit = false;

				$.each(
					formData,
					function(intIndex, objInput)
					{
						if (objInput['name'] == 'notificationRecipient')
						{
							var strEmail = formData[2]['value'];

							if (strEmail == strDefaultText)
							{
								setOosFormError('Please enter your email');
							}
							else if (!strEmail.match(/[\S]+@[\S]+\.[\S]/))
							{
								// very loose address check to cut down on unnecessary server requests
								setOosFormError('Please enter a valid email address');
							}
							else
							{
								bolSubmit = true;
							}
						}
					}
				);

				if (bolSubmit)
				{
					return true;
				}

				return false;
			}

			outOfStockForm.attr('action', '/web_services/json/ProductBackInStockNotificationRequest');

			outOfStockForm.ajaxForm({
				beforeSubmit : validateBeforeSubmit,
				dataType     : 'json',
				success      : handleFormResponse,
				error        : function()
				{
					alert('We were unfortunately unable to process your request');
				}
			});

			// quick hack to remove empty the tab line if there aren't any tabs
			if ($('.tabs').find('li').length == 0)
			{
				$('.tabs')
					.hide();
			}
		}

		/*
		 * Gallery
		 */
		$('.ad-gallery').adGallery(
		{
			width: 258,
			height: 200,
			effect: 'fade',
			animation_speed: 250
		});

		/*
		 * Main product image as gallery image size hack
		 * We have a fixed max height but set the height if the width is > maxDim
		 */
		var maxDim     = 30;
		var mainImg    = $('#mainProductImage');
		var mainWidth  = mainImg.width();

		if (mainWidth > maxDim)
		{
			mainImg.attr('width', maxDim);
			mainImg.attr('height', Math.ceil((maxDim / mainWidth) * mainImg.height()));
		}

		/*
		 * Review handling
		 */
		var reviewOffset    = 4;
		var reviewIncrement = 5;

		function getReviewOffset()
		{
			return reviewOffset;
		}

		function incrementReviewOffset()
		{
			reviewOffset += reviewIncrement;
		}

		function allReviewsLoaded()
		{
			$('#reviews')
				.find('.reviewControls')
				.html('<span class="noMoreReviews">There are no more reviews to load, that\'s all of them!</a>')
		}

		// initial review controls
		$('#reviews')
			.find('.reviewControls')
			.append('<a class="loadReviews">Load more reviews</a>');

		// load reviews
		$('#reviews .loadReviews').click(function(e)
		{
			e.preventDefault();

			$('#reviews .loadReviews')
				.addClass('loading');

			var jsonUrl = '/web_services/json/JsonGetReviews/?productId=' + getProductId() + '&offset=' + getReviewOffset();

			var orderBy    = getReviewOrderBy();
			var reviewType = getReviewType();

			if (orderBy.length > 0)
			{
				jsonUrl += '&review_order_by=' + orderBy;
			}

			if (reviewType.length > 0)
			{
				jsonUrl += '&review_type=' + reviewType;
			}

			$.ajax({
				url: jsonUrl,
				dataType: 'json',
				data: {},
				success: function(json)
				{
					addExtraReviews(json);
				},
				error: function(request, status, error)
				{
					alert('Sorry, reviews seem to be temporarily unavailable.. please try again shortly.');

					$('#reviews .loadReviews')
						.removeClass('loading');
				}
			});

			return false;
		});

		// add extra reviews
		function addExtraReviews(json)
		{
			var newReviewTop = $('#dynamicReviewZone').offset().top;
			var zoneHeight   = $('#dynamicReviewZone').height();

			if (zoneHeight > 0)
			{
				newReviewTop += zoneHeight;
			}

			if (json.productReviews.reviews)
			{
				var pullCount = json.productReviews.reviews.review.length;

				if (pullCount > 0)
				{
					for(x in json.productReviews.reviews.review)
					{
						appendReview(json.productReviews.reviews.review[x]);
					}

					incrementReviewOffset();
					scrollFromTop(newReviewTop);
				}

				if (pullCount < reviewIncrement)
				{
					allReviewsLoaded();
				}
			}
			else
			{
				allReviewsLoaded();
			}

			$('#reviews .loadReviews').removeClass('loading');
		}

		// append helpful links
		$('#dynamicReviewZone').find('.reviewsHelpful').each(function()
		{
			$(this)
				.append('Did you find this ' + $(this).attr('type') + ' useful?')
				.append('<a class="vote" helpful="1">Yes</a>')
				.append('<a class="vote" helpful="0">No</a>');
		})

		// handle helpful link actions
		$('#dynamicReviewZone .reviewsHelpful .vote').live('click', function(e)
		{
			e.preventDefault();

			var reviewId = $(this).parent().attr('review');
			var vote     = $(this).attr('helpful');

			$.ajax({
				type: 'POST',
				dataType: 'json',
				url : '/web_services/json/ReviewHelpfulVote',
				data:
				{
					'reviewId'    : reviewId,
					'helpfulVote' : vote
				},
				success: function(data)
				{
					if (data.helpfulVote.result == 'success')
					{
						$('#dynamicReviewZone')
							.find('.reviewsHelpful[review="' + reviewId + '"]')
							.html('Thank you for your vote!');
					}
					else if (data.helpfulVote.reason == 'notLoggedIn')
					{
						alert('You must be logged in to vote.');
					}
					else
					{
						alert('Something went wrong, please try again shortly.');
					}
				},
				error: function(request, status, error)
				{
					alert('Sorry, we couldn\'t process your vote.. please try again.');
				}
			});

			return false;
		});

		$('#productBuyingInfo').find('.buyButtonLarge').hover(function()
		{
			$(this).stop().fadeTo(500, 0);
		},
		function()
		{
			$(this).stop().fadeTo(500, 1);
		});

		/*
		 * Discussion
		 */
		var intMinChars = 10;
		var intMaxChars = 1000;

		function limitDiscussionChars(strElementId, intLimit, strCharsLeftInfoId)
		{
			var strMessage = $('#'+strElementId).val();
			var intMessageLength = strMessage.length;
			var strCharWord = 'characters';

			if (intMessageLength > intLimit)
			{
				$('#'+strCharsLeftInfoId).html('No characters remaining');
				$('#'+strCharsLeftInfoId).addClass('bold');
				$('#'+strElementId).val(strMessage.substr(0, intLimit));
				return false;
			}
			else
			{
				if ( intMessageLength == 0 )
				{
					$('#' + strCharsLeftInfoId).html(' ');
					return true;
				}
				else if( (intLimit - intMessageLength) == 1 )
				{
					strCharWord = 'character';
					$('#'+strCharsLeftInfoId).removeClass('bold');
				}
				else if ( intLimit == intMessageLength )
				{
					$('#'+strCharsLeftInfoId).addClass('bold');
				}
				else
				{
					$('#'+strCharsLeftInfoId).removeClass('bold');
				}

				$('#' + strCharsLeftInfoId).html('You have '+ (intLimit - intMessageLength) + ' ' + strCharWord + ' left');
				return true;
			}
		}

		$("#discussionValidation").text('Please enter more than ' + intMinChars + ' characters').hide();

		$('#DiscussionText').keyup(function(){
			limitDiscussionChars('DiscussionText', intMaxChars, 'discussionCharsLeft');
		});

		$("#productDiscussionForm").submit(function()
		{
			if ($("#DiscussionText").val().length > intMinChars )
			{
				return true;
			}
			else
			{
				$("#discussionValidation").stop(true, true).fadeIn(500).fadeOut(5000);
				return false;
			}
		});

		/*
		 * Keyboard commands
		 */
		document.onkeydown = function(e)
		{
			if (e == null)
			{
				// IE
				keycode = event.keyCode;
			}
			else
			{
				// Mozilla
				keycode = e.which;
			}

			// keycode 27 = Esc
			if (keycode == 27)
			{
				overlayClose();
			}
		}

		/*
		 * Fancy "to top of page" scroll animation
		 */
		var pageTopLink = $('a.toTop');

		pageTopLink.attr('href', '#top').bind('click', function(e)
		{
			e.preventDefault();
			scrollFromTop(0);
			return false;
		});

		/*
		 * Enable print page button
		 */
		$('.print-page a').click(function(e)
		{
			e.preventDefault();
			window.print();
			return false;
		});
	});

	function stripslashes(str)
	{
		str = str.replace(/\\'/g,  '\'');
		str = str.replace(/\\"/g,  '"');
		str = str.replace(/\\0/g,  '\0');
		str = str.replace(/\\\\/g, '\\');

		return str;
	}

	var targetDate                    = null;
	var deliverByDateText             = null;
	var previousDeliveryCountDownText = null;

	function getDateElement(seconds, element)
	{
		switch (element)
		{
			case 'daysVal':
				return ((Math.floor(seconds/86400))%100000).toString()
				break;

			case 'hoursVal':
				return ((Math.floor(seconds/3600))%24).toString()
				break;

			case 'minutesVal':
				return ((Math.floor(seconds/60))%60).toString()
				break;

			case 'secondsVal':
				return ((Math.floor(seconds/1))%60).toString()
				break;
		}
	}

	function setCutOffText(secondsToGo)
	{
		var textDiv = $('#deliveryCountDown');

		var text = '';
		var textAppend = '';

		if (secondsToGo > 0)
		{
			var daysVal    = getDateElement(secondsToGo, 'daysVal');
			var hoursVal   = getDateElement(secondsToGo, 'hoursVal');
			var minutesVal = getDateElement(secondsToGo, 'minutesVal');
			var secondsVal = getDateElement(secondsToGo, 'secondsVal');

			text += 'Order ';

			// in seconds..
			var oneHour = 3600; // 60*60
			var oneDay  = 86400; // oneHour*24;
			var twoDays = 172800; // oneDay*2;

			var showMinutesUnderHours = 6;

			if (secondsToGo < oneDay)
			{
				// a few hacks to round up the hours and minutes
				// so for example, we can say "within 5 minutes" instead of "just over 4 minutes"
				if (minutesVal >= 0)
				{
					minutesVal = parseInt(minutesVal) + 1;
				}

				if (hoursVal >= showMinutesUnderHours && hoursVal < 24)
				{
					hoursVal = parseInt(hoursVal) + 1;
				}
				else if (hoursVal < showMinutesUnderHours && minutesVal == 60)
				{
					minutesVal = 0;
					hoursVal = parseInt(hoursVal) + 1;
				}

				text += 'within ';

				if (hoursVal > 0)
				{
					text += hoursVal + ' ';
					text += hoursVal == 1 ? 'hour' : 'hours';
					text += ' ';
				}

				if (hoursVal < showMinutesUnderHours && minutesVal > 0)
				{
					if (hoursVal > 0)
					{
						text += 'and ';
					}

					text += minutesVal + ' ';
					text += minutesVal == 1 ? 'minute' : 'minutes';
				}
			}
			else if (secondsToGo >= oneDay && secondsToGo < twoDays)
			{
				if (hoursVal >= 0)
				{
					hoursVal = parseInt(hoursVal) + 1;
				}

				if (hoursVal == 24)
				{
					hoursVal = 0;
					daysVal = parseInt(daysVal) + 1;
				}

				text += 'within ';

				if (hoursVal > 0)
				{
					text += '1 day and ' + hoursVal + ' ';
					text += hoursVal == 1 ? 'hour' : 'hours';
					text += ' ';
				}
				else
				{
					text += '24 hours';
				}
			}
			else
			{
				text += 'now';
			}
		}
		else
		{
			text += "Sorry, you're out of time to order today";
			textAppend = '<br /><span class="refreshMe">Please refresh to see when we can next deliver</span>';
		}

		text += ' for delivery on <span class="deliverByDate">' + deliverByDateText + '</span>';

		text += textAppend;

		if (text != previousDeliveryCountDownText)
		{
			textDiv.hide().html(text).show();
			previousDeliveryCountDownText = text;
		}
	}

	function updateCutOffTimer()
	{
		var dateNow     = new Date();
		var dateDiff    = new Date(targetDate - new Date());
		var secondsToGo = Math.floor(dateDiff.valueOf()/1000);

		setCutOffText(secondsToGo);

		if (secondsToGo > 0)
		{
			setTimeout('updateCutOffTimer()', 1000);
		}
	}

	function initialiseCutOffTimer(daysTilCutOff, hoursTilCutOff, minutesTilCutOff, secondsTilCutOff, deliverByDate)
	{
		targetDate = new Date();

		deliverByDateText = deliverByDate;

		targetDate.setDate(targetDate.getDate() + daysTilCutOff);
		targetDate.setHours(targetDate.getHours() + hoursTilCutOff);
		targetDate.setMinutes(targetDate.getMinutes() + minutesTilCutOff);
		targetDate.setSeconds(targetDate.getSeconds() + secondsTilCutOff);

		updateCutOffTimer();
	}

	function appendReview(review)
	{
		var reviewTypeText = '';

		if (review.reviewType == 'review')
		{
			reviewTypeText = 'Review:';
		}
		else
		{
			reviewTypeText = 'Comment:';
		}

		var reviewerName = '';

		if (review.anonymous == 'no' && review.reviewerName.length > 0)
		{
			reviewerName = review.reviewerName;
		}
		else if (review.anonymous == 'yes' && review.anonName.length > 0)
		{
			reviewerName = review.anonName;
		}
		else
		{
			reviewerName = 'Anonymous';
		}

		var rating = '';

		if (review.reviewType == 'review')
		{
			rating =
				$('<span class="reviewerRating">')
					.append('rating:<br /><img src="' + getStaticUrl() + '/images/reviewstar_' + review.rating + '.gif" border="0" alt="customer rating" />');
		}

		var reviewerInfo =
			$('<div class="reviewer">')
				.append('review by <span class="reviewerName"><strong>' + stripslashes(reviewerName) + '</strong></span>')
				.append(rating)
				.append('<span class="reviewerOs">operating system: ' + review.operatingSystem + '</span>');

		var helpfulVote = '';

		if (showVote())
		{
			helpfulVote =
				$('<span class="reviewsHelpful" review="' + review.id + '">')
					.append('Did you find this ' + review.reviewType + ' useful?')
					.append('<a class="vote" helpful="1">Yes</a>')
					.append('<a class="vote" helpful="0">No</a>');
		}

		var reviewBoxBase =
			$('<div class="reviewBoxBase"><strong>' + review.helpfulCount + ' of ' + review.voteCount + '</strong> people found this review useful</div>')
			.append(helpfulVote);

		var newReview =
			$('<div class="reviewBox">')
				.append('<span class="reviewDate">' + review.reviewDate + '</span>')
				.append('<span class="reviewType">' + reviewTypeText + '</span>')
				.append('<h5>' + stripslashes(review.reviewTitle) + '</h5>')
				.append(reviewerInfo)
				.append('<p>' + stripslashes(review.reviewText) + '</p>')
				.append(reviewBoxBase);

		var identifier = 'r' + review.id;

		var reviewContainer =
			$('<div id="' + identifier + '" style="display: none;">')
				.append(newReview)
				.append('<div class="reviewBoxEnd">');

		$('#dynamicReviewZone').append(reviewContainer);

		$('#' + identifier).fadeIn();
	}

