/**
	Search.js 0.1
	
	Classe para injetar comportamento de search a <select>s.
	
	Pré:
		A lista de <option>s deve estar em ordem alfabética.
		
	Opções:
		id: id do <select>,  defaults to 'search'
		textId: id do elemento html (span, div, ...) que mostrara o texto de busca,  defaults to null			
		timeout: tempo (em milis) para o search expirar,  defaults para 2 segundos
*/
var Search = Class.create();
Search.prototype =
{
	initialize: function( options )
	{
		this.searchText = '';
		this.setOptions( options );
		this.setUp();
	},
	
	setOptions: function( options )
	{
		this.options = {
			id: 'search',
			textId: null,
			timeout: 2000,
			showHelp: true
		};
		Object.extend( this.options, options || {} );
	},
	
	setUp: function()
	{
		// Localiza o combo
		this.combo = $( this.options.id );
		if ( !this.combo ) {
			return;
		}

		// Carrega os textos para busca
		this.texts = [];
		for ( var i=0; i < this.combo.options.length; ++i ) {
			this.texts.push( this.readOptionText(this.combo.options[i]) );
		}
		
		if ( this.options.textId ) {
			this.textContainer = $( this.options.textId );
		}

		// Registra o listeneres de teclado
		//this.combo.onkeypress = this.onkeypress.bindAsEventListener( this );
		this.combo.onkeydown = this.onkeydown.bindAsEventListener( this );
		this.combo.onkeyup = this.onkeyup.bindAsEventListener( this );
		
		if ( this.options.showHelp ) {
			this.combo.onfocus = this.onfocus.bind(this);
			this.combo.onblur = this.onblur.bind(this);
		}
	},
	
	readOptionText: function( option )
	{
		var text = option.innerHTML.toUpperCase();
		text = text.replace( /[ÁÂÃ]/g, 'A' );
		text = text.replace( /[ÉÊ]/g,  'E' );
		text = text.replace( /Í/g,     'I' );
		text = text.replace( /[ÓÔÕ]/g, 'O' );
		text = text.replace( /ÚÜ/g,    'U' );
		text = text.replace( /Ç/g,     'C' );
		return text;
	},
	
	onkeydown: function( event )
	{
		//this.alert( event, 'down' );
		var code = event.keyCode ? event.keyCode : event.which;
		
		// Processa Backspace, Tab e Esc (backspace aqui para evitar que o IE faça back na URL)
		if ( code == 8 || code == 27 ) {
			if (code == 8) {
				// Backspace uma letra
				if ( this.searchText.length > 0 ) {
					this.setSearchText( this.searchText.substr( 0, this.searchText.length - 1 ) );
				}
				
				// Refaz o search
				this.search();
			}
			else {
				// Esc reseta a busca e seleciona o primeiro <option>
				this.setSearchText( '' );
				this.select( 0 );
			}

			// Para o evento
			return false;
		}
		
		if (code == 9) {
			// Tab limpa o texto de busca
			this.setSearchText( '' );
		}
		
		// Não foi backspace ou Esc, continua o evento
		return true;
	},
	
	onkeyup: function( event )
	{		
		//this.alert( event, 'up' );
		var code = event.keyCode ? event.keyCode : event.which;
		
		// Processa somente setas, pgup/down, home/end e letras
		if ( !(code >= 33 && code <= 40) && !this.ehLetraValida(code) ) {
			// Deixa o evento continuar
			return true;
		}

		// pgUp, pgDown, home, end e setas limpam a busca mas não alteram o <option> selecionado
		if ( code >= 33 && code <= 40 ) {
			this.setSearchText( '' );
			
			// Deixa o evento continuar
			return true;
		}
		
		// Nova letra
		var letra
		if ( code == 59 || code == 186 ) {
			letra = 'C';
		}
		else if ( code == 190 ) {
			letra = '.';
		}
		else if ( code == 109 || code == 189 ) {
			letra = '-';
		}
		else {
			letra = String.fromCharCode( code );
		}
		
		this.setSearchText( this.searchText + letra );
		
		this.search();
		return false;
	},
	
	search: function()
	{
		// Localiza
		var len = this.searchText.length;
		var idx = 0;
		for ( var i = 0; i < this.texts.length; ++i ) {
			if ( this.texts[i].substr(0,len) < this.searchText ) {
				continue;
			}
			if ( this.texts[i].substr(0,len) == this.searchText ) {
				idx = i;
			}
			break;
		}
		
		// Seleciona
		this.select( idx );

		// Seta o timeout para limpar a busca
		this.setTimeout();
	},
	
	ehLetraValida: function( code )
	{
		// espaço ç - . letras (em ordem abaixo)
		return code == 32 || (code == 59 || code == 186) || (code == 109 || code == 189) || code == 190 || (code >= 65 && code <= 90);
	},
	
	setSearchText: function( text )
	{
		// Para o timeout (setado no search)
		this.killTimeout();
			
		this.searchText = text;
		
		if ( this.textContainer ) {
			this.textContainer.innerHTML = text.toLowerCase().replace(/ /g, '&nbsp;');
		}
	},
	
	select: function( idx )
	{
		this.combo.options.selectedIndex = idx;
	},
	
	setTimeout: function()
	{
		this.timeoutId = window.setTimeout( this.expired.bind(this), this.options.timeout );
	},
	
	killTimeout: function()
	{
		if ( this.timeoutId ) {
			window.clearTimeout( this.timeoutId );
		}
	},
	
	expired: function()
	{
		this.setSearchText( '' );
	},
	
	onfocus: function()
	{
		this.textContainer.innerHTML = "Digite o texto para a busca";
	},
	
	onblur: function()
	{
		this.textContainer.innerHTML = "";
	},
	
	alert: function( event, msg )
	{
		var code = event.keyCode ? event.keyCode : event.which;
		window.alert( "code: " + code + ", char: " + String.fromCharCode(code) + " " + (msg || "") );
	}
};
