var FilterSearch = new Class({
	Implements: [Options, Events],
	
	options: {
		filteredClass: 'filtered',
		matchedClass: 'matched',
		activeClass: 'active',
		highlightClass: 'highlight'
	},
	
	initialize: function(input, list, options){
		this.setOptions(options);
		this.list = $(list).addEvents({
			mouseover: this.handleMouse.bind(this),
			click: this.handleClick.bind(this)
		});
		this.input = $(input).addEvents({
			keydown: this.navigate.bind(this),
			keypress: this.filter.create({bind: this, delay: 1}),
			blur: this.end.bind(this),
			focus: this.start.bind(this)
		});
		this.loadItems();
		this.filter();
	},
	
	loadItems: function() {
		this.cache = this.list.getElements('li').map(function(item){
			return {
				element: item,
				string: item.get('text')
			};
		});
	},
	
	handleClick: function(event){
		if (event.target.hasClass(this.options.matchedClass)) this.select(event.target);
	},

	handleMouse: function(event) {
		var target = $(event.target);
		if (target.hasClass(this.options.matchedClass)){
			this.activate(target);
		}
	},
	
	navigate: function(event) {
		if (!this.active) return;
		switch (event.key){
			case 'up': case 'down':
				var element = this.active[(event.key == 'up') ? 'getPrevious' : 'getNext']('.' + this.options.matchedClass);
				if (element) this.activate(element);
			break;
			case 'enter': this.select(this.active);
		}
	},
	
	select: function(element){
		var text = $(element).get('text');
		this.input.set('value', text);
		this.filter();
		this.input.blur();
		this.fireEvent('onSelect', text);
	},
	
	start: function(){
		this.fireEvent('onStart');
	},
	
	end: function(){
		this.fireEvent('onEnd');
	},
	
	activate: function(item) {
		var klass = this.options.activeClass;
		if (item){
			if (this.active) this.active.removeClass(klass);
			this.active = $(item).addClass(klass);
		} else if (this.active) {
			this.active.removeClass(klass);
			this.active = null;
		}
	},
	
	filter: function() {
		var search = this.input.get('value').replace(/\W/g, '').toLowerCase();
		if (this.currentFilter == search) return;
		this.currentFilter = search;
		// console.profile('filter');
		if (!search) {
			this.list.removeClass(this.options.filteredClass);
			this.cache.each(function(item){
				item.element.addClass(this.options.matchedClass);
			}, this);
		} else {
			this.list.addClass(this.options.filteredClass);
			var regexp = new RegExp('[' + search + ']', 'gi');
			var span = '<span class=' + this.options.highlightClass + '>';
			this.cache.each(function(item){
				var remaining = search;
				var result = item.string.replace(regexp, function(match){
					if(!remaining) return match;
					if (remaining[0] == match.toLowerCase()){
						match = span + match + '</span>';
						remaining = remaining.substr(1);
					}
					return match;
				});
				if (remaining) {
					item.element.removeClass(this.options.matchedClass);
				} else {
					item.element.addClass(this.options.matchedClass)
						.set('html', result);
				}
			}, this);
		}
		if (!this.active || !this.active.hasClass(this.options.matchedClass))
			this.activate(this.list.getElement('.' + this.options.matchedClass));
		// console.profileEnd('filter');
	}
});