window.addEvent('domready', function() {
	
	/* [GENERAL] */

	/* Extend Fx.Slide for dynamic filter-slide updates */
	Fx.Slide = new Class({
		Extends: Fx.Slide,
		onComplete: function() {
			
			/* Mootools fix for undersliding subfilters */
			if (this.wrapper.offsetHeight != 0) 
				this.wrapper.setStyle('height', 'auto');
			
			/* Mootools fix for extra margin when filter closed */
			if (this.wrapper.offsetHeight == 2) 
				this.element.setStyle(this.margin,(this.element.getStyle(this.margin).toInt())-2);
			
			if ($('space').getStyle('margin-top') != '0px')
				$('activeSpace').setStyle('z-index','0');
		},
		onStart: function() {
			$('activeSpace').setStyle('z-index','-1');
		}
	});
	
	
	/* Clear search */
	var clearSearch = false;

	if ($('search')) $('search').addEvent('focus', function() {
		if (clearSearch != false)
			return false;

		this.set('value','');
		clearSearch = true;
	});

	/* External links */
	$$('.external').addEvent('click', function(e) {
		e.stop();
		
		var href = (this.href) ? this.href : this.getElements('a').first.href;
		var rel = (this.rel) ? this.rel : (this.getElements('a').first) ? this.getElements('a').first.rel : null;

		pageTracker._trackEvent('External/' + rel, href);
		window.open(href);
	});
	
	/* Internal links */
	$$('.internal').addEvent('click', function(e) {
		e.stop();

		var href = (this.href) ? this.href : this.getElement('a').href; 
		var rel = (this.rel) ? this.rel : this.getElement('a').rel;

		pageTracker._trackEvent('Internal/' +  rel, href);
		document.location.href = href;
	});
	
	
	/* [FRONTPAGE]	*/
	/* Helper function to change frontpage tabs */

	var frontPageTabs;

	var switchTab = function(sourceTab) {
		frontPageTabs.removeClass('activeTab');
		$$('.frontPageTabContent').setStyle('display', 'none');
	
		var targetTab = sourceTab + 'Content';
		$(sourceTab).addClass('activeTab');
		$(targetTab).setStyle('display', 'block');
	}

	if ($('frontPageIntro')) {
		frontPageTabs = $$('#tabs td');
		frontPageTabs.addEvent('mouseover', function() {
			switchTab(this.get('id'));
		});
		
		switchTab('frontPageTab2');
	}

	/* Color Chooser */
	if ($('colorChooser')) {
		var colors = $$('#colorChooser span a');
		var colorThumbs = $$('#colorChooser .colorThumbs');

		colors.addEvent('mouseenter', function() {
			colorThumbs.setStyle('display', 'none');
			colorThumbs[colors.indexOf(this)].setStyle('display', 'block');
		});
	}

	/* [LIST-VIEW]	*/
	
	if ($('rightColumn')) {

		/* SETUP FILTERS */
		var filterToggle = $$('#rightColumn h3');
		var filters = $$('#rightColumn ul.filterMenu');
		filters.slide('hide');

		var subFilterToggle = $$('#rightColumn a.arrowSubMenu');
		var subFilters = $$('#rightColumn li.filterMenuSub ul');
		subFilters.slide('hide');
	
		filterToggle.addEvent('click', function(e){
			e.stop();
			index = filterToggle.indexOf(this);
			filters[index].slide();
		});

		subFilterToggle.addEvent('click', function(e){
			e.stop();
			var index = subFilterToggle.indexOf(this);
			subFilters[index].slide();
		});
		
		/* CHECKBOX ACTIONS */
		var filterBoxes = $$('#rightColumn input');
		filterBoxes.addEvent('click', function() {
			document.location.href = this.getNext('a').get('href');
		});

		/* OPEN ACTIVE FILTERS */
		$$('.active').slide('show').setStyle('height','auto');
		$$('.active').each(function(openFilter) {
			openFilter.getParent().setStyle('height','auto');
		});
		
		/* SHOW FILTER MENU */
		if ($('rightColumn'))
			$('rightColumn').setStyle('visibility','visible');
		
	}
	
	
	/* [LIST-VIEW & SCRAPBOOK] */ 
	
	if ($('leftColumn') || $('scrapRight')) {
	
		/* THUMB MOUSEOVERS */
		$$('div.thumb').addEvent('mouseover', function() {	
			if (!this.hasClass('static'))
				this.addClass('open');	
		});
		$$('div.thumb').addEvent('mouseout', function() {
			if (!this.hasClass('static')) {
				if (this.getFirst('ul').getStyle('display') != 'block') {
					this.removeClass('open');
				}
			}
		});

		/* THUMB SHOW OPTIONS */
		var mainThumbs = $$('.thumbOptions');
		var mainThumbOptions = $$('.optionsList');
		
		mainThumbs.addEvent('click', function(e) {
			e.stop();
			index = mainThumbs.indexOf(this);
			mainThumbOptions[index].setStyle('display','block');
		});

		$$('li.optionsClose').addEvent('click', function(e) {
			e.stop();
			this.getParent().setStyle('display','none');
		});
	
	}
	

	/* [SUBMENU] */
	
	if ($('subMenu')) {
		var subMenuLink = $$('#header ul#menu li');
		var subMenuContent = $$('.subMenuContent');
		
		subMenuLink.addEvent('mouseenter', function() {
			
			subMenuContent.setStyle('display','none');					// Reset any previous menus
			if ($('linkBottom')) $('linkBottom').destroy();
			subMenuLink.removeClass('activeHover');		
			
			index = subMenuLink.indexOf(this);
			this.addClass('activeHover');

			if (this.hasClass('hasSub')) {									// Regular menu
				$$('.menuBorder').setStyle('visibility','visible');
				subMenuContent[index].setStyle('display','block');
				
				var linkWidth = (this.getSize().x - 2);
				var bottomBar = new Element('div', {
					'id': 'linkBottom',
					'styles': {	
						'width': linkWidth,
						'z-index': '11'
					 }
				}).injectTop(this);
				
			} else {																	// Scrapbook
				$$('.menuBorder').setStyle('visibility','hidden');
				this.addClass('activeHover');
			}
			
		});

		$('subMenu').addEvent('mouseleave', function() {
			HideSubMenu();
		});

		$('top').addEvent('mouseenter', function() {
			HideSubMenu();
		});
			
		function HideSubMenu(){
			if ($('linkBottom')) $('linkBottom').destroy();
			subMenuContent.setStyle('display','none');
			$$('.menuBorder').setStyle('visibility','hidden');
			subMenuLink.removeClass('activeHover');
		}
	}
	
	
	/* [SLIDE VIEW] */
	
	if ($('slide')) {

		$('slideImg').set('title', '');
		$('slideImg').set('alt', '');
		
		/* E-MAIL SLIDE */
		var mailPreview = false;
		
		$('mailSlide').addEvent('click', function(e) {
			e.stop();
			$('slideLayer').setStyle('display','block');
			$('slideLayerBack').setStyle('display','block');
			mailPreview = true;
		});	
			 
		$$('a.cancel').addEvent('click', function(e) {
			e.stop();
			$('slideLayer').setStyle('display','none');
			$('slideLayerBack').setStyle('display','none');
			$('emailSuccess').setStyle('display','none');
			mailPreview = false;
		});
		
		/* Preview & send mail */
		$('mailSubmit').addEvent('click', function(e) {
			e.stop();

			if ($chk(mailPreview)) {
				
				function checkForm() {
					var errors = false;
					
					for (i=1; i<=4; i++) {
						var fieldValue = $('field' + i).get('value');
						
						if (!$chk(fieldValue)) {
							errors = true;
							fieldStatus(i,'#ffdddd');
						} else {
							fieldStatus(i,'#fff');
						}
								
					}
					
					if ($chk(errors))
						return false;
					
					if (!checkEmail($('field2' ).get('value'))) {
						fieldStatus(2,'#ffdddd');
						return false;
					}
					
					if (!checkEmail($('field3' ).get('value'))) {
						fieldStatus(3,'#ffdddd');
						return false;
					}
					
					$('emailForm').send();
					$('emailSuccess').setStyle('display','block');
				}
				
				function fieldStatus(fieldNumber,status) {
					$('field' + fieldNumber).setStyle('background',status);
				}
				
				function checkEmail(address) {
					return new RegExp(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i).test(address);
				}
				
				checkForm();		
			}
				
		});
		
		/* Capture keys - dirty */
		function keyCheck(e) {
			if (!keyPolling == true)
				return false;

			var keyPress = (window.event) ? event.keyCode : e.keyCode;		/* 37 = prev, 39 = next */
			if (keyPress == 39) {
				if ($('moreSlide') && mailPreview != true) {
					var loc = $('moreSlide').get('href');
					if (loc != '#') {
						document.location.href = loc;
					} else {
						showLastSlide();
					}
				}
			} else if (keyPress == 37) {
				if ($('lessSlide') && mailPreview != true) document.location.href = $('lessSlide').get('href');
			}
		}

		var keyPolling = true;
		document.onkeyup = keyCheck;
		
		/* Timer to hide slide buttons with animation */
		var buttons = $$('.slideButton');
		
		if (buttons.length > 0) {
			var currentCounter = new Hash({counter: 0});

			var simpleTimer = function() {
				var currentTime = this.counter++;
				if (currentTime == 3) {
					if (buttons[0].getStyle('visibility') == 'visible')
						buttons.fade('out');
					$clear(buttonTimer);
				}
			}

			var buttonTimer = simpleTimer.periodical(1000, currentCounter);

			/* Show slide buttons & reset timer*/
			var showButtons = function() {
				buttons.fade('show');
				if ($chk(buttonTimer))
					$clear(buttonTimer);
				currentCounter.set('counter', 0);
				buttonTimer = simpleTimer.periodical(1000, currentCounter);
			}
			
			/* Delay the mouse button triggers for IE and Safari 
			 * Temporarily disabled */
			//var delay = function() { attachMouseTrigger(); };
			//setTimeout(delay, 1000);
				 
			//function attachMouseTrigger() {
				$('slide').addEvent('mousemove', showButtons.bindWithEvent());
			//}

			/* Inject Google Ad */
			//$('contextualContent').inject($('contextual'));

		}
		
		/* Last Slide */
		$('moreSlide').addEvent('click', function(e) {
			showLastSlide(e);
		});

		function showLastSlide(e) {
			if ($('lastSlideLayer')) {
				if (e) e.stop();
				$('lastSlideLayerBack').setStyle('display', 'block');
				$('lastSlideLayer').setStyle('display', 'block');
			}
		}

		/* Tip Bar */		
		$$('.tipCloseLink').addEvent('click', function(e) {
			e.stop();
			this.getParent().getParent().fade('out');
		});
		
		/* Add This */		
		$('shareLink').addEvent('click', function(e) {
			e.stop();
			$('shareBar').fade('0.75');
		});

		/* Save Scrapbook Tip When Not Logged In */
		if ($('save')) {
			$('scrap').getPrevious('a').addEvent('click', function(e) {
				$('save').fade('0.75');
			});
		}
		
		/* Catalog */
		if ($('catalogLink')) {
			$('catalogLink').addEvent('click', function(e) {
				e.stop();
				keyPolling = false;

				$('slideLayer').setStyle('display', 'block');
				$('catalogContainer').setStyle('display','block');
				$('catalog').setStyle('display','block');
			});

			$('catalogSubmit').addEvent('click', function(e) {
				e.stop();
				$('catalogForm').set('send', {
					onSuccess: function(response) {
						$('catalog').setStyle('display', 'none');
						$('catalogSuccess').setStyle('display', 'block');
					}
				});
				$('catalogForm').send();
				keyPolling = true;
			});

			$$('.closeForm').addEvent('click', function(e) {
				$('catalogContainer').setStyle('display', 'none');
				$('slideLayer').setStyle('display', 'none');
				$('catalogSuccess').setStyle('display', 'none');
				keyPolling = true;
			});
		}
		
		/* Contact ME! */
		
		/* Catalog */
		if ($('contactmeLink')) {
			$('contactmeLink').addEvent('click', function(e) {
				e.stop();
				keyPolling = false;

				$('slideLayer').setStyle('display', 'block');
				$('contactmeContainer').setStyle('display','block');
				$('contactme').setStyle('display','block');
			});

			$('contactmeSubmit').addEvent('click', function(e) {
				e.stop();
				$('contactmeForm').set('send', {
					onSuccess: function(response) {
						$('contactme').setStyle('display', 'none');
						$('contactmeSuccess').setStyle('display', 'block');
					}
				});
				$('contactmeForm').send();
				keyPolling = true;
			});

			$$('.closeForm').addEvent('click', function(e) {
				$('contactmeContainer').setStyle('display', 'none');
				$('slideLayer').setStyle('display', 'none');
				$('contactmeSuccess').setStyle('display', 'none');
				keyPolling = true;
			});
		}
		
		/* I'm lovin' it */
		$('loveLink').addEvent('click', function(e) {
			e.stop();
			
			if (this.hasClass('loved'))
				return;
			
			try {
				pageTracker._trackEvent('Slide', 'Love', this.getElement('a').get('href'));
			} catch(err){
			}
			
			var loveAdd = new Request.HTML({url: document.location.href + '/love'}).post();
			var target = this.getElement('label');
			var counter = parseInt(target.get('html'));
			target.set('html', counter + 1);
			
			this.addClass('loved');
		});
	}

		
	/* [SHOPS]	*/
	
	/* BRAND SHOP GRID */
	if ($('brandShopGrid')) {

		var shopThumbs = $$('.shopMore a');
		var shopThumbExtends = $$('.shopThumbExtend');
		
		shopThumbs.addEvent('click', function(e) {
			e.stop();
			index = shopThumbs.indexOf(this);
			shopThumbExtends[index].setStyle('display','block');
		});
		
		$$('.shopClose').addEvent('click', function(e) {
			e.stop();
			this.getParent().setStyle('display','none');
		});
		
		if ($('refineSearch') && $('refineSearch').get('class') != 'active') {
			$('refineSearch').addEvent('click', function(e) {
				e.stop();
				$('layerRefineSearch').setStyle('display','block');
			});
		
			$('searchClose').addEvent('click', function(e) {
				e.stop();
				$('layerRefineSearch').setStyle('display','none');
			});
		}
		
	}
	
	
	/* [SHOP MAP] */
	
	if ($('shopMap')) {
		
		window.addEvent("unload", function(){
			GUnload();
		}); 
		 
		if (GBrowserIsCompatible()) {

			var map = new GMap2($('shopMap'));
			var index = 0;
			map.setCenter(new GLatLng(52.2, 5.3), 8);
			map.addControl(new GSmallMapControl());
			//map.addControl(new GMapTypeControl());
			
			var baseIcon = new GIcon(G_DEFAULT_ICON);
			baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
			baseIcon.iconSize = new GSize(20, 34);
			baseIcon.shadowSize = new GSize(37, 34);
			baseIcon.iconAnchor = new GPoint(9, 34);
			baseIcon.infoWindowAnchor = new GPoint(9, 2);

			/* BUILD MAP */
			shops['locations'].each(function(loc) {
				
				var letter = String.fromCharCode("A".charCodeAt(0) + index);
				var letteredIcon = new GIcon(baseIcon);
				letteredIcon.image = "http://www.google.com/mapfiles/marker" + letter + ".png";
				markerOptions = { icon:letteredIcon };
			 
				var marker = new GMarker(new GLatLng(loc['lat'], loc['long']),markerOptions);
				GEvent.addListener(marker,'mouseover', function() {
					marker.openInfoWindowTabsHtml(
						[
							new GInfoWindowTab(
								loc['tab1label'],
								loc['tab1content']
							)
						]
					);
				});

				map.addOverlay(marker);
				index++;
				
			});
		}

	}
	
});


/* [USER LOGIN / COOKIE - ZEEKAT] */
	
var lieverData = {}

function update_user_info() {
	lieverData.login = Cookie.read("login");
	
	var p = Cookie.read("photos")
	lieverData.photos = p ? p.split(',') : []

	var m = Cookie.read("matches")
	lieverData.matches = m ? m.split(',') : []
	
	var loginLink = $("login")
	var registerLink = $('registreren');
	var mlink = $("matches")
	var plink = $("photos")
  if (lieverData.matches && lieverData.matches.length) {
		mlink.href = "/"+ locale + "/" + category_string +"/temporary_scrapbooks/tips" 
		mlink.firstChild.data = lieverData.matches.length + " nieuw!"
	}  else {
		mlink.firstChild.data = ""
	}
	if (lieverData.login) {
		mlink.href = "/"+ locale + "/" + category_string +"/scrapbooks/" + lieverData.login + "/tips"
		registerLink.set('html','uitloggen');
		registerLink.href = "/logout"
		
		$('message').set('html', 'Welkom terug, ');
		loginLink.set('html', lieverData.login);
		loginLink.set('href', "/"+ locale + "/" + category_string +"/scrapbooks/" + lieverData.login);

	}  else {
	
	}
	
	if (lieverData.photos.length > 0) {
		plink.firstChild.data = "(" + lieverData.photos.length + ")"
	} else {
		plink.firstChild.data = ""
	}

	if (!$('content')) return

	$('content').getElements(".star").forEach(function(t) {
		var id = t.id.replace(/^[a-z]+_/,"")
		if (!id) return;

		var included = lieverData.photos.filter(function(e) { return e == id }).length > 0
    
		if (false){//included) {
			t.className = "star marked"
			
			if (t.lastChild) t.lastChild.data = "Bewaard"
			} else {
				t.className = "star"
			}
	})
}

function scrapbook_toggle(photo_id,reload) {
	if (lieverData.photos.filter(function(e) { return e == photo_id }).length) {
		scrapbook_remove(photo_id,!reload)
	}  else {
		scrapbook_add(photo_id,!reload)
  }
}

function scrapbook_remove(photo_id,dont_reload) {
	if (lieverData.login) {
		var r = new Request({
			url: "/"+ locale + "/" + category_string +"/scrapbooks/remove?photo_id="+photo_id,
			onComplete: function (transport) {
				if (dont_reload) {
					update_user_info()
					$('star_'+photo_id).className = "star";
					$('star_'+photo_id).innerHTML = transport;
				} else {
					document.location.reload()
				}
			}
		})
		r.send()
	} else {
		// no user yet, store photos in cookies
		if (!lieverData.photos) {
			lieverData.photos = []
		} else {
			lieverData.photos = lieverData.photos.filter(function(e) { return e != photo_id })
			Cookie.write("photos", lieverData.photos.join(","), { path: "/" })
			scrapbook_update_matches(photo_id, dont_reload)
		}
	}
}

function scrapbook_update_matches(photo_id, dont_reload) {
  (new Request({
    url: "/" + locale + "/" + category_string + "/temporary_scrapbooks",
    onComplete: function () {
      if (dont_reload) {
        update_user_info();
      } else {
        document.location.reload()
      }
    }
  })).send()
}

function scrapbook_add(photo_id, dont_reload) {
	if (lieverData.login) {
		var r = new Request({
			url: "/" + locale + "/" + category_string +"/scrapbooks/add?photo_id="+photo_id,
			onComplete: function (transport) {
				if (dont_reload) {
					update_user_info()
					$('star_'+photo_id).className = "star marked";
					$('star_'+photo_id).innerHTML = transport;
				} else {
					document.location.reload()
				}
			}
		})
		r.send()
	} else {
		// no user yet, store photos in cookies
		if (lieverData.photos.filter(function(e) { return e == photo_id }).length == 0) {
			Cookie.write("photos", (lieverData.photos.length > 0 ? lieverData.photos + "," + photo_id : photo_id), { path: "/" } )
			scrapbook_update_matches(photo_id, dont_reload)
		}
	}
}

function switchRssLink(name) {
	var newlink
	if ($("rssLink").href.indexOf(name) > -1) {
		newlink = $("rssLink").href.replace(name,"").replace(/\++/g,"+").replace(/(\+\/|\/\+)/g,"/")
		if (newlink.indexOf("//list.rss") > -1)
			newlink = "#"
		} else {
			newlink = $("rssLink").href
			if (newlink.indexOf("#") > -1) {
				newlink = "/"+name+"/list.rss"
			} else {
				newlink = newlink.replace(/\/list.rss$/,"+" + name + "/list.rss")
			}
		}
	$("rssLink").href = newlink
}

window.addEvent('domready', update_user_info);


/**
 * Autocompleter
 *
 * http://digitarald.de/project/autocompleter/
 *
 * @version		1.1.2
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */

var Autocompleter = new Class({

	Implements: [Options, Events],

	options: {/*
		onOver: $empty,
		onSelect: $empty,
		onSelection: $empty,
		onShow: $empty,
		onHide: $empty,
		onBlur: $empty,
		onFocus: $empty,*/
		minLength: 3,
		markQuery: true,
		width: 'inherit',
		maxChoices: 10,
		injectChoice: null,
		customChoices: null,
		emptyChoices: null,
		visibleChoices: true,
		className: 'autocompleter-choices',
		zIndex: 42,
		delay: 200,
		observerOptions: {},
		fxOptions: {},

		autoSubmit: false,
		overflow: false,
		overflowMargin: 25,
		selectFirst: false,
		filter: null,
		filterCase: false,
		filterSubset: false,
		forceSelect: false,
		selectMode: true,
		choicesMatch: null,

		multiple: false,
		separator: ', ',
		separatorSplit: /\s*[,;]\s*/,
		autoTrim: false,
		allowDupes: false,

		cache: true,
		relative: false
	},

	initialize: function(element, options) {
		this.element = $(element);
		this.setOptions(options);
		this.build();
		this.observer = new Observer(this.element, this.prefetch.bind(this), $merge({
			'delay': this.options.delay
		}, this.options.observerOptions));
		this.queryValue = null;
		if (this.options.filter) this.filter = this.options.filter.bind(this);
		var mode = this.options.selectMode;
		this.typeAhead = (mode == 'type-ahead');
		this.selectMode = (mode === true) ? 'selection' : mode;
		this.cached = [];
	},

	/**
	 * build - Initialize DOM
	 *
	 * Builds the html structure for choices and appends the events to the element.
	 * Override this function to modify the html generation.
	 */
	build: function() {
		if ($(this.options.customChoices)) {
			this.choices = this.options.customChoices;
		} else {
			this.choices = new Element('ul', {
				'class': this.options.className,
				'styles': {
					'zIndex': this.options.zIndex
				}
			}).inject(document.body);
			this.relative = false;
			if (this.options.relative) {
				this.choices.inject(this.element, 'after');
				this.relative = this.element.getOffsetParent();
			}
			this.fix = new OverlayFix(this.choices);
		}
		if (!this.options.separator.test(this.options.separatorSplit)) {
			this.options.separatorSplit = this.options.separator;
		}
		this.fx = (!this.options.fxOptions) ? null : new Fx.Tween(this.choices, $merge({
			'property': 'opacity',
			'link': 'cancel',
			'duration': 200
		}, this.options.fxOptions)).addEvent('onStart', Chain.prototype.clearChain).set(0);
		this.element.setProperty('autocomplete', 'off')
			.addEvent((Browser.Engine.trident || Browser.Engine.webkit) ? 'keydown' : 'keypress', this.onCommand.bind(this))
			.addEvent('click', this.onCommand.bind(this, [false]))
			.addEvent('focus', this.toggleFocus.create({bind: this, arguments: true, delay: 100}))
			.addEvent('blur', this.toggleFocus.create({bind: this, arguments: false, delay: 100}));
	},

	destroy: function() {
		if (this.fix) this.fix.destroy();
		this.choices = this.selected = this.choices.destroy();
	},

	toggleFocus: function(state) {
		this.focussed = state;
		if (!state) this.hideChoices(true);
		this.fireEvent((state) ? 'onFocus' : 'onBlur', [this.element]);
	},

	onCommand: function(e) {
		if (!e && this.focussed) return this.prefetch();
		if (e && e.key && !e.shift) {
			switch (e.key) {
				case 'enter':
					if (this.element.value != this.opted) return true;
					if (this.selected && this.visible) {
						this.choiceSelect(this.selected);
						return !!(this.options.autoSubmit);
					}
					break;
				case 'up': case 'down':
					if (!this.prefetch() && this.queryValue !== null) {
						var up = (e.key == 'up');
						this.choiceOver((this.selected || this.choices)[
							(this.selected) ? ((up) ? 'getPrevious' : 'getNext') : ((up) ? 'getLast' : 'getFirst')
						](this.options.choicesMatch), true);
					}
					return false;
				case 'esc': case 'tab':
					this.hideChoices(true);
					break;
			}
		}
		return true;
	},

	setSelection: function(finish) {
		var input = this.selected.inputValue, value = input;
		var start = this.queryValue.length, end = input.length;
		if (input.substr(0, start).toLowerCase() != this.queryValue.toLowerCase()) start = 0;
		if (this.options.multiple) {
			var split = this.options.separatorSplit;
			value = this.element.value;
			start += this.queryIndex;
			end += this.queryIndex;
			var old = value.substr(this.queryIndex).split(split, 1)[0];
			value = value.substr(0, this.queryIndex) + input + value.substr(this.queryIndex + old.length);
			if (finish) {
				var tokens = value.split(this.options.separatorSplit).filter(function(entry) {
					return this.test(entry);
				}, /[^\s,]+/);
				if (!this.options.allowDupes) tokens = [].combine(tokens);
				var sep = this.options.separator;
				value = tokens.join(sep) + sep;
				end = value.length;
			}
		}
		this.observer.setValue(value);
		this.opted = value;
		if (finish || this.selectMode == 'pick') start = end;
		this.element.selectRange(start, end);
		this.fireEvent('onSelection', [this.element, this.selected, value, input]);
	},

	showChoices: function() {
		var match = this.options.choicesMatch, first = this.choices.getFirst(match);
		this.selected = this.selectedValue = null;
		if (this.fix) {
			var pos = this.element.getCoordinates(this.relative), width = this.options.width || 'auto';
			this.choices.setStyles({
				'left': pos.left,
				'top': pos.bottom,
				'width': (width === true || width == 'inherit') ? pos.width : width
			});
		}
		if (!first) return;
		if (!this.visible) {
			this.visible = true;
			this.choices.setStyle('display', '');
			if (this.fx) this.fx.start(1);
			this.fireEvent('onShow', [this.element, this.choices]);
		}
		if (this.options.selectFirst || this.typeAhead || first.inputValue == this.queryValue) this.choiceOver(first, this.typeAhead);
		var items = this.choices.getChildren(match), max = this.options.maxChoices;
		var styles = {'overflowY': 'hidden', 'height': ''};
		this.overflown = false;
		if (items.length > max) {
			var item = items[max - 1];
			styles.overflowY = 'scroll';
			styles.height = item.getCoordinates(this.choices).bottom;
			this.overflown = true;
		};
		this.choices.setStyles(styles);
		this.fix.show();
		if (this.options.visibleChoices) {
			var scroll = document.getScroll(),
			size = document.getSize(),
			coords = this.choices.getCoordinates();
			if (coords.right > scroll.x + size.x) scroll.x = coords.right - size.x;
			if (coords.bottom > scroll.y + size.y) scroll.y = coords.bottom - size.y;
			window.scrollTo(Math.min(scroll.x, coords.left), Math.min(scroll.y, coords.top));
		}
	},

	hideChoices: function(clear) {
		if (clear) {
			var value = this.element.value;
			if (this.options.forceSelect) value = this.opted;
			if (this.options.autoTrim) {
				value = value.split(this.options.separatorSplit).filter($arguments(0)).join(this.options.separator);
			}
			this.observer.setValue(value);
		}
		if (!this.visible) return;
		this.visible = false;
		if (this.selected) this.selected.removeClass('autocompleter-selected');
		this.observer.clear();
		var hide = function(){
			this.choices.setStyle('display', 'none');
			this.fix.hide();
		}.bind(this);
		if (this.fx) this.fx.start(0).chain(hide);
		else hide();
		this.fireEvent('onHide', [this.element, this.choices]);
	},

	prefetch: function() {
		var value = this.element.value, query = value;
		if (this.options.multiple) {
			var split = this.options.separatorSplit;
			var values = value.split(split);
			var index = this.element.getSelectedRange().start;
			var toIndex = value.substr(0, index).split(split);
			var last = toIndex.length - 1;
			index -= toIndex[last].length;
			query = values[last];
		}
		if (query.length < this.options.minLength) {
			this.hideChoices();
		} else {
			if (query === this.queryValue || (this.visible && query == this.selectedValue)) {
				if (this.visible) return false;
				this.showChoices();
			} else {
				this.queryValue = query;
				this.queryIndex = index;
				if (!this.fetchCached()) this.query();
			}
		}
		return true;
	},

	fetchCached: function() {
		return false;
		if (!this.options.cache
			|| !this.cached
			|| !this.cached.length
			|| this.cached.length >= this.options.maxChoices
			|| this.queryValue) return false;
		this.update(this.filter(this.cached));
		return true;
	},

	update: function(tokens) {
		this.choices.empty();
		this.cached = tokens;
		var type = tokens && $type(tokens);
		if (!type || (type == 'array' && !tokens.length) || (type == 'hash' && !tokens.getLength())) {
			(this.options.emptyChoices || this.hideChoices).call(this);
		} else {
			if (this.options.maxChoices < tokens.length && !this.options.overflow) tokens.length = this.options.maxChoices;
			tokens.each(this.options.injectChoice || function(token){
				var choice = new Element('li', {'html': this.markQueryValue(token)});
				choice.inputValue = token;
				this.addChoiceEvents(choice).inject(this.choices);
			}, this);
			this.showChoices();
		}
	},

	choiceOver: function(choice, selection) {
		if (!choice || choice == this.selected) return;
		if (this.selected) this.selected.removeClass('autocompleter-selected');
		this.selected = choice.addClass('autocompleter-selected');
		this.fireEvent('onSelect', [this.element, this.selected, selection]);
		if (!this.selectMode) this.opted = this.element.value;
		if (!selection) return;
		this.selectedValue = this.selected.inputValue;
		if (this.overflown) {
			var coords = this.selected.getCoordinates(this.choices), margin = this.options.overflowMargin,
				top = this.choices.scrollTop, height = this.choices.offsetHeight, bottom = top + height;
			if (coords.top - margin < top && top) this.choices.scrollTop = Math.max(coords.top - margin, 0);
			else if (coords.bottom + margin > bottom) this.choices.scrollTop = Math.min(coords.bottom - height + margin, bottom);
		}
		if (this.selectMode) this.setSelection();
	},

	choiceSelect: function(choice) {
		if (choice) this.choiceOver(choice);
		this.setSelection(true);
		this.queryValue = false;
		this.hideChoices();
	},

	filter: function(tokens) {
		return (tokens || this.tokens).filter(function(token) {
			return this.test(token);
		}, new RegExp(((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp(), (this.options.filterCase) ? '' : 'i'));
	},

	/**
	 * markQueryValue
	 *
	 * Marks the queried word in the given string with <span class="autocompleter-queried">*</span>
	 * Call this i.e. from your custom parseChoices, same for addChoiceEvents
	 *
	 * @param		{String} Text
	 * @return		{String} Text
	 */
	markQueryValue: function(str) {
		return (!this.options.markQuery || !this.queryValue) ? str
			: str.replace(new RegExp('(' + ((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp() + ')', (this.options.filterCase) ? '' : 'i'), '<span class="autocompleter-queried">$1</span>');
	},

	/**
	 * addChoiceEvents
	 *
	 * Appends the needed event handlers for a choice-entry to the given element.
	 *
	 * @param		{Element} Choice entry
	 * @return		{Element} Choice entry
	 */
	addChoiceEvents: function(el) {
		return el.addEvents({
			'mouseover': this.choiceOver.bind(this, [el]),
			'click': this.choiceSelect.bind(this, [el])
		});
	}
});

var OverlayFix = new Class({

	initialize: function(el) {
		if (Browser.Engine.trident) {
			this.element = $(el);
			this.relative = this.element.getOffsetParent();
			this.fix = new Element('iframe', {
				'frameborder': '0',
				'scrolling': 'no',
				'src': 'javascript:false;',
				'styles': {
					'position': 'absolute',
					'border': 'none',
					'display': 'none',
					'filter': 'progid:DXImageTransform.Microsoft.Alpha(opacity=0)'
				}
			}).inject(this.element, 'after');
		}
	},

	show: function() {
		if (this.fix) {
			var coords = this.element.getCoordinates(this.relative);
			delete coords.right;
			delete coords.bottom;
			this.fix.setStyles($extend(coords, {
				'display': '',
				'zIndex': (this.element.getStyle('zIndex') || 1) - 1
			}));
		}
		return this;
	},

	hide: function() {
		if (this.fix) this.fix.setStyle('display', 'none');
		return this;
	},

	destroy: function() {
		if (this.fix) this.fix = this.fix.destroy();
	}

});

Element.implement({

	getSelectedRange: function() {
		if (!Browser.Engine.trident) return {start: this.selectionStart, end: this.selectionEnd};
		var pos = {start: 0, end: 0};
		var range = this.getDocument().selection.createRange();
		if (!range || range.parentElement() != this) return pos;
		var dup = range.duplicate();
		if (this.type == 'text') {
			pos.start = 0 - dup.moveStart('character', -100000);
			pos.end = pos.start + range.text.length;
		} else {
			var value = this.value;
			var offset = value.length - value.match(/[\n\r]*$/)[0].length;
			dup.moveToElementText(this);
			dup.setEndPoint('StartToEnd', range);
			pos.end = offset - dup.text.length;
			dup.setEndPoint('StartToStart', range);
			pos.start = offset - dup.text.length;
		}
		return pos;
	},

	selectRange: function(start, end) {
		if (Browser.Engine.trident) {
			var diff = this.value.substr(start, end - start).replace(/\r/g, '').length;
			start = this.value.substr(0, start).replace(/\r/g, '').length;
			var range = this.createTextRange();
			range.collapse(true);
			range.moveEnd('character', start + diff);
			range.moveStart('character', start);
			range.select();
		} else {
			this.focus();
			this.setSelectionRange(start, end);
		}
		return this;
	}

});

var Observer = new Class({

	Implements: [Options, Events],

	options: {
		periodical: false,
		delay: 1000
	},

	initialize: function(el, onFired, options){
		this.element = $(el) || $$(el);
		this.addEvent('onFired', onFired);
		this.setOptions(options);
		this.bound = this.changed.bind(this);
		this.resume();
	},

	changed: function() {
		var value = this.element.get('value');
		if ($equals(this.value, value)) return;
		this.clear();
		this.value = value;
		this.timeout = this.onFired.delay(this.options.delay, this);
	},

	setValue: function(value) {
		this.value = value;
		this.element.set('value', value);
		return this.clear();
	},

	onFired: function() {
		this.fireEvent('onFired', [this.value, this.element]);
	},

	clear: function() {
		$clear(this.timeout || null);
		return this;
	},

	pause: function(){
		if (this.timer) $clear(this.timer);
		else this.element.removeEvent('keyup', this.bound);
		return this.clear();
	},

	resume: function(){
		this.value = this.element.get('value');
		if (this.options.periodical) this.timer = this.changed.periodical(this.options.periodical, this);
		else this.element.addEvent('keyup', this.bound);
		return this;
	}

});

var $equals = function(obj1, obj2) {
	return (obj1 == obj2 || JSON.encode(obj1) == JSON.encode(obj2));
};

/* compatibility */

Autocompleter.Base = Autocompleter;

Autocompleter.Request = new Class({

	Extends: Autocompleter,

	options: {/*
		indicator: null,
		indicatorClass: null,
		onRequest: $empty,
		onComplete: $empty,*/
		postData: {},
		ajaxOptions: {},
		postVar: 'value'

	},

	query: function(){
		var data = $unlink(this.options.postData) || {};
		data[this.options.postVar] = this.queryValue;
		var indicator = $(this.options.indicator);
		if (indicator) indicator.setStyle('display', '');
		var cls = this.options.indicatorClass;
		if (cls) this.element.addClass(cls);
		this.fireEvent('onRequest', [this.element, this.request, data, this.queryValue]);
		this.request.send({'data': data});
	},

	/**
	 * queryResponse - abstract
	 *
	 * Inherated classes have to extend this function and use this.parent()
	 */
	queryResponse: function() {
		var indicator = $(this.options.indicator);
		if (indicator) indicator.setStyle('display', 'none');
		var cls = this.options.indicatorClass;
		if (cls) this.element.removeClass(cls);
		return this.fireEvent('onComplete', [this.element, this.request]);
	}

});

Autocompleter.Request.JSON = new Class({

	Extends: Autocompleter.Request,

	initialize: function(el, url, options) {
		this.parent(el, options);
		this.request = new Request.JSON($merge({
			'url': url,
			'method': 'get',
			'link': 'cancel'
		}, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this));
	},

	queryResponse: function(response) {
		this.parent();
		this.update(response);
	}

});

Autocompleter.Request.HTML = new Class({

	Extends: Autocompleter.Request,

	initialize: function(el, url, options) {
		this.parent(el, options);
		this.request = new Request.HTML($merge({
			'url': url,
			'link': 'cancel',
			'update': this.choices
		}, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this));
	},

	queryResponse: function(tree, elements) {
		this.parent();
		if (!elements || !elements.length) {
			this.hideChoices();
		} else {
			this.choices.getChildren(this.options.choicesMatch).each(this.options.injectChoice || function(choice) {
				var value = choice.innerHTML;
				choice.inputValue = value;
				this.addChoiceEvents(choice.set('html', this.markQueryValue(value)));
			}, this);
			this.showChoices();
		}

	}

});

/* compatibility */

Autocompleter.Ajax = {
	Base: Autocompleter.Request,
	Json: Autocompleter.Request.JSON,
	Xhtml: Autocompleter.Request.HTML
};

window.addEvent('domready', function() {
    new Autocompleter.Request.JSON('search', '/' + locale + '/' + category_string + '/search/suggest', {
        'postVar': 'q'
    });
 
});
