/**
 * LiveSearch.js
 * Copyright (c) Fluid Creativity, 2009
 * 
 * Implements a live search
 */

var LiveSearch = new Class({

	Implements: [Options, Events],
	
	url: null,
	searchForm: null,
	searchInput: null,
	resultsPanel: null,
	isOpen: false,
	timer: null,
	
	options: {
		url: '/ajax/search',
		transition: 'quad:out',
		fadeDuration: 400,
		searchDelay: 1000,
		closeLinkId: 'liveSearchClose',
		minCharLength: 0
	},

	initialize: function(searchForm, options) {
		this.searchForm = $(searchForm);
		this.setOptions(options);
		this.setupControls();
	},
	
	setupControls: function() {
		if (!$defined(this.searchForm)) return;
		
		// Get input box
		this.searchInput = this.searchForm.getElement('input[type=text]');
		
		// Get search URL
		this.url = this.options.url;
		if (!this.url) this.url = this.searchForm.get('action');
		
		// Get result panel
		this.resultsPanel = $(this.options.resultsPanel);
		if (!this.resultsPanel) this.resultsPanel = new Element('div').inject(this.searchForm);
		this.resultsPanel.setStyle('height', 0);

		// Prevent default events
		this.resultsPanel.addEvent('click', function(e) {
			e.stopPropagation()
		});
		
		this.searchForm.addEvents({
			'submit': function(e) {
				e.stop();
				this.getResults();
			}.bind(this),
			'click': function(e) {
				e.stopPropagation();
			}
		});

		// Attach events
		this.searchInput.addEvent('keyup', function(e) {
			switch (e.key) {			
				case 'esc':
					this.hideResults(e);
				break;
				
				default:
					if (!e.alt && !e.meta) {
						if (this.timer) this.timer = $clear(this.timer);
						
						if (this.searchInput.value != this.searchInput.defaultValue && this.searchInput.value.length > 0) {
							this.timer = this.getResults.bind(this).delay(this.options.searchDelay);
						} else {
							this.timer = this.hideResults.bind(this).delay(this.options.searchDelay);
						}
					}
				break;
			}
		}.bindWithEvent(this));

		this.dismantle = this.hideResults.bindWithEvent(this);
	},
	
	getResults: function() {
		// Get input value
		var searchText = this.searchInput.value;
		
		// Do search if more than minimum characters
		if (searchText != this.searchInput.defaultValue && searchText.length >= this.options.minCharLength) {
			// Add loading icon
			this.searchForm.getElement('fieldset').addClass('loading');
			
			// Request HTML from AJAX feed
			new Request.HTML({
				url: this.url,
				update: this.resultsPanel,
				autoCancel: true,
				onComplete: function() {
					var closeLink = this.resultsPanel.getElementById(this.options.closeLinkId);
					
					if (closeLink) {
						closeLink.addEvent('click', function(e) {
							e.stop();
							this.hideResults();
						}.bindWithEvent(this));
					}
				
					this.searchForm.getElement('fieldset').removeClass('loading');
					this.showResults.bind(this)();
				}.bind(this)
			}).get({ 'search': searchText });
		}
	},
	
	showResults: function() {
		// Setup global events
		if (!this.isOpen) {
			document.addEvent('click', this.dismantle);
			document.addEvent('keypress', this.dismantle);
			
			this.isOpen = true;
		}

		// Calculate full height
		var fullHeight = this.resultsPanel.getFullHeight();
		
		// Tween the height to the new value
		new Fx.Tween(this.resultsPanel, {
			property: 'height',
			link: 'cancel',
			transition: this.options.transition,
			duration: this.options.fadeDuration
		}).start(fullHeight);
	},
	
	hideResults: function(e) {
		if (!this.isOpen || ($defined(e) && e.type == 'keypress' && e.key != 'esc')) return;
		this.isOpen = false;
		
		// Remove global events
		document.removeEvent('clck', this.dismantle);
		document.removeEvent('keypress', this.dismantle);
		
		// Removing loading icon
		this.searchForm.getElement('fieldset').removeClass('loading');

		// Empty search panel and hide
		new Fx.Tween(this.resultsPanel, {
			property: 'height',
			link: 'cancel',
			transition: this.options.transition,
			duration: this.options.fadeDuration,
			onComplete: function(e) {
				this.resultsPanel.empty();
			}.bind(this)
		}).start(0);
	}
});
