var
ElementAutocomplete = $class({





	_style: 'font:11px \'Arial\' sans-serif; border:1px solid #ccc; background-color:white; padding:2px; cursor:default; max-height:15em; overflow:auto; z-index:9999; ',

	_word_style: 'color:#390',



	select: function(key, sel) {},

	reset: function() {},


	$: null,
	rows: null,
	keys: null,
	titles: null,

	in_make: 0,
	another_make: 0,
	exact_match: 0,

	list: null,
	full_list: null,
	full_list_divs:null,
	auto_list: null,
	list_divs: null,

	list_height: 15,
	list_row: null,


	initialize: function(data, style) {
		if (data instanceof Array) {
			this.rows = [];  this.titles = [];
			var rows=this.rows, titles=this.titles;
			$.each(data, function(k,v) {
				rows[k] = k+':'+v
				titles[k] = '%%'
			});
		} else {
			this.rows = [];  this.keys = [];  this.titles = [];
			var keys=this.keys, rows=this.rows, titles=this.titles;
			var i=0;
			$.each(data, function(k,v) {
				keys.push(k);
				if (v instanceof Array) {
					rows[i] = i+':'+v[0]
					titles[i] = v[1]
				} else {
					rows[i] = i+':'+v
					titles[i] = '%%'
				}
				i++
			});
		}
		this._style += style;
	},


	init: function()
	{
		this.$ = $(this);


		this.$.attr('autocomplete', 'off');


		if (b.ie) {
			this.$e('keydown', function() {
				ElementAutocomplete.prototype.onkeypress.apply(this, [window.event]);

				return window.event.keyCode!=13  &&  window.event.keyCode!=9;
			})

		}
	},


	init_list: function()
	{
		if (this.auto_list)  return;


		this.auto_list = $('<span style="position:absolute; display:none; '+this._style+'"></span>');
		this.auto_list.css('margin-top',
			this.$.height() +
			parseInt(this.$.css('border-bottom-width'))*2 + parseInt(this.$.css('padding-bottom'))*2 - 1
		);
		if (b.ie)   this.auto_list.css('height', this.auto_list.css('max-height'));


		this.full_list = this.auto_list.clone();
		var titles=this.titles, rowsln=this.titles.length, i;
		this.full_list_divs = [];
		for (i=0; i<rowsln; i++) {
			var div = d.createElement('div');
			div.idx = div.ind = i;
			div.innerHTML = titles[i].replace(/%%/, this.rows[i].replace(/[0-9]+:/, ''));
			this.full_list_divs.push(div);
			this.full_list[0].appendChild(div);
		}
		this.full_list.hide();

		this.$.before(this.auto_list).before(this.full_list);


		this.init_list_actions(this.auto_list);
		this.init_list_actions(this.full_list);
	},


	init_list_actions: function(list)
	{

		list[0].par = this;

		list[0].select_by_element = function(par, el, finish) {
			while (el.idx==null) {
				el = el.parentNode;
				if (!el  ||  el==par) {
					return false;
				}
			}

			par.select_row(el.idx, 1, finish);
			return true;
		}

		list.mousedown(function(evt) {

			if (!b.ie) {
				this.select_by_element(this.par, evt.target);
			} else {
				if (!this.select_by_element(this.par, evt.target, 1))  this.par.blur_stop = 1;
			}
			this.mdown = 1;
			return false;
		});
		list.mouseup(function(evt) {
			this.select_by_element(this.par, evt.target, 1);
			this.mdown = 0;
			return false;
		});

		list.mousemove(function(evt) {
			this.select_by_element(this.par, evt.target);
		});

		list.focus(function() {this.par.focus() });
		list.scroll(function() {this.par.focus() });

		if (b.ie) list[0].onselectstart = function() {return false;};
	},


	onkeypress: function(evt) {
		if (!evt) {return true;}

		switch (evt.keyCode) {
		case 35:
		case 36:
		case 37:
		case 39:
			return true;

		case 33:
			this.select_row(this.list_row-this.list_height); return true;
		case 34:
			this.select_row(this.list_row+this.list_height); return true;

		case 38:
			this.select_row(this.list_row-1); return true;
		case 40:
			this.select_row(this.list_row+1); return true;

		case 9:
		case 13:
			this.select_row(this.list_row, 1, 1); return false;

		case 27:
			this.hide_list(); return false;
		}


		this.update_list();
		return true;
	},


	blur_stop: 0,
	onblur: function() {

		if (b.opera)  return;

		var idx = this.rows.indexOf(this.value);
		if (idx!=-1) {
			this.select(this.keys ? this.keys[idx] : null);
		}

		if (b.ie && this.blur_stop) {
			this.blur_stop = 0;
			return;
		}
		this.hide_list();
	},

	onfocus: function() {
		if (!b.ie)  this.update_list();
	},


	update_list: function() {

		if (!this.auto_list) {
			this.init_list();
		}

		if (this.in_make) {
			this.another_make = 1;
		} else {
			setTimeout('$("#'+this.id+'")[0].make_list();', 150);
		}
	},


	make_list: function()
	{
		var phrase, phrases;

		do {
			this.another_make = 0;
			this.in_make = 1;
			this.exact_match = 0;

			phrase = $.trim(this.$.val());
			phrases = phrase.match(/[a-zA-Zà-ÿÀ-ß¸¨0-9_]+/g);
			if (phrase.length<2  ||  !phrases) {

				this.make_full_list();
			} else {

				var re = new RegExp('[0-9]+:.*'+phrases.join('.*')+'.*', 'gi');
				var rows = this.rows.join('\n').match(re);

				if (!rows) {

					this.make_null_list();
				}
				else if (rows.length>=this.rows.length) {

					this.make_full_list();
				}
				else {

					this.make_filtered_list(phrase, phrases, rows);
				}
			}

			if (this.exact_match) {

				var idx = this.check_indexOf(this.value);
				if (idx!=-1) {
					this.select(this.keys ? this.keys[idx] : null)
				}
			} else {
				this.reset()
			}
		}
		while (this.another_make);


		this.select_row(0);
	},



	make_full_list: function() {
		display_objects(0);
		this.auto_list.hide();
		this.full_list.css('display', 'inline');
		this.list = this.full_list;
		this.list_divs = this.full_list_divs;
		this.in_make = 0;
	},



	make_null_list: function() {
		this.full_list.hide();
		this.auto_list.html('').css('display', 'none');
		this.list = this.auto_list;
		this.list_divs = [];
		this.in_make = 0;
	},



	make_filtered_list: function(phrase, phrases, rows) {

		var html = '';
		var topdivs = [];
		var divs = [];
		var list = this.auto_list[0];   list.innerHTML = '';

		var i, ln, phrasesln = phrases.length
		var phrase_lower = phrases[0].toLowerCase()
		var regsearch = RegExp('('+phrases.join('|')+')', 'gi')
		var regreplace = '<span style="'+this._word_style+'">$1</span>'


		if (rows) {
			var rowsln=rows.length;
			for (i=0; i<rowsln; i++) {


				var div = d.createElement('div');
				div.ind = rows[i].split(':', 2)[0]
				row = this.rows[div.ind].replace(/[0-9]+:/, '')

				div.innerHTML = this.titles[div.ind]
					.replace(/%%/, row.replace(regsearch, regreplace));

				if (row.toLowerCase().indexOf(phrase_lower)==0) {
					if (row==phrase)   this.exact_match = 1;
					topdivs.push(div);
				} else {
					divs.push(div);
				}
			}

			this.list_divs = [];
			var idx = 0;
			for (ln=topdivs.length, i=0; i<ln; i++) {
				topdivs[i].idx = idx++;
				list.appendChild(topdivs[i]);
				this.list_divs.push(topdivs[i]);
			}
			for (ln=divs.length, i=0; i<ln; i++) {
				divs[i].idx = idx++;
				list.appendChild(divs[i]);
				this.list_divs.push(divs[i]);
			}
		}


		display_objects(0);
		this.full_list.hide();
		this.auto_list.css('display', 'inline');
		this.list = this.auto_list;

		this.in_make = 0;
	},



	select_row: function(row, noscroll, finish) {
		if (!this.list_divs  ||  !this.list_divs.length) {
			return;
		}

		if (row < 0) {
			row = 0;
		} else if (row >= this.list_divs.length) {
			row = this.list_divs.length-1;
		}

		var div = this.list_divs[this.list_row];
		if (div) {
			div.style.backgroundColor = 'white';
		}
		div = this.list_divs[row];
		div.style.backgroundColor = '#C7D2E7';

		if (!noscroll) {
			var y = div.offsetTop-1, y2 = y+div.offsetHeight,
				lst = this.list[0],  top = lst.scrollTop,  hgh = lst.offsetHeight-4;
			if (y < top) {
				lst.scrollTop = y;
			} else if (y2 > top+hgh) {
				lst.scrollTop = y2-hgh;
			}
		}

		this.list_row = row;

		if (finish) {


			this.value = this.rows[div.ind].replace(/.*:/, '');
			this.hide_list();
			div.style.backgroundColor = 'white';

			this.select(this.keys ? this.keys[this.rows.indexOf(this.rows[div.ind])] : null, true);
		}
	},


	hide_list: function() {
		display_objects(1);
		if (!this.list)  return;
		this.another_make = 0;
		this.list.hide();
	},


	check_indexOf: function(val) {
		var re = new RegExp('[0-9]+:'+val, 'gi');
		var rows = this.rows.join('\n').match(re);

		return rows ? rows[0].split(':', 2)[0] : false;
	}
})
