// $Id: autocomplete.js 28 2010-06-10 12:35:04Z daniel15 $

/**
 * Autocomplete
 * Author: Daniel15 <dan.cx>
 */
var Autocomplete = new Class(
{
	Implements: [Options, Events],
	options: 
	{
		/*
		onSelect: $empty,
		*/
		className: 'autocomplete',
		size: 7
	},
	
	/**
	 * Initialise the autocomplete dropdown
	 */
	initialize: function(element, items, options)
	{
		this.element = $(element);
		this.element.autocomplete = 'off';
		this.items = new Hash(items);
		this.setOptions(options);
		this.build();
	},
	
	/**
	 * Build the HTML for the autocomplete
	 */
	build: function()
	{
		var menu = this.menu = new Element('select',
		{
			name: 'autocomplete',
			id: 'autocomplete',
			'class': this.options.className,
			size: this.options.size,
			events: 
			{
				click: this.selectCurrent.bind(this)
			}
		});
		
		this.menu.inject(this.element, 'after');
		
		// Connect the event handlers
		this.element.addEvents(
		{
			//click: this.show.bind(this),
			keydown: this.keydown.bind(this),
			keyup: this.populate.bind(this)
		});
		
		// Hide the autocomplete when the body is clicked
		$(document.body).addEvent('click', this.hide.bind(this));
	},
	
	/**
	 * Populate the items in the list
	 */
	populate: function()
	{			
		var currentIndex = this.menu.selectedIndex;
		var oldItem = this.menu.value;
		var search = this.element.value.toLowerCase();
		
		// Remove all the options, and re-add the matching ones
		this.menu.options.length = 0;
		// Filter out items that don't match
		this.items.filter(function(item)
		{
			return item.toLowerCase().match(search);
		}, this).each(function(item, key)
		{
			new Element('option', 
			{
				html: item,
				'value': key
			}).inject(this.menu);
		}, this);
		
		this.menu.selectedIndex = currentIndex;
		// If the old item no longer exists, set the index back to the start
		if (this.menu.value != oldItem || this.menu.selectedIndex == -1)
			this.menu.selectedIndex = 0;
	},
	
	/**
	 * Position the dropdown list at the right spot
	 */
	setPosition: function()
	{
		var pos = this.element.getPosition();
		var size = this.element.getSize();
		this.menu.setStyles(
		{
			top: pos.y + size.y,
			left: pos.x,
			width: size.x
		});
	},
	
	/**
	 * Show the autocompleter
	 */
	show: function()
	{
		this.populate();
		this.setPosition();
		this.menu.setStyle('display', 'block');
	},
	
	/**
	 * Hide the autocompleter
	 */
	hide: function()
	{
		this.menu.setStyle('display', 'none');
		this.element.value = '';
	},
	
	/**
	 * Handle key presses
	 */
	keydown: function(e)
	{
		// Make sure the autocomplete box is showing
		this.show();
		
		switch (e.key)
		{
			case 'up':
				this.previous();
				return false;
				break;
				
			case 'down':
				this.next();
				return false;
				break;
				
			case 'enter':
				this.selectCurrent();
				return false;
				break;
			
			case 'esc':
				this.hide();
				break;
		}
	},
	
	/**
	 * Move to the previous item in the list
	 */
	previous: function()
	{
		if (this.menu.selectedIndex == 0)
			this.menu.selectedIndex = this.menu.options.length - 1;
		else
			this.menu.selectedIndex--;
	},
	
	/**
	 * Move to the next item in the list
	 */
	next: function()
	{
		if (this.menu.selectedIndex == this.menu.options.length - 1)
			this.menu.selectedIndex = 0;
		else
			this.menu.selectedIndex++;
	},
	
	/**
	 * Select the current item
	 */
	selectCurrent: function()
	{
		this.element.value = '';
		this.hide();
		this.fireEvent('onSelect', [this.menu.value, this.menu.options[this.menu.selectedIndex].text]);
	}
});