/*
* xnAutocompleter v2 By Inventix: www.inventix.ru
* Created 2009-08-25
* */

(function($) {

	var Keys = {
		RETURN: 13,
		ESC: 27,
		BACKSPACE: 8,
		DELETE: 46,
		UP: 38,
		DOWN: 40
	};

	$.fn.xnAutocompleter = function(Settings) {
		var Defaults = {
			Url: '',
			Preload: true,
			InputFormat: 'id-value',
			Limit: 0,

			MinChars: 1,
			Delay: 100,

			Disabled: false,
			IdPrefix: '',
			NamePrefix: '',
			Width: 171,

			ButtonValue: '>',
			EmptyMessage: 'Not found',
			UpdateMessage: 'Please wait...',
			HideButton: false,
			ExpandOnFocus: false,

			AnimationDuration: 200,

			OnChange: function(ExsistItem, Value, Id) { }
		};

		Settings = $.extend(Defaults, Settings);

		//Methods
		var UpdateList = function(Url, Filter) {
			if (!Filter)
				Filter = '';

			ShowMessage(Settings.UpdateMessage);

			$.get(Url, { q: Filter, limit: Settings.Limit }, function(Response) {
				Elements.Ul.empty();

				if (Response['res'] != 'ok')
					return false;

				for (var i = 0; i < Response['data'].length; i++) {
					var Id = '';
					var Value = '';

					if (Settings.InputFormat == 'id-value') {
						Id = Response['data'][i][0];
						Value = Response['data'][i][1];
					} else {
						Id = Response['data'][0][i];
						Value = Id;
					}

					var Li = $('<li value="' + Id + '">' + Value + '</li>');

					Li.hover(
						function() {
							$(this).addClass('li_hover');
						},
						function() {
							$(this).removeClass('li_hover');
						}
					);
					Li.click(function() {
						Elements.Id.attr('value', $(this).attr('value'));
						Elements.Value.attr('value', $(this).text());

						Settings.OnChange(true, $(this).text(), $(this).attr('value'));

						HideList();
					});
					Li.appendTo(Elements.Ul);
				}

				if (Response['data'].length == 0)
					ShowMessage(Settings.EmptyMessage);
				else
					HideMessage();

				if (Settings.Limit) {
					$('li:gt(' + (Settings.Limit - 1) + ')', Elements.Ul).css('display', 'none');
				}
			}, 'json');
		};

		var SetFilter = function(Filter) {
			if (Filter.length > 0) {
				Elements.Ul.children().css('display', 'none').filter(function(index) {
					return $(this).text().toLowerCase().indexOf(Filter.toLowerCase()) == 0;
				}).css('display', 'block');

				if ($('li:visible:first', Elements.Ul).text().toLowerCase() == Filter.toLowerCase()) {
					$('li:visible:first', Elements.Ul).click();
				}
			} else {
				Elements.Ul.children().css('display', 'block');
			}

			if ($('li:visible', Elements.Ul).length == 0) {
				ShowMessage(Settings.EmptyMessage);
			} else {
				HideMessage();
			}

			if (Settings.Limit) {
				$('li:visible:gt(' + Settings.Limit + ')', Elements.Ul).css('display', 'none');
			}
		};

		var ShowList = function(Animation) {
			if (Animation == false)
				Elements.List.show();
			else
				Elements.List.slideDown(Settings.AnimationDuration);
		}

		var HideList = function(Animation) {
			if (Animation == false)
				Elements.List.hide();
			else
				Elements.List.slideUp(Settings.AnimationDuration);
			
			$('li', Elements.List).removeClass('li_hover');
		}

		var ShowMessage = function(Message) {
			Elements.Span.text(Message).show();
		};

		var HideMessage = function() {
			Elements.Span.hide();
		};
		//---------------------------------------------------
		
		$(this).append(
			'<input type="hidden" value="' + Settings.Url + '" id="' + Settings.IdPrefix + '_url"  />' +
			'<input type="hidden" value="' + Settings.NamePrefix + '_id" id="' + Settings.IdPrefix + '_id" />' +
			'<input type="text" name="' + Settings.NamePrefix + '_val" id="' + Settings.IdPrefix + '_val" autocomplete="off" />' +
			'<input type="button" value="' + Settings.ButtonValue + '" />' +
			'<div>' +
			'   <span></span>' +
			'   <ul></ul>' +
			'</div>'
		);

		//Common elements
		var Elements = { };

		Elements.Url    = $('#' + Settings.IdPrefix + '_url', $(this));

		Elements.Id     = $('#' + Settings.IdPrefix + '_id', $(this));
		Elements.Value  = $('#' + Settings.IdPrefix + '_val', $(this));
		Elements.Button = $('input:button', $(this));

		Elements.List   = $('div', $(this));
		Elements.Ul     = $('ul', $(this));
		Elements.Span   = $('span', $(this));

		Elements.List.css({ width: Settings.Width });
		Elements.Value.attr('disabled', Settings.Disabled);
		Elements.Button.attr('disabled', Settings.Disabled);

		HideList(false);

		if (!Settings.Disabled) {
			UpdateList(Settings.Url);
		}

		if (Settings.HideButton) {
			Elements.Button.hide();
		}

		var SelectedItem = -1;

		//Events
		Elements.Url.change(function() {
			UpdateList(Elements.Url.attr('value'));
		});

		//Variables for correct OnBlur event
		var Focus = { Value: false, Button: false, List: false };

		function OnBlur() {
			setTimeout(function() {
				if (!Focus.Value && !Focus.Button && !Focus.List) {
					HideList();
				}
			}, 100);
		}

		Elements.Value.focus(function() {
			Focus.Value = true;
			if (Elements.List.is(':hidden') && Settings.ExpandOnFocus) {
				ShowList();
			}
		}).blur(function() {
			Focus.Value = false;
			OnBlur();
		});

		Elements.Button.focus(function() {
			Focus.Button = true;
		}).blur(function() {
			Focus.Button = false;
			OnBlur();
		});
		
		Elements.List.focus(function() {
			Focus.List = true;
			OnBlur();
		}).blur(function() {
			Focus.List = false;
			OnBlur();
		});
		
		Elements.Button.click(function() {
			if (Elements.List.is(':hidden'))
				ShowList();
			else
				HideList();
		});
		
		Elements.Value.keyup(function(e) {
			keyup(e);
		});
		Elements.Button.keyup(function(e) {
			keyup(e);
		});

		function keyup(e) {
			if (e.which == Keys.RETURN) {
				if (Elements.List.is(':visible')) {
					if (SelectedItem < 0)
						SelectedItem = 0;

					$('li:visible:eq(' + SelectedItem + ')', Elements.Ul).click();
				}
			} else if (e.which == Keys.ESC) {
				HideList();
			} else if (e.which == Keys.DOWN) {
				if (Elements.List.is(':hidden')) {
					ShowList();
				} else {
					if (SelectedItem > -1) 
						$('li:visible:eq(' + SelectedItem + ')').removeClass('li_hover');
					
					if (SelectedItem < $('li:visible', Elements.Ul).length - 1) 
						SelectedItem++;
					
					$('li:visible:eq(' + SelectedItem + ')').addClass('li_hover').focus();
				}
			} else if (e.which == Keys.UP) {
				if (SelectedItem < $('li:visible', Elements.Ul).length)
					$('li:visible:eq(' + SelectedItem + ')').removeClass('li_hover');

				if (SelectedItem > 0)
					SelectedItem--;

				$('li:visible:eq(' + SelectedItem + ')').addClass('li_hover');
			} else {
				SelectedItem = -1;

				Settings.OnChange(false, Elements.Value.attr('value'));

				if (!Settings.Preload)
					UpdateList(Elements.Url.attr('value'), Elements.Value.attr('value'));

				if (Elements.Value.attr('value').length >= Settings.MinChars || e.which == Keys.BACKSPACE) {
					ShowList();
					SetFilter(Elements.Value.attr('value'));
				}
			}
		}
	};

})(jQuery);
