﻿var RichWidgets_Input_AutoComplete_DelayInMs = 200;
var RichWidgets_Input_AutoComplete_IndexResults = function(term, items) { return true; };
var RichWidgets_Input_AutoComplete_UsePartialResultCache = false;

function RichWidgets_Input_AutoComplete_setup(options) {
    if (options.DelayInMs !== undefined) {
        RichWidgets_Input_AutoComplete_DelayInMs = options.DelayInMs;
    }
    if (options.UsePartialResultCache !== undefined) {
        RichWidgets_Input_AutoComplete_UsePartialResultCache = options.UsePartialResultCache;
    }
}

function RichWidgets_Input_AutoComplete_init(inputId, inputValueId, autocompleteId, searchFromStart) {

 osjs(function($) {
  var input = $("#" + inputId);
  var inputAutocomplete;
  
  var autocompleteBlock = $("#" + autocompleteId);
  var inputValue = $("#" + inputValueId);
  var forceSearch = false;

  // Hashtable with the search results, keyed by the search term
  var searchIndex = {};

  if (inputValue.val() == "") {
   inputValue.val("--unchanged--");
  }

  var forceOpenAutocomplete = function(event) {
   forceSearch = true;
   input.autocomplete("search", "");
   forceSearch = false;
  };

  var addItems = function(term, items, add) {

   if (RichWidgets_Input_AutoComplete_IndexResults.call(input.get(0), term, items)) {
    searchIndex[term] = items;
   }

   add(items);

   if (items.length == 0) {
    // Workaround the fact that the menu preserves the last value even if is
    // refreshed as empty
    inputAutocomplete.menu.element.empty();
    inputAutocomplete.menu.active = null;
   } else {
    // Try to find an item which exactly matches the input
    // For performance reasons, we only search in the 10 first items
    var fullMatcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(input.val()) + "$", "i");
    var menuItems = inputAutocomplete.menu.element.children("li");
    for (var i = 0; i < menuItems.length && i < 10; i++) {
     if (fullMatcher.test(menuItems.eq(i).data("item.autocomplete").label)) {
      // Exact case-insensitive match: activate it
      inputAutocomplete.menu.activate($.Event("search"), menuItems.eq(i));
      return;
     }
    }

    // Activate the first item as fallback
    inputAutocomplete.menu.activate($.Event("search"), menuItems.eq(0));
   }
  };

  var onNotifySource = function(req, add) {
   window["RichWidgets_Input_AutoComplete_setListFor" + inputId.replace(":", "$")] = function(rows) {
    var items = $.map(rows.split("\n"), function(row) {
     if (row != "") {
      var rowParts = $.trim(row).split("\t");
      return { label: rowParts[0], id: rowParts[1] };
     } else {
      return null;
     }
    });

    addItems(req.term, items, add);
   };

   OsNotifyWidget(autocompleteId, searchFromStart? req.term + "%" : "%" + req.term + "%");
   return true;
  };

  var onIndexedSource = function(req, add) {
   // Search exact match in the searchIndex
   var items = searchIndex[req.term];
   if (items) {
    addItems(req.term, items, add);
    return true;
   }
   
   if (RichWidgets_Input_AutoComplete_UsePartialResultCache) {
    // Search for a substring-match
    for (var k in searchIndex) {
     var matcher;

     if (searchFromStart && req.term.toLowerCase().indexOf(k.toLowerCase()) == 0) {
      matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(req.term), "i");
     } else if (!searchFromStart && req.term.toLowerCase().indexOf(k.toLowerCase()) != -1) {
      matcher = new RegExp($.ui.autocomplete.escapeRegex(req.term), "i");
     }

     if (matcher) {
      var items = $.map(searchIndex[k], function(item) {
       if (matcher.test(item.label)) {
        return item;
       } else {
        return null;
       }
      });
      addItems(req.term, items, add);
      return true;
     }
    }
   }

   return false;
  };

  input.autocomplete({
   delay: RichWidgets_Input_AutoComplete_DelayInMs,
   minLength: 0,
   source: function(req, add) {
    onIndexedSource(req, add) || onNotifySource(req, add);
   },
   search: function(event, ui) {
    if (input.val() == "" && !forceSearch) {
     // Prevent search without any input
     input.autocomplete("close");
     return false;
    }
   },
   change: function(event, ui) {
    if (ui.item) {
     inputValue.val(ui.item.id);
     inputValue.trigger("onchange");
    } else {
     inputValue.val(input.val() == ""? "" : "--invalid--");
    }
   },
   open: function(event, ui) {
    OsDisableSubmitOnEnterKey = true;
   },
   close: function(event, ui) {
    OsDisableSubmitOnEnterKey = false;
   },
   focus: function(event, ui) {
     inputAutocomplete.selectedItem = null;
     if (ui.item && (input.val().toLowerCase() == ui.item.label.toLowerCase())) {
       inputAutocomplete.selectedItem = ui.item;
     }
    }
  });

  inputAutocomplete = input.data("autocomplete");
  //Remove blur event from menu to avoid it from re-writing the input text
  inputAutocomplete.menu.options['blur'] = null
  //Transfer on changes to the real input
  if (input.attr("onchange") != null) {
    inputValue.get(0).onchange = input.get(0).onchange;
    input.removeAttr("onchange");
  }
  if (input.attr("onoschange") != null) {
    inputValue.attr("onoschange", input.attr("onoschange"));
    input.removeAttr("onoschange");
  }
  inputAutocomplete.menu.element.bind("menuselected", function(event, ui) {
    if (ui.item) {
        inputValue.val(ui.item.data("item.autocomplete").id);
        inputValue.trigger("onchange");
    }
  });

  inputAutocomplete._renderItem = (function(oldRenderItem) {
   return function(ul, item) {
    var li = oldRenderItem(ul, item);
    var text = $("a", li).text();
    $("a", li).html('<ui-autocomplete-item>' + text.replace(new RegExp("(" + $.ui.autocomplete.escapeRegex(this.term) + ")", "i"), "<strong>$1</strong>") + '</ui-autocomplete-item>');
    return li;
   };
  })(inputAutocomplete._renderItem);

  input.bind("dblclick.autocomplete", function(event) {
   forceOpenAutocomplete(event);
  }).bind("keydown.autocomplete", function(event) {
   if (input.val() == "" && (event.keyCode == $.ui.keyCode.DOWN || event.keyCode == $.ui.keyCode.UP)) {
    forceOpenAutocomplete(event);
   } else if (event.keyCode == $.ui.keyCode.ENTER && inputAutocomplete.menu.active) {
    event.stopPropagation();
   }
  }).bind("paste.autocomplete", function(event) {
      input.trigger("keydown");
      event.stopPropagation();
  });
  
  var autocompleteValue = function(newValue) {
    if(arguments.length > 0) {
        input.focus();
      input.val(newValue);
      input.trigger("keydown");
    } else {
      return input.val();
    }
  }
    
  autocompleteBlock[0].autocompleteValue = autocompleteValue;
  input[0].autocompleteValue = autocompleteValue;
 });
}
