(function( $ ){

	var methods = {
		Init : function( url, options ) {
			var settings = $.extend({
				url: url,
				visibleInputName: "tokenSearch_visible",
				hintText: "Type in a search term",
				noResultsText: "No results",
				searchingText: "Searching...",
				searchDelay: 1000, //not currently in use
				minChars: 1,
				tokenLimit: null,
				//jsonContainer: null,
				method: "POST",
				//contentType: "json",
				//queryParam: "q",
				//onResult: null,
				//addSpecialResult: null
			}, options);
		
			settings.classes = $.extend({
				//tokenList: "token-input-list",
				//token: "token-input-token",
				//tokenDelete: "token-input-delete-token",
				//selectedToken: "token-input-selected-token",
				//highlightedToken: "token-input-highlighted-token",
				//dropdown: "token-input-dropdown",
				//dropdownItem: "token-input-dropdown-item",
				//dropdownItem2: "token-input-dropdown-item2",
				//selectedDropdownItem: "token-input-selected-dropdown-item",
				//inputToken: "token-input-input-token"
			}, options.classes),
			
			// Keys "enum"
			KEY = {
				BACKSPACE: 8,
				TAB: 9,
				RETURN: 13,
				ESC: 27,
				LEFT: 37,
				UP: 38,
				RIGHT: 39,
				DOWN: 40,
				COMMA: 188
			};
			
			function IsPrintableCharacter(keycode) {
				if((keycode >= 48 && keycode <= 90) ||      // 0-1a-z
				   (keycode >= 96 && keycode <= 111) ||     // numpad 0-9 + - / * .
				   (keycode >= 186 && keycode <= 192) ||    // ; = , - . / ^
				   (keycode >= 219 && keycode <= 222)       // ( \ ) '
				  ) {
					  return true;
				  } else {
					  return false;
				  }
			}

			return this.each(function(){
				
				// Keep a reference to the original input box
				// Recall any existing data.
				var $hiddenInput = $(this),
				data = $hiddenInput.data('tokenSearch');
				

				// If the plugin hasn't been initialized yet
				if ( ! data ) {
					
					//No tokens yet
					$hiddenInput.data('tokenCount', 0);
					
											
					
					// Create a new text input and bind events
    				var $visibleInput = $('<input />', {
											type : 'text',
											id : settings.visibleInputName,
											name : settings.visibleInputName,
											value : 'new',
										})
										//.insertAfter($hiddenInput)
										/*.css({
											outline: "none"
										})*/
										.bind('focus.tokenSearch', function () {
											var tokenCount = $hiddenInput.data('tokenCount');
											$dropdown = $hiddenInput.data('tokenSearch').dropdown;
											if (settings.tokenLimit == null || settings.tokenLimit > tokenCount) {
												//show_dropdown_hint();
												$hiddenInput.tokenSearch("ShowDropdownHint");
												//alert("Show Dropdown - tokenCount ="+ tokenCount);
												
											}
										})
										
										.bind('blur.tokenSearch', function () {
											$dropdown.hide();
											//hide_dropdown();
										})
										
										
										.keydown(function (event) {
											//var previous_token;
											//var next_token;
								
											switch(event.keyCode) {
												//case KEY.LEFT:
												//case KEY.RIGHT:
												//case KEY.UP:
												/*case KEY.DOWN:
													if(!$(this).val()) {
														previous_token = input_token.prev();
														next_token = input_token.next();
								
														if((previous_token.length && previous_token.get(0) === selected_token) || (next_token.length && next_token.get(0) === selected_token)) {
															// Check if there is a previous/next token and it is selected
															if(event.keyCode == KEY.LEFT || event.keyCode == KEY.UP) {
																deselect_token($(selected_token), POSITION.BEFORE);
															} else {
																deselect_token($(selected_token), POSITION.AFTER);
															}
														} else if((event.keyCode == KEY.LEFT || event.keyCode == KEY.UP) && previous_token.length) {
															// We are moving left, select the previous token if it exists
															select_token($(previous_token.get(0)));
														} else if((event.keyCode == KEY.RIGHT || event.keyCode == KEY.DOWN) && next_token.length) {
															// We are moving right, select the next token if it exists
															select_token($(next_token.get(0)));
														}
													} else {
														var dropdown_item = null;
								
														if(event.keyCode == KEY.DOWN || event.keyCode == KEY.RIGHT) {
															dropdown_item = $(selected_dropdown_item).next();
														} else {
															dropdown_item = $(selected_dropdown_item).prev();
														}
								
														if(dropdown_item.length) {
															select_dropdown_item(dropdown_item);
														}
														return false;
													}
													break;*/
								
												/*case KEY.BACKSPACE:
													previous_token = input_token.prev();
								
													if(!$(this).val().length) {
														if(selected_token) {
															delete_token($(selected_token));
														} else if(previous_token.length) {
															select_token($(previous_token.get(0)));
														}
								
														return false;
													} else if($(this).val().length == 1) {
														hide_dropdown();
													} else {
														// set a timeout just long enough to let this function finish.
														setTimeout(function(){do_search(false);}, 5);
													}
													break;*/
								
												//case KEY.TAB:
												//case KEY.RETURN:
												/*case KEY.COMMA:
												  if(selected_dropdown_item) {
													add_token($(selected_dropdown_item));
													return false;
												  }
												  break;
								
												case KEY.ESC:
												  hide_dropdown();
												  return true;*/
								
												default:
													if(IsPrintableCharacter(event.keyCode)) {
												  		// set a timeout just long enough to let this function finish.
												  		setTimeout(function(){
													  		$hiddenInput.tokenSearch("InitiateSearch",true);
														}, 5);
													}
												break;
											}
										});
					
					//Bind Events using Namespacing (probably not necessary in this case... but shouldnt hurt)
   					$hiddenInput.show()
								.bind('focus.tokenSearch', function () {
									//$hiddenInput.tokenSearch('AddToken');
									//var tokenCount = $hiddenInput.data('tokenCount');
									
									$visibleInput.focus();
									
									//alert(tokenCount);
								});
								
								
					// Create the list to store the token items in
					var $tokenList = $('<ul />')
						//.addClass(settings.classes.tokenList)
						.insertAfter($hiddenInput);
						/*.click(function (event) {
							var li = get_element_from_event(event, "li");
							if(li && li.get(0) != input_token.get(0)) {
								toggle_select_token(li);
								return false;
							} else {
								input_box.focus();
					
								if(selected_token) {
									deselect_token($(selected_token), POSITION.END);
								}
							}
						})
						.mouseover(function (event) {
							var li = get_element_from_event(event, "li");
							if(li && selected_token !== this) {
								li.addClass(settings.classes.highlightedToken);
							}
						})
						.mouseout(function (event) {
							var li = get_element_from_event(event, "li");
							if(li && selected_token !== this) {
								li.removeClass(settings.classes.highlightedToken);
							}
						})
						.mousedown(function (event) {
							// Stop user selecting text on tokens
							var li = get_element_from_event(event, "li");
							if(li){
								return false;
							}
						});*/
						
					// The token holding the search Input
    				var $inputToken = $("<li />")
        				//.addClass(settings.classes.inputToken)
        				.appendTo($tokenList)
        				.append($visibleInput);
					
					// The list to store the dropdown items in
					var $dropdown = $("<div>")
						//.addClass(settings.classes.dropdown)
						.insertAfter($tokenList)
						.text("moo")
						.hide();
						
						
					
					
					//Save the data for use in other methods.
					$hiddenInput.data('tokenSearch', {
						settings : settings,
						hiddenInput : $hiddenInput,
						visibleInput : $visibleInput,
						tokenList :  $tokenList,
						inputToken : $inputToken,
						dropdown : $dropdown
					});
					

				}
				
			});
			
		},
		
		Destroy : function( ) {

			return this.each(function(){
				
				// Keep a reference to the original input box
				// Recall any existing data.
				var $hiddenInput = $(this),
				data = $hiddenInput.data('tokenSearch');

				// Destroy binds and data.
				$(window).unbind('.tokenSearch');
				data.tokenSearch.remove();
				$hiddenInput.removeData('tokenSearch');

			})

		},
		
		AlertValue : function( ) {
			return this.each(function(){

				// Keep a reference to the original input box
				// Recall any existing data.
				var $hiddenInput = $(this),
				data = $hiddenInput.data('tokenSearch');
				
				alert("Hidden: "+data.hiddenInput.val()+"\n\rVisible: "+data.visibleInput.val());
				
			});
		},
		
		AddToken : function( ) {
			return this.each(function(){

				var $hiddenInput = $(this);	
				
				$hiddenInput.data('tokenCount', $hiddenInput.data('tokenCount') + 1);
				
			}); 
		},
		
		
		ShowDropdownHint : function( ) {
			return this.each(function(){
				
				var $hiddenInput = $(this),
				$dropdown = $hiddenInput.data('tokenSearch').dropdown,
				settings = $hiddenInput.data('tokenSearch').settings;
				
				$dropdown	.html("<p>"+settings.hintText+"</p>")
							.show();
				
			});
		},
		
		ShowDropdownSearching : function() {
			return this.each(function(){
				
				var $hiddenInput = $(this),
				$dropdown = $hiddenInput.data('tokenSearch').dropdown,
				settings = $hiddenInput.data('tokenSearch').settings;
       			
				$dropdown	.html("<p>"+settings.searchingText+"</p>")
            				.show();
			});
    	},
		
		PopulateDropdown : function (results) {
			return this.each(function(){
				
				var $hiddenInput = $(this),
				$dropdown = $hiddenInput.data('tokenSearch').dropdown,
				settings = $hiddenInput.data('tokenSearch').settings;
			
			/*if(results.length) {
				dropdown.empty();
				var dropdown_ul = $("<ul>")
					.appendTo(dropdown)
					.mouseover(function (event) {
						select_dropdown_item(get_element_from_event(event, "li"));
					})
					.mousedown(function (event) {
						add_token(get_element_from_event(event, "li"));
						return false;
					})
					.hide();
	
				for(var i in results) {
					if (results.hasOwnProperty(i)) {
						var this_li = $("<li>"+highlight_term(results[i].name, query)+"</li>")
										  .appendTo(dropdown_ul);
	
						if(i%2) {
							this_li.addClass(settings.classes.dropdownItem);
						} else {
							this_li.addClass(settings.classes.dropdownItem2);
						}
	
						if(i == 0) {
							select_dropdown_item(this_li);
						}
	
						$.data(this_li.get(0), "tokeninput", {"id": results[i].id, "name": results[i].name});
					}
				}
				
				if (settings.addSpecialResult != null) {
					var this_li2 = $("<li>------------</li>")
										  .appendTo(dropdown_ul);
	
						if(i%2) {
							this_li2.addClass(settings.classes.dropdownItem);
						} else {
							this_li2.addClass(settings.classes.dropdownItem2);
						}
	
						if(i == 0) {
							select_dropdown_item(this_li2);
						}
	
						$.data(this_li2.get(0), "tokeninput", {"id": 99998, "name": "------------"});
					var this_li = $("<li>"+settings.addSpecialResult+"</li>")
										  .appendTo(dropdown_ul);
	
						if(i%2) {
							this_li.addClass(settings.classes.dropdownItem);
						} else {
							this_li.addClass(settings.classes.dropdownItem2);
						}
	
						if(i == 0) {
							select_dropdown_item(this_li);
						}
	
						$.data(this_li.get(0), "tokeninput", {"id": 99999, "name": settings.addSpecialResult});
						
					
				}
	
				dropdown.show();
				dropdown_ul.slideDown("fast");
	
			} else {*/
				$dropdown
					.html("<p>"+settings.noResultsText+"</p>")
					.show();
			//}
			});
		},
		
		// Initiate a search and show the "searching" dropdown if the input is longer
    	// than settings.minChars
		InitiateSearch : function (immediate) {
			return this.each(function(){
				
				var $hiddenInput = $(this),
				$visibleInput = $hiddenInput.data('tokenSearch').visibleInput,
				$dropdown = $hiddenInput.data('tokenSearch').dropdown,
				settings = $hiddenInput.data('tokenSearch').settings;
		

				var query = $visibleInput.val().toLowerCase();
		
				if (query && query.length) {
					/*if(selected_token) {
						deselect_token($(selected_token), POSITION.AFTER);
					}*/
					if (query.length >= settings.minChars) {
						$hiddenInput.tokenSearch("ShowDropdownSearching");
						if (immediate) {
							//run_search(query);
							$dropdown	.html("<p>Search executed</p>")
            							.show();
						} else {
							
							var timeout = setTimeout(function(){ $hiddenInput.tokenSearch("PerformSearch"); }, settings.searchDelay);
						}
					} else {
						$dropdown.hide();
					}
				}
			});
    	},
		
		PerformSearch : function () {
			return this.each(function(){
				
				var $hiddenInput = $(this),
				settings = $hiddenInput.data('tokenSearch').settings,
				query = visibleInput.val().toLowerCase();
				
				$.ajax({
					 url: settings.url,
					 type: settings.method,
					 data: 'query='+query,
					 async: true,
					 success: function(results) { // Do an AJAX call
									
									
					 }
									
				});
				
				
				
				
				$dropdown	.html("<p>Search executed</p>")
            				.show();
				
			});
    	},
		
		Update : function( content ) {
			// ...
		}
	};

	$.fn.tokenSearch = function( method ) {

		if ( methods[method] ) {
			return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
		} else if ( typeof method === 'object' || ! method ) {
			return methods.init.apply( this, arguments );
		} else {
			$.error( 'Method ' +  method + ' does not exist on jQuery.tokenSearch' );
		}    

	};

})( jQuery );
