window['ProductFinder'] = (function($) {

	var publicObj = {
		"init":	function(sizes, priceRange, isSearch) {
			oThis.init(sizes, priceRange, isSearch);
		}
	};

	var oThis = {

		init: function(sizes, priceRange, isSearch) {

			this.priceRange = priceRange;
			this.sizes = sizes;
			this.size = sizes.small;
			this.doHover = true;
			this.showInfo = false;
			this.showCompare = false;
			this.isSearch = isSearch;

			this.searchQuery = '';
			this.currentHash = '';

			$(function() {
				oThis.readyInit();
			});

			$(window).load(function() {
				oThis.loadInit();
			});
		},

		readyInit: function() {
			var oThis = this;

			this.containerDiv = $('#shop-items');

			this.containerWidth = this.containerDiv.width();
			this.containerHeight = this.containerDiv.height();
			this.prevContainerHeight = this.containerHeight;
			this.containerOffset = this.containerDiv.offset();

			this.currentLeft = 0;
			this.currentTop = 0;

			this.compareButton = $('.itemsHeader a.compare');
			this.compareDiv = $('#compare-div');

			this.compareDiv.show();
			this.compareStartOffset = this.compareDiv.offset();
			this.compareStartPosition = this.compareDiv.position();
			this.compareDiv.hide();

			this.compareButton.hover(function() {
				oThis.comparePopup();
			}, function() {
				oThis.compareHide();
			}).click(function() {
				oThis.compareDiv.hide();
			});

			$(window).scroll(function() {
				oThis.scrollPopup();
			});
			this.scrollPopup();

			this.searchInfo = $('.itemsHeader .searchInfo');
			this.noProductsFound = $('.noProductsFound');

			this.tiles = this.containerDiv.find('div.items img');

			// Sort tiles into correct order
			var tileSort = function(a, b) {
				var aId = parseInt(a.id.substr(13));
				var bId = parseInt(b.id.substr(13));
				return aId - bId;
			};
			this.tiles.sort(tileSort);

			this.visibleTiles = this.tiles.filter(':visible');

			this.helpInfo = $('#shop-help');

			if(!$.cookie("hiddenHelp")) {
				this.helpInfo.show();

				this.helpInfo.click(function() {
					oThis.hideHelp();
				});

				setTimeout(function() {
					oThis.hideHelp();
				}, 3000);
			}

			this.tiles.each(function() {
				var imgData = oThis.getImgData($(this));
				var priceNum = imgData.price.replace(/[^0-9.]/g, '');
				$(this)
					.data('imgData', imgData)
					.attr('price', priceNum);
			});

			this.groupULs = $('#left-column ul');

			this.navLinks = $('#left-column ul a.nav');
			this.resetButton = $('#resetButton');

			this.setWorking(true);
			this.firstLoad = true;

			this.calculateDimensions();

			// Nav click
			$.address.internalChange(function(event) {
				setTimeout(function() {
					oThis.updateDisplay(true);
				}, 0);
			});

			// Back button/deep linking
			$.address.externalChange(function(event) {
				oThis.setWorking(true);

				var hasHash = event.path.length > 1;
				var hasQuery = typeof event.parameters.q != 'undefined' && event.parameters.q.length > 0;

				if(hasHash) {
					oThis.currentHash = event.path;

					oThis.navLinks.removeClass('selected');
					var aliases = event.path.substr(1).split('/');

					for(var i=0; i<aliases.length; i++) {
						oThis.navLinks.filter('[rel=' + aliases[i] + ']').addClass('selected');
					}
				}

				var completeFn = function() {
					if(!oThis.firstLoad || oThis.showInfo || oThis.showCompare || hasHash || hasQuery) {
						oThis.updateDisplay(false);
					} else {
						oThis.updateNav();
						oThis.setWorking(false);
					}

					if(oThis.firstLoad) {
						oThis.firstLoad = false;
					}
				};

				if(hasQuery) {
					oThis.doSearch(event.parameters.q, completeFn);
				} else {
					completeFn.call(oThis);
				}
			});

			this.navLinks.click(function() {
				oThis.clickFn($(this));
				return false;
			});

			this.resetButton.click(function() {
				oThis.setWorking(true);
				oThis.hideHelp();
				oThis.navLinks.removeClass('selected');

				setTimeout(function() {
					oThis.resetSlider();

					if($.address.path() == '/')
						oThis.updateDisplay(true);
					else if($.address.value() != '/-')
						$.address.value('-');
					else
						oThis.setWorking(false);
				}, 0);

				return false;
			});

			this.rolloverEl = $('.shop-item-rollover');
			this.rolloverTitle = this.rolloverEl.find('p.altDesc');
			this.rolloverImgEl = this.rolloverEl.find('.shop-rollover-image');
			this.rolloverPrice = this.rolloverEl.find('p.price');

			this.rolloverDivWidth = this.rolloverEl.width();
			this.rolloverDivHeight = this.rolloverEl.height();

			this.compareHover = $('.shop-med-compare');
			this.compareHoverA = $('.shop-med-compare a');

			this.compareHoverA.click(function() {
				var id = $(this).attr('rel');
				oThis.comparePopup(id);
				return false;
			});

			this.infoDivs = $([]);

			this.minPrice = this.priceRange[0];
			this.maxPrice = this.priceRange[1];
			this.currency = this.priceRange[2];

			/*$('#product-search-submit').click(function(e) {
				if(oThis.working)
					return;
				oThis.setWorking(true);

				oThis.doSearch($('#product-search-box').val(), function() {
					oThis.rebuildHash();
				});

				return false;
			});*/

			this.initSlider();

			this.initEls();
		},

		hideHelp: function() {
			if(this.helpHidden)
				return;
			this.helpHidden = true;

			this.helpInfo.fadeOut(100);
			$.cookie("hiddenHelp", true);
		},

		loadInit: function() {
			var oThis = this;

			this.setWorking(false);

			setTimeout(function() {
				oThis.setWorking(false);
			}, 100);
		},

		initEls: function() {
			var oThis = this;

			this.tiles
					.mouseenter(function(e) {
						clearTimeout(oThis.rolloverTimeout);
						oThis.updateRollover($(this));
					})
					.mouseleave(function(e) {
						oThis.rolloverTimeout = setTimeout(function() {
							oThis.rolloverEl.hide();
						}, 5);
					});

			this.containerDiv
						.mousemove(function(e) {
							oThis.moveRollover(e);
						})
						.mouseleave(function(e) {
							clearTimeout(oThis.rolloverTimeout);
							oThis.rolloverEl.hide();
							oThis.compareHover.hide();
						});
		},

		// Calculate new dimensions
		calculateDimensions: function() {
			var tileCount = this.visibleTiles.length;

			if(tileCount <= this.sizes.large.maxItems){
				this.size = this.sizes.large;
				this.imageNewSrc = '_large.png';
				this.doHover = false;
				this.showInfo = true;
				this.showCompare = false;
			} else if( tileCount > this.sizes.large.maxItems && tileCount <= this.sizes.medium.maxItems) {
				this.size = this.sizes.medium;
				this.imageNewSrc = '_med.jpg';
				this.doHover = true;
				this.showInfo = false;
				this.showCompare = true;
			} else {
				this.size = this.sizes.small;
				this.imageNewSrc = '_small.gif';
				this.doHover = true;
				this.showInfo = false;
				this.showCompare = false;
			}
		},

		// Set height of container (updated by moveEls)
		setContainerHeight: function(atEnd) {
			var oldHeight = this.containerHeight;
			var newHeight = Math.max(800, this.currentLeft == 0 ? this.currentTop : this.currentTop + this.size.divHeight);

			if(newHeight > oldHeight && !atEnd) {
				this.containerHeight = newHeight;
				this.containerDiv.css('height', newHeight);
			} else if (newHeight < oldHeight && atEnd) {
				this.containerHeight = newHeight;
				this.containerDiv.animate({'height': newHeight}, 200);
			}
		},

		// Calculate position of all images
		positionEls: function() {
			var oThis = this;

			var beforeWidth = this.size.width;

			this.calculateDimensions();

			this.currentLeft = this.size.leftStart;
			this.currentTop = this.size.topStart;

			this.visibleTiles.each(function() {
				oThis.positionEl($(this));
			});

			return beforeWidth != this.size.width;
		},

		// Set correct image source
		setImgSrc: function(els) {
			var oThis = this;

			els.each(function() {
				var thisEl = $(this);
				var imageSrc = oThis.getNewImgSrc(thisEl.attr('src'), oThis.imageNewSrc)
				thisEl.attr({'src':imageSrc});
			});
		},

		getNewImgSrc: function(src, newSrc) {
			return src
					.replace('_small.gif',newSrc)
					.replace('_med.jpg',newSrc)
					.replace('_large.png',newSrc);
		},

		// Calculate new position
		positionEl: function(el) {

			var targetPos = {
				'left':		this.currentLeft,
				'top':		this.currentTop,
				'height':	this.size.height,
				'width':	this.size.width
			};

			var startPos = {
				'left':		parseInt(el.css('left')),
				'top':		parseInt(el.css('top')),
				'height':	parseInt(el.css('height')),
				'width':	parseInt(el.css('width'))
			};

			var changePos = {
				'left':		targetPos.left - startPos.left,
				'top':		targetPos.top - startPos.top,
				'height':	targetPos.height - startPos.height,
				'width':	targetPos.width - startPos.width
			};

			el.get(0).aniData = {prev: startPos, change: changePos};
			el.data('targetPos', targetPos);

			if (this.currentLeft + (this.size.divWidth * 2) < this.containerWidth) {
				this.currentLeft += this.size.divWidth;
			} else {
				this.currentLeft = this.size.leftStart;
				this.currentTop += this.size.divHeight;
			}
		},

		// Move to new position
		moveEls: function(els, animate, cb) {
			var oThis = this;

			var completeFn = function() {
				if(typeof cb == 'function') {
					cb();
				}
			};

			if(animate) {
				this.animatePos(els, 100, completeFn);
			} else {
				this.movePos(els);
				completeFn();
			}
		},

		// Move to new position with animation
		animatePos: function(elements, duration, cb) {
			var oThis = this;
			var time = 0;
			var interval;

			var easing = function (t, b, c, d) {
				return c*((t=t/d-1)*t*t + 1) + b;
			}

			var startTime = (new Date()).getTime();
			var i, aniData;

			var aniFn = function() {
				for(i=0; i<elements.length; i++) {
					aniData = elements[i].aniData;

					elements[i].style.left = easing(time, aniData.prev.left, aniData.change.left, duration) + 'px';
					elements[i].style.top = easing(time, aniData.prev.top, aniData.change.top, duration) + 'px';
					elements[i].style.height = easing(time, aniData.prev.height, aniData.change.height, duration) + 'px';
					elements[i].style.width = easing(time, aniData.prev.width, aniData.change.width, duration) + 'px';
				}

				time += 10;

				if(time > duration) {
					clearInterval(interval);
					if(typeof cb == 'function')
						cb();
					return;
				}
			};

			interval = setInterval(aniFn, 1);
		},

		// Move without animating
		movePos: function(elements) {
			var oThis = this;

			elements.each(function() {
				var thisEl = $(this);
				var pos = thisEl.data('targetPos');

				thisEl.css(pos);
			});
		},

		doSearch: function(query, completeFn) {
			var oThis = this;

			this.searchQuery = query;

			$.getJSON('search-results', {q:query}, function(data) {
				oThis.tiles.removeClass('search-result');

				$.each(data, function(i, id) {
					oThis.containerDiv.find('div.items>a[rel=' + id + ']>img').addClass('search-result');
				});

				oThis.navLinks.filter('[rel=search-result]')
										.removeClass('disabled')
										.addClass('selected')
										.html('Search: ' + query)
										.parent()
											.show();

				if(typeof completeFn == 'function') {
					completeFn.call(oThis);
				}
			});
		},

		clickFn: function(el) {
			if(this.working || el.hasClass('disabled'))
				return;
			this.setWorking(true);

			this.hideHelp();

			if(this.visibleTiles.length == 0) {
				this.navLinks.filter('[rel=search-result]').removeClass('selected');
			}

			if(el.hasClass('selected')) {
				el.removeClass('selected');
			} else {
				el.addClass('selected');
			}

			setTimeout(function() {	// Do processing asynchronously so the UI works smoothly
				var aliasArr = [];

				oThis.navLinks.filter('.selected').each(function() {
					aliasArr.push(this.rel);
				});

				oThis.currentHash = aliasArr.length > 0 ? aliasArr.join('/') : '-';

				oThis.rebuildHash();
			}, 0);
		},

		rebuildHash: function() {
			var query = this.currentHash;

			if(this.searchQuery.length > 0) {
				query += '?q=' + this.searchQuery;
			}

			$.address.value(query);
		},

		getNavFilterEls: function(el) {
			var linkSelector = 'a.selected';

			if(el && this.visibleTiles.length == 0) {
				linkSelector += '[rel!=search-result]';
			}

			if(el) {
				linkSelector += ',a[rel=' + el.rel + ']';
			}

			var newVisibleEls = this.tiles.filter(function() {
				var price = $(this).attr('price');
				return price >= oThis.minPrice && price <= oThis.maxPrice;
			});

			this.groupULs.each(function() {
				var links = $(this).find(linkSelector);
				var groupCss = [];
				links.each(function() {
					if(!el || this.rel != el.rel || !$(this).hasClass('selected')) {
						groupCss.push('.' + this.rel);
					}
				});
				if(groupCss.length)
					newVisibleEls = newVisibleEls.filter(groupCss.join(','));
			});

			return newVisibleEls;
		},

		updateNav: function() {//return;
			var oThis = this;
			var currentCount = this.visibleTiles.length;

			// Update title text
			var infoText = "Showing " + (currentCount==this.tiles.length ? 'all' : currentCount) + " product" + (currentCount == 1 ? '' : 's');
			if(currentCount == 0) {
				infoText = 'No products found';
				this.noProductsFound.show();
			} else {
				this.noProductsFound.hide();
			}
			this.searchInfo.html(infoText);

			// Update bracketed numbers
			this.navLinks.each(function() {
				var newCount = oThis.getNavFilterEls(this).length;
				var difference = newCount - currentCount;
				var num = '';
				var thisEl = $(this);

				thisEl.removeClass('disabled');

				if(!thisEl.hasClass('selected')) {
					if(newCount == 0 || difference == 0) {
						thisEl.addClass('disabled');
					} else {
						num = '(' + (difference>0 && currentCount>0 ? '+' + difference : newCount) + ')'
					}
				}

				thisEl.find('.count').html(num);
			});
		},

		setWorking: function(state) {
			this.working = state;

			var bodyCss = {cursor: state ? 'progress' : 'default'};
			var linkCss = {cursor: state ? 'progress' : 'pointer'};

			$('body').css(bodyCss);
			this.navLinks.css(linkCss);
			this.resetButton.css(linkCss);
		},

		updateDisplay: function(animate) {
			var oThis = this;

			var newVisibleEls = this.getNavFilterEls();

			//var toLeaveEls = newVisibleEls.filter(':not(.hiddentile)');
			var toShowEls = newVisibleEls.filter('.hiddentile').removeClass('hiddentile');
			var currentlyVisibleEls = this.visibleTiles;
			this.visibleTiles = newVisibleEls;

			newVisibleEls.addClass('tilesToShow');
			var toHideEls = currentlyVisibleEls.filter(':not(.tilesToShow)');
			newVisibleEls.removeClass('tilesToShow');

			toHideEls.addClass('hiddentile').hide();

			oThis.updateNav();

			var changedSize = this.positionEls();

			this.containerDiv.children('.shop-view12-auto-description').remove();

			if(newVisibleEls.length == this.tiles.length || newVisibleEls.length > currentlyVisibleEls.length) {
				// Reset/add tiles

				toShowEls.css('opacity', 0).show();
				this.setImgSrc(newVisibleEls);
				this.setContainerHeight(false);

				this.moveEls(toShowEls, false);

				this.moveEls(newVisibleEls, animate, function() {
					oThis.setContainerHeight(true);

					toShowEls.fadeTo(500, 1);

					setTimeout(function() {
						oThis.updateInfo();
						//oThis.updateNav();
						oThis.setWorking(false);
					}, 250);
				});
			} else if(newVisibleEls.length < currentlyVisibleEls.length || currentlyVisibleEls.length == this.tiles.length) {
				// Remove tiles/first click
				toShowEls.show();

				this.setContainerHeight(false);

				this.moveEls(newVisibleEls, animate, function() {
					oThis.setContainerHeight(true);

					oThis.setImgSrc(newVisibleEls);
					oThis.updateInfo();
					//oThis.updateNav();
					oThis.setWorking(false);
				});
			} else {
				// Do nothing
				oThis.updateInfo();
				//oThis.updateNav();
				oThis.setWorking(false);
			}
		},

		updateInfo: function() {
			var oThis = this;

			if(this.showInfo) {
				this.visibleTiles.each(function() {
					var data = $(this).data('imgData');
					var prodId = $(this).parent().attr('rel');

					var div = $('<div/>')
									.addClass('shop-view12-auto-description')
									.append(
										$('<p/>')
											.addClass('title')
											.html(data.desc)
									)
									.append(
										$('<p/>')
											.addClass('price')
											.html(data.price)
											.append(
												$('<a/>')
													.addClass('compare')
													.addClass('compareid-' + prodId)
													.attr('title', 'Compare')
													.attr('href', 'compare/' + prodId)
													.html('Compare')
											)
									);
					div.css({
						left:	parseInt($(this).css('left')) - oThis.size.leftStart,
						top:	parseInt($(this).css('top')) + oThis.size.height + 5
					})

					div.find('a.compare').click(function() {
						oThis.comparePopup(prodId);
						return false;
					});

					oThis.containerDiv.append(div);
				});
			}
		},

		scrollPopup: function() {
			if($(document).scrollTop() > this.compareStartOffset.top) {
				this.compareDiv.css({
					position:	'fixed',
					top:		0,
					left:		this.compareStartOffset.left
				});
			} else {
				this.compareDiv.css({
					position:	'absolute',
					top:		this.compareStartPosition.top,
					left:		this.compareStartPosition.left
				});
			}
		},

		comparePopup: function(productId){
			var oThis = this;

			if(typeof productId == 'undefined') {
				productId = '';
			}

			oThis.compareDiv.find('#compare-content').hide();
			oThis.compareDiv.find('#compare-loading').show();

			this.compareDiv.clearQueue().fadeTo(300, 1);

			$.post('compare-popup/' + productId, function(data) {
				oThis.compareDiv.find('#compare-loading').hide();
				oThis.compareDiv.find('#compare-content').html(data.html).show();

				oThis.compareButton
							.attr('href', 'compare/' + data.compareIds.join('/'))
							.html('Comparing (' + data.compareIds.length + ') items')
							.css('visibility', data.compareIds.length == 0 ? 'hidden' : 'visible');

				if(productId != '') {
					setTimeout(function() {
						oThis.compareHide();
					}, 1000);
				}
			});

			return false;
		},

		compareHide: function() {
			this.compareDiv.fadeOut(300);
		},

		updateRollover: function(el) {
			if(this.working || !this.doHover)
				return;

			var imgData = el.data('imgData');
			var srcImage = this.getNewImgSrc(el.attr('src'), '_large.png');

			this.rolloverTitle.html(imgData.desc+' <span class="product-code">'+imgData.code+'</span>');
			this.rolloverPrice.html('Price <span>' + imgData.price + '</span>');

			var rolloverImg = this.rolloverImgEl.children('img');
			var hasImg = true;

			if(rolloverImg.length == 0) {
				hasImg = false;
				rolloverImg = $('<img/>')
			}

			rolloverImg
					.attr('src', srcImage)
					.attr('alt', imgData.desc);

			if(!hasImg) {
				this.rolloverImgEl.append(rolloverImg);
			}

			this.rolloverEl.show();

			if(this.showCompare) {
				var id = el.parents().attr('rel');

				this.compareHover
						.css({
							left:	el.css('left'),
							top:	parseInt(el.css('top')) + this.size.divHeight - 20
						})
						.show();

				this.compareHoverA.attr('rel', id);

				if($.inArray(id, this.compare) == -1)
					this.compareHoverA.removeClass('compareselected');
				else
					this.compareHoverA.addClass('compareselected');
			}
		},

		moveRollover: function(e) {
			if(this.working || !this.doHover)
				return;

			var mousePosX = e.pageX - this.containerOffset.left;
			var mousePosY = e.pageY - this.containerOffset.top;

			var maxHeight = $(document).scrollTop() + $(window).height() - this.containerOffset.top;

			var top = mousePosY + 20 + this.rolloverDivHeight < maxHeight;
			var left = mousePosX + 20 + this.rolloverDivWidth < this.containerWidth;

			this.rolloverEl.css({
				'left': left ? mousePosX + this.size.width : mousePosX  - this.rolloverDivWidth - this.size.width + 'px',
				'top': top ? mousePosY + 10 : mousePosY + 10 - this.rolloverDivHeight,
				'backgroundImage':'url(/images/shop-overview/rollover-bg-' + (top ? 'top' : 'bottom') + '-' + (left ? 'left' : 'right') + '.png)',
				'paddingLeft': left ? 21 : 11,
				'paddingRight': left ? 10 : 20
			});
		},

		getImgData: function(img) {
			var mainParts = img.attr('alt').split(" | ");
			var priceParts = mainParts[1].split("=");

			return {
				desc:	mainParts[0],
				price:	priceParts[1],
				code:	mainParts[2]
			};
		},

		setPriceRange: function(min, max) {
			this.minPrice = min;
			this.maxPrice = max;

			this.updateDisplay(true);
		},

		resetSlider: function() {
			this.minPrice = this.priceRange[0];
			this.maxPrice = this.priceRange[1];
			this.currency = this.priceRange[2];

			this.priceMinEl.html(this.currency.replace('#', this.minPrice));
			this.priceMaxEl.html(this.currency.replace('#', this.maxPrice));

			this.priceSlider.slider("values", 0, this.minPrice);
			this.priceSlider.slider("values", 1, this.maxPrice);
		},

		initSlider: function() {
			var oThis = this;

			this.priceSelector = $('#price-selector');
			this.priceSelector.css('display', 'block');

			this.priceSlider = $('#price-slider');

			this.priceMinEl = this.priceSelector.find('span.min-amount');
			this.priceMaxEl = this.priceSelector.find('span.max-amount');

			this.priceSlider.slider({
				range: true,
				min: this.minPrice,
				max: this.maxPrice,
				values: [this.minPrice, this.maxPrice],
				slide: function(event, ui) {
					oThis.priceMinEl.html(oThis.currency.replace('#', ui.values[0]));
					oThis.priceMaxEl.html(oThis.currency.replace('#', ui.values[1]));
				},
				stop: function(event, ui) {
					oThis.setPriceRange(oThis.priceSlider.slider('values', 0), oThis.priceSlider.slider('values', 1));
				}
			});

			var handles = this.priceSlider.children('a.ui-slider-handle');
			handles.eq(0).addClass('left-slider-arrow');
			handles.eq(1).addClass('right-slider-arrow');

			this.priceMinEl.html(this.currency.replace('#', this.priceSlider.slider("values", 0)));
			this.priceMaxEl.html(this.currency.replace('#', this.priceSlider.slider("values", 1)));
		}
	};

	return publicObj;

})(jQuery);