(function() {

	SL.ui.AutoComplete = Class.create(SL.Component, {

		init : function() {

			this.config.setDefault('css_prefix', 'autocomplete');
			this.config.setDefault('multi', false);
			this.config.ensureHash('options');

			this.input = this.e.down('input');
			this.input.writeAttribute('autocomplete', 'off');
			var form = this.input.up('form');

			if (form) {
				this.input.writeAttribute('autocomplete', 'off');
			}

			new Form.Element.Observer(this.input, 0.2, this.onInputChange.bind(this));
			this.input.observe('blur', this.hideDelayed.bind(this));

		},

		onInputChange : function(e) {

			if (!this.initialized) {

				this.dd = new Element('div', {
					'class' : this.config.get('css_prefix') + '_dropdown'
				});

				this.options = this.config.get('options');
				this.url = this.config.get('options_url');

				this.input.insert({
					after : this.dd
				});

				this.e.setStyle({
					position : 'relative'
				});

				this.dd.setStyle({
					position : 'absolute',
					left : '0px',
					top : this.input.getHeight() + 'px'
				});

				this.dd.hide();

				this.initialized = true;
			}

			var values = this.input.getValue().strip();

			if (!this.config.get('multi')) {
				var value = values;
			} else {
				var pos = values.lastIndexOf(',');
				if (pos < 0) {
					value = values;
				} else {
					value = values.substr(pos + 1).strip();
				}
			}

			if (this.lastValue == value) {
				return;
			}

			this.lastValue = value;
			if (value.empty()) {
				return;
			}

			this.updateDropdown(value);
		},

		updateDropdown : function(value) {

			options = this.options.get(value);

			if (!options) {
				if (!this.url) {
					this.hide();
					return;
				}

				if (this.config.get('multi')) {
					var pos = value.lastIndexOf(',');
					if (pos > 0) {
						value = value.substr(pos + 1);
					}
				}

				var url = this.url.replace("@value@", value);

				new Ajax.Request(url, {
					onSuccess : this.onOptionsResponse.bind(this)
				});

				return;
			}

			if (options.length > 0) {
				this.updateDropdownOptions(options);
			} else {
				this.hide();
			}
		},

		updateDropdownOptions : function(options) {
			var inner = new Element('div', {
				'class' : this.config.get('css_prefix') + '_dowpdown_inner'
			});
			this.dd.update(inner);

			for ( var i = 0; i < options.length; i++) {
				var o = options[i];

				if (o.link) {
					var e = new Element('div');
					inner.appendChild(e);
					e.update(o.html);
					e.store('sl_ac_link', o.link);
					e.observe('click', o.link);
				} else {
					var e = new Element('div');
					inner.appendChild(e);
					e.update(o.html);
					e.store('sl_ac_id', o.id);
					e.observe('click', this.onOptionClick.bind(this, o.id));
				}
			}

			if (!this.shown) {
				this.dd.show();
				if (!this.keyHandler) {
					this.keyHandler = this.onInputKey.bind(this);
					document.observe('keydown', this.keyHandler);
				}
				this.shown = true;
			}
		},

		onOptionsResponse : function(o) {
			var options = eval('(' + o.responseText + ')');
			if (options && options.data.length > 0) {
				this.options.set(options.id, options.data);
				this.updateDropdownOptions(options.data);
			} else {
				this.hide();
			}
		},

		onInputKey : function(event) {

			if (!this.shown) {
				return;
			}

			if (event.keyCode == Event.KEY_DOWN) {
				event.stop();
				var current = this.dd.down('.selected');
				var next;
				if (!current) {
					next = this.dd.down().down();
				} else {
					next = current.next();
					current.removeClassName('selected');
					if (!next) {
						return;
					}
				}
				next.addClassName('selected');
			} else if (event.keyCode == Event.KEY_UP) {
				event.stop();
				var current = this.dd.down('.selected');
				var prev;
				if (!current) {
					var children = this.dd.down().childElements();
					prev = children[children.length - 1];
				} else {
					prev = current.previous();
					current.removeClassName('selected');
					if (!prev) {
						return;
					}
				}
				prev.addClassName('selected');
			} else if (event.keyCode == Event.KEY_RETURN) {
				var current = this.dd.down('.selected');
				if (current) {
					event.stop();
					var link = current.retrieve('sl_ac_link');
					if (link) {
						link();
					} else {
						this.selectOption(current.retrieve('sl_ac_id'));
					}
				}
				this.hide();
			} else if (event.keyCode == Event.KEY_ESC) {
				event.stop();
				this.hide();
			}
		},

		onOptionClick : function(id, event) {
			this.selectOption(id);
			this.hide.bind(this).defer();
		},

		hideDelayed : function() {
			setTimeout(this.hide.bind(this), 150);
		},

		hide : function() {
			if (this.shown) {
				this.dd.hide();
				this.shown = false;
			}
		},

		add : function(value) {
			this.selectOption(value, true);
		},

		selectOption : function(value, append) {

			if (!this.config.get('multi')) {
				this.lastValue = value;
				this.input.value = value;
				this.input.focus();
				return;
			}

			if (!value || this.contains(value)) {
				this.input.focus();
				return;
			}

			var values = this.input.value;
			if (values) {
				var pos = values.lastIndexOf(',');
				if (pos < 0) {
					if (append) {
						values += ', ' + value;
					} else {
						values = value;
					}
				} else if (append) {
					values = values.strip();
					if (values.endsWith(',')) {
						values += value;
					} else {
						values += ', ' + value;
					}
				} else {
					values = values.substr(0, pos + 1) + ' ' + value;
				}
			} else {
				values = value;
			}

			this.lastValue = value;
			this.input.value = values;
			this.input.focus();

			this.hide.bind(this).defer();
		},

		contains : function(id) {
			var data = this.input.value;
			if (!data) {
				return false;
			}

			data = data.split(',');

			for ( var i = 0; i < data.length; i++) {
				if (data[i].strip() == id) {
					return true;
				}
			}
			return false;
		}
	});

})();

