/*global jQuery*/
(function($) {
	$.fn.tagField = function(params) {
		params = $.extend({
			query_parameters: {},
			query_url: null,
			tag_name: "tag"
		}, params);
		
		return this.each(function() {
			var input = $(this);
			
			input.data("params", params);
			
			input.keypress(function(e) {
				this.hideTags();
				var validChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZčćžšđČĆŽŠĐ1234567890".split("");
				var character = String.fromCharCode(e.which);
				if($.inArray(character, validChars) !== -1) {
					// we're dealing with a valid character
					var tag = this.extract_last_tag(input.val())
					if (tag == null)
					   tag = "";
					tag += character;
					this.fetchAndDisplayTags(tag);
				} else if(e.which === 8) {
					// backspace pressed, check if there's still a part of a word present
					var last_word = this.extract_last_tag(input.val())
					last_word = last_word.slice(0, last_word.length - 1);
					if(last_word == "") {
						this.hideTags();
					} else {
						// refetch the tags
						this.fetchAndDisplayTags(last_word);
					}
				}
			});
			
			// destroy the tags after focus has been lost
			input.blur(function() {
				setTimeout(function() {
					input.get(0).hideTags();
				}, 500);
			});
			
			// ==============
			// | Public API |
			// ==============
			
      this.extract_last_tag = function(txt) {
          var re, res_array;
          re = /"(([\.\w-]|\s)+)"?$/;
          res_array =  re.exec(txt);
          if (res_array != null)
              return res_array[1];
      
          re = /'(([\.\w-]|\s)+)'?$/;
          res_array =  re.exec(txt);
          if (res_array != null)
              return res_array[1];
      
          re = /[\.\w-]+$/;
          res_array =  re.exec(txt);
          if (res_array != null)
              return res_array[0];
      
          return null;
      }

			this.displayTags = function(tag_list) {
				this.hideTags();
				var position = input.offset();
				var tagField = $('<div class="tagField"></div>').appendTo("body").css({
					top: position.top + input.outerHeight() + "px",
					left: position.left + "px",
					position: "absolute",
					zIndex: 10000
				});
				
				for(var i = 0; i < tag_list.length; i++) {
					tagField.append('<label>' + tag_list[i].label + '</label><ul/>');
					var list = tagField.find('ul:last');
					for(var j = 0; j < tag_list[i].tags.length; j++) {
						list.append('<li>' + tag_list[i].tags[j] + '</li>');
					}
				}
				
				// hook up click events
				tagField.find('li').click(function() {
					var tag = $(this).text();
					if(/[^, ]+$/.test(input.val())) {
						// we have a word to replace
    				if($.inArray(' ', tag.split("")) !== -1)
						  input.val(input.val().replace(/[^, ]+$/, '"' + tag + '"') + " ");
						else
						  input.val(input.val().replace(/[^, ]+$/, tag) + " ");
					} else {
						// just append it to the value
    				if($.inArray(' ', tag.split("")) !== -1)
						  input.val(input.val() + '"' + tag + '"' + " ");
    				else
						  input.val(input.val() + tag + " ");
					}
					input.get(0).hideTags();
					input.focus();
				});
			};
			
			this.hideTags = function() {
				var tagField = $('body').find('div.tagField').remove();
			};
			
			this.fetchAndDisplayTags = function(tag) {
				input.get(0).hideTags();
				var params = input.data("params");
				var extend_params = {};
				extend_params[params.tag_name] = $.trim(tag);
				params.query_parameters = $.extend(params.query_parameters, extend_params);
				$.getJSON(
					params.query_url,
					params.query_parameters,
					function(response) {
						input.get(0).displayTags(response);
					}
				);
			};
			
			this.getParameters = function() {
				return input.data("params");
			};
		});
	};
})(jQuery);