/*
Class: Aurora.Suggest
*/
Aurora.Suggest = new Class({
	
	Implements: Options,
	
	options: {
		
		target: null,
		
		parameter: null,
		
		field: null,
		
		itemQuery: 'li',
		
		minLength: 5,
		
		populateField: false,
		
		populateLabelField: false,
		populateValueField: false,
		
		highlightTerms: true,
		highlightQuery: 'a',
		
		gotoLink: false,
		
		disableBlur: false,
		
		extendOnSelect: false,
		
		left: 0,
		top: 0,
		
		onRender: null
		
	},
	
	initialize: function( target, options )
	{
		var $el = this.$el = $( target );
		
		this.setOptions( options );
		
		// Find the field
		var $field = this.$field = $el.getElement( 'input' );
		
		if ( this.options.field )
			$field = $( this.options.field );
		
		if ( !$field )
		{
			$log( 'No valid field was found for Aurora.Suggest, you must use a standard input field inside the container or supply an id as [field].' );
			return;
		}
		
		// Find results (or create it)
		var $results = this.$results = $el.getElement( '.aurora-suggest-results' );
		
		if ( !$results )
			$results = this.$results = new Element( 'div', { 'class': 'aurora-suggest-results', style: 'position: absolute;' } ).inject( $field, 'after' );
			
		$results.hide();
		
		// Activity El
		var $activity = this.$activity = $el.getElement( '.aurora-suggest-activity' );
		
		
		// Add events to field
		$field.addEvents({
			
			'keypress': (function( event ) {
				
				// Specific keys
				if ( event.key == 'esc' )
					return this.hide();
				
				if ( event.key == 'enter' )
				{
					if ( this._lastFocused )
						this._lastFocused.fireEvent( 'mousedown' );
					
					this.hide();
					
					return;
				}
				
				var ci = null;
				
				if ( this.results )
					ci = this.results.indexOf( this._lastFocused );
				
				if ( event.key == 'up' )
				{
					event.stop();
					
					if ( this.results && this.results[ ci - 1 ] )
						this.focusItem( this.results[ ci - 1 ] );
					
					return;
				}
				
				if ( event.key == 'down' )
				{
					event.stop();
					
					if ( !this._lastFocused )
					{
						var firstItem = this.results[0];
					
						this.focusItem( firstItem );
						
						return;
					}
					
					if ( this.results && this.results[ ci + 1 ] )
						this.focusItem( this.results[ ci + 1 ] );
					
					return;
				}
			
			}.bind( this )),
			
			'keyup': (function( event ) {
			
				if ( event.key == 'esc' || event.key == 'enter' )
					return;
				
				// Search
				if ( !$field.value.trim() )
				{
					this.hide();
					return;
				}
				
				if ( this._redirecting )
					return;
				
				var searchStr = $field.value.trim(),
					visible = 0,
					firstVisible = null;
				
				if ( this._timer )
					$clear( this._timer );
				
				this._timer = (function() {
				
					this.search();
				
				}.bind( this )).delay( 250 );
			
			}.bind( this )),
			
			'blur': (function( event ) {
			
				if ( !this.options.disableBlur )
					this.hide();
			
			}.bind( this ))
		
		});
	
	},
	
	hide: function()
	{
		(function(){
			
			if ( this.$results )
				this.$results.hide();
				
			this._lastSearch = '';
			
		}).delay( 250, this );
	},
	
	search: function()
	{
		var value = this.$field.value.trim();
		
		if ( value.length < this.options.minLength )
			return;
		
		if ( value && ( this._lastSearch == value ) )
		{
			$log( 'Search string is the same.' );
			return;
		}
		
		// Reset values
		this._lastSearch = value;
		
		this._lastFocused = false;
		
		// Search
		var send = {
			path: '/' + this.options.target,
			data: {}
		}
		
		var parameter = this.$field.getProperty( 'name' );
		
		if ( this.options.parameter )
			parameter = this.options.parameter;
		
		send.data[ parameter ] = value;
		
		// Show activity
		if ( this.$activity )
			this.$activity.show();
		
		// Call action
		Aurora.loadSparkle( send )
			.then( (function( rtn ) {
				
				if ( this.$field.value.trim() != value )
					return;
				
				this.render( rtn );
			
			}.bind( this )));
	},
	
	focusItem: function( newFocus )
	{
		if ( this._lastFocused )
			this._lastFocused.removeClass( 'aurora-suggest-focused' );
		
		this._lastFocused = newFocus;
		
		if ( newFocus )
			newFocus.addClass( 'aurora-suggest-focused' );
	},
	
	render: function( results )
	{
		var $field = this.$field,
			$results = this.$results;
		
		// Hide activity
		if ( this.$activity )
			this.$activity.hide();
		
		// If we have no results, don't render anything
		if ( !results.html )
			return;
		
		// Show and position results
		$results.show();
		
		$results.position({ relativeTo: $field, position: 'bottomLeft', align: 'topLeft', offset: { x: this.options.left, y: this.options.top } });
		
		$results.set( 'html', results.html );
		
		// Reset last focused as its a brand new set of elements
		this._lastFocused = false;
		
		// Add events to items
		var results = this.results = $results.getElements( this.options.itemQuery );
		
		results.each( (function( $i ) {
			
			$i.addEvents({
			
				'mouseover': (function() {
				
					// this.focusItem( $i );
				
				}.bind( this )),
				
				'mouseout': (function() {
				
					$i.removeClass( 'aurora-suggest-focused' );
					
				}.bind( this )),
				
				'mousedown': (function(e) {
				
					// TW: Disabled for now
					// this._redirecting = true;
					
					// Populate the label hidden field (if we have one) or just use the field we are binded to
					if ( this.options.populateLabelField )
					{
						var label = $i.getElement( '.aurora-suggest-label' ).get( 'text' ),
							$labelField = this.$labelField = this.$el.getElement( '[name=' + this.options.populateLabelField + ']' );
						
						$labelField.value = label;
						
						// Populate field
						if ( this.options.populateField )
							this.$field.value = label.clean();
					}
					
					if ( this.options.populateField )
					{
						var label = $i.get( 'text' );
						
						this.$field.value = label.clean();
						
						$log( this.$field, label );
					}
					
					// Populate the value hidden field (if we have one)
					if ( this.options.populateValueField )
					{
						var value = $i.getElement( '.aurora-suggest-value' ).get( 'text' ),
							$valueField = this.$valueField = this.$el.getElement( '[name=' + this.options.populateValueField + ']' );
						
						$valueField.value = value.clean();
					}
					
					// Onselect event
					if ( this.options.onSelect )
					{
						var value = $i.getElement( '.aurora-suggest-value' );
						
						if ( value )
						{
							if ( this.options.extendOnSelect )
								Aurora.doCallback( this.options.onSelect, [ value, this.$field ] );
							else
								Aurora.doCallback( this.options.onSelect, value );
						}
					}
					
					// Go to the first link we encounter (may want to expand this further in case we have examples with more than one link)
					if ( this.options.gotoLink )
					{
						var $link = $i;
					
						if ( $i.get( 'tag' ) != 'a' )
							$link = $i.getElement( 'a' );
						
						if ( !$link )
							return;
						
						top.location.href = $link.getProperty( 'href' );
					
					}
					
					// Make the sure last search is reflected by the current value (it may have changed)
					this._lastSearch = this.$field.value.trim();
					
					// Hide the results (since we selected something)
					if ( this.options.gotoLink || this.options.populateField || this.options.onSelect )
						if ( !this.options.disableBlur )
							this.hide();
					
				}.bind( this ))
				
			});
			
		}.bind( this )));
		
		// Add highlights
		if ( this.options.highlightTerms )
		{
			var regex = new RegExp( '(' + this._lastSearch + ')', 'gi' );
			
			$results.getElements( this.options.highlightQuery ).each( (function( $el ) {
			
				var text = $el.get( 'text' ),
					parsed = text.replace( regex, '<span class="aurora-suggest-highlight">$1</span>' );
				
				$el.set( 'html', parsed );
			
			}.bind( this )));
		}
		
		// Init Aurora Classes
		Aurora.initClasses( $results );
		
		// On Render Function
		if ( this.options.onRender )
			Aurora.doCallback( this.options.onRender, this.$el );
	
	}
	
});