(function($) {

var ajax = $.ajax;

var pendingRequests = {};

var synced = [];
var syncedData = [];
var valueSelected = false;

$.ajax = function(settings) {
// create settings for compatibility with ajaxSetup
settings = jQuery.extend(settings, jQuery.extend({}, jQuery.ajaxSettings, settings));

var port = settings.port;

switch (settings.mode) {
case "sync":
var pos = synced.length;

synced[pos] = {
error: settings.error,
success: settings.success,
complete: settings.complete,
done: false
};

syncedData[pos] = {
error: [],
success: [],
complete: []
};

settings.error = function() { syncedData[pos].error = arguments; };
settings.success = function() { syncedData[pos].success = arguments; };
settings.complete = function() {
syncedData[pos].complete = arguments;
synced[pos].done = true;

if (pos == 0 || !synced[pos - 1])
for (var i = pos; i < synced.length && synced[i].done; i++) {
if (synced[i].error) synced[i].error.apply(jQuery, syncedData[i].error);
if (synced[i].success) synced[i].success.apply(jQuery, syncedData[i].success);
if (synced[i].complete) synced[i].complete.apply(jQuery, syncedData[i].complete);

synced[i] = null;
syncedData[i] = null;
}
};
}
return ajax.apply(this, arguments);
};

})(jQuery);
jQuery.autocomplete = function(input, options) {
// Create a link to self
var me = this;
var resultHidden = true;
var currentAjax = null;

// Create jQuery object for input element
var $input = $(input).attr("autocomplete", "off");

// Apply inputClass if necessary
if (options.inputClass) {
$input.addClass(options.inputClass);
}

// Create results
var results = document.createElement("div");

// Create jQuery object for results
var $results = $(results).hide().addClass(options.resultsClass).css("position", "absolute");
if (options.width > 0) {
$results.css("width", options.width);
}
if ($.browser.msie) {
// we put a styled iframe behind the calendar so HTML SELECT elements don't show through
$results.append(document.createElement('iframe'));
}


// Add to body element
if (options.attachedToBody) {
$("body").append(results);
} else {
$input.parent().append(results);
}

input.autocompleter = me;

var timeout = null;
var prev = "";
var active = -1;
var keyb = false;
var hasFocus = false;
var lastKeyPressCode = null;
var mouseDownOnSelect = false;
var hidingResults = false;
var xAdj = 0;
if ($.browser.msie) {
xAdj = 1;
}


$input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(e) {
//$input
//.keydown(function(e) {
// track last key pressed
lastKeyPressCode = e.keyCode;
switch (e.keyCode) {
case 38: // up
e.preventDefault();
moveSelect(-1);
break;
case 40: // down
e.preventDefault();
moveSelect(1);
break;
case 9:  // tab
case 13: // return
/*if (!$results.is(":visible")) {
return;
}*/
if (selectCurrent()) {
// make sure to blur off the current field
valueSelected = true;
$input.get(0).blur();
e.preventDefault();
}
break;
case 37: //left
moveSelect(-1);
break;
case 39: //right
moveSelect(1);
break;
case 8: //backspace need to throttle
active = -1;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(function() { onChange(); }, 100);
break;
default:
active = -1;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(function() { onChange(); }, options.delay);
break;
}
})
.focus(function() {
// track whether the field has focus, we shouldn't process any results if the field no longer has focus
hasFocus = true;
})
.blur(function() {

//If only 1 result then always autoselect
if (options.selectOnly) {
var $li = $("li", results);
if ($li.length == 1) {
li = $li[0];
selectItem(li, { eventType: "blur" });
}
}

// track whether the field has focus
hasFocus = false;
if (!mouseDownOnSelect) {
hideResults();
}
});

hideResultsNow();

function onChange() {
// ignore if the following keys are pressed: [del] [shift] [capslock]
valueSelected = false;
if (lastKeyPressCode == 46 || (lastKeyPressCode > 8 && lastKeyPressCode < 32)) return $results.hide();
var v = $input.val();
if (v == prev) return;
prev = v;
if (v.length >= options.minChars) {
resultHidden = false;
requestData(v);
} else {
resultHidden = true;
$results.hide();
}
};

function moveSelect(step) {

var lis = $("li", results);
if (!lis) return;

active += step;

if (active < 0) {
active = 0;
} else if (active >= lis.size()) {
active = lis.size() - 1;
}

lis.removeClass("ac_over");

$(lis[active]).addClass("ac_over");

};

function selectCurrent() {

var li = $("li.ac_over", results)[0];
if (!li) {
var $li = $("li", results);
if (options.selectOnly) {
if ($li.length == 1) li = $li[0];
} else if (options.selectFirst) {
li = $li[0];
}
}
if (li) {
if (li.selectValue.toLowerCase().substring(0, $input.val().length) != $input.val().toLowerCase()) {
return false;
}

selectItem(li);
return true;
} else {
return false;
}
};

function selectItem(li, extraData) {

if (!li) {
li = document.createElement("li");
li.extra = [];
li.selectValue = "";
}
var v = $.trim(li.selectValue ? li.selectValue : li.innerHTML);
input.lastSelected = v;
prev = v;
$results.html("");
$input.val(v);
hideResultsNow();
if (options.onItemSelect) {
setTimeout(function() { options.onItemSelect(li, extraData) }, 1);
}
};

function showResults() {
//var pos = findPos(input);
var iWidth = (options.width > 0) ? options.width : $input.width();
/*$results.css({
width: parseInt(iWidth) + "px",
top: (pos.y + input.offsetHeight - 1) + "px",
left: pos.x + xAdj + "px"
}).show();*/
$results.css({
width: parseInt(iWidth) + "px",
top: ($input.position().top + input.offsetHeight - 1) + "px",
left: $input.position().left + xAdj + "px"
}).show();


};

function hideResults() {
if (timeout) clearTimeout(timeout);
//timeout = setTimeout(hideResultsNow, 200);
hideResultsNow();
};

function hideResultsNow() {
if (hidingResults) {
return;
}
hidingResults = true;

if (timeout) {
clearTimeout(timeout);
}

var v = $input.val();

if ($results.is(":visible")) {
$results.hide();
}

if (options.mustMatch) {
if (!input.lastSelected || input.lastSelected != v) {
selectItem(null);
}
}

hidingResults = false;
};

function receiveData(q, data) {
if (data) {
//results.innerHTML = "";
$("ul", $results).remove();
if (!hasFocus || data.length == 0) return hideResultsNow();
/*if ($.browser.msie) {
// we put a styled iframe behind the calendar so HTML SELECT elements don't show through
$results.append(document.createElement('iframe'));
}*/
$results.append(dataToDom(data));
showResults();
} else {
hideResultsNow();
}
};

function parseData(data) {

if (!data) return null;
var parsed = [];
var rows = data.split(options.lineSeparator);
for (var i = 0; i < rows.length; i++) {
var row = $.trim(rows[i]);
if (row) {
parsed[parsed.length] = row.split(options.cellSeparator);
}
}
return parsed;
};

function dataToDom(data) {
var ul = document.createElement("ul");
var num = data.length;

// limited results to a max number
if ((options.maxItemsToShow > 0) && (options.maxItemsToShow < num)) num = options.maxItemsToShow;

for (var i = 0; i < num; i++) {
var row = data[i];

if (!row) continue;
var li = document.createElement("li");
if (options.formatItem) {
li.innerHTML = options.formatItem(row, i, num);
li.selectValue = row[0];
li.otherValue = row[1];
} else {
li.innerHTML = row[0];
li.selectValue = row[0];
li.otherValue = row[1];
}
var extra = null;
if (row.length > 1) {
extra = [];
for (var j = 1; j < row.length; j++) {
extra[extra.length] = row[j];
}
}
li.extra = extra;
ul.appendChild(li);

$(li).hover(
function() { $("li", ul).removeClass("ac_over"); $(this).addClass("ac_over"); active = $("li", ul).indexOf($(this).get(0)); },
function() { $(this).removeClass("ac_over"); }
).click(function(e) {
e.preventDefault();
e.stopPropagation();
selectItem(this)
});

if (i == 0) {
$(li).addClass("ac_over");
active = 0;
}


}
$(ul).mousedown(function() {
mouseDownOnSelect = true;
}).mouseup(function() {
mouseDownOnSelect = false;
});
return ul;
};

function requestData(q) {
var data = null;
var sc = document.createElement('script');
sc.type = 'text/javascript';
sc.src = 'http://search.' + domain + '/AutoComplete.ashx?query=' + q + '&languageCode=' + lang + '&limit=10&format=script&' + Math.random();
document.getElementsByTagName('head')[0].appendChild(sc);
};

this.success = function(data, q) {
if (valueSelected) return;
if ($input.val().length < options.minChars) return;
receiveData(q, data);
}

function makeUrl(q) {
var sep = options.url.indexOf('?') == -1 ? '?' : '&';
var url = options.url + sep + "query=" + encodeURI(q);
for (var i in options.extraParams) {
url += "&" + i + "=" + encodeURI(options.extraParams[i]);
}
return url;
};

this.setExtraParams = function(p) {
options.extraParams = p;
};

function findPos(obj) {

var curleft = obj.offsetLeft || 0;
var curtop = obj.offsetTop || 0;
while (obj = obj.offsetParent) {
curleft += obj.offsetLeft
curtop += obj.offsetTop
}
return { x: curleft, y: curtop };
}

}

jQuery.fn.autocomplete = function(url, options, data) {
options = options || {};
options.url = url;
options.data = ((typeof data == "object") && (data.constructor == Array)) ? data : null;

// Set default values for required options
options = $.extend({
inputClass: "ac_input",
resultsClass: "ac_results",
lineSeparator: "\n",
cellSeparator: "|",
minChars: 3,
delay: 10,
mustMatch: 0,
extraParams: {},
loadingElement: null,
selectFirst: true,
selectOnly: true,
maxItemsToShow: 10,
width: 0,
attachedToBody: false
}, options);
options.width = parseInt(options.width, 10);
this.each(function() {
var input = this;
new jQuery.autocomplete(input, options);
});

// Don't break the chain
return this;
}

jQuery.fn.autocompleteArray = function(data, options) {
return this.autocomplete(null, options, data);
}

jQuery.fn.indexOf = function(e) {
for (var i = 0; i < this.length; i++) {
if (this[i] == e) return i;
}
return -1;
};

function bind(element) {
var url = "http://search." + domain + "/AutoComplete.ashx";
$(element).autocomplete(url, {
maxItemsToShow: 10,
selectFirst: true,
selectOnly: true,
onItemSelect: function(item, extraData) {
$("#selectedLocationID").val(item.extra[1]);
$("#selectedFileName").val(item.extra[0]);
$("#selectedCityName").val(item.selectValue);
if (!(extraData && extraData.eventType == "blur")) {
$(element).focus();
}
},
formatItem: function(row, i, num) {
var originalLength = row[0].split(",").length;
var display = row[0].ellipsisString(47);
var parts = display.split(",");
var result = "";
if (parts.length > 2) {
return result = parts[0] + ", " + parts[1] + ", <b>" + parts[2] + "</b>";
} else if (parts.length == 2 && originalLength == 3) {
return result = parts[0] + ", " + parts[1];
} else if (parts.length == 2) {
return result = parts[0] + ", <b>" + parts[1] + "</b>"
} else {
return result = parts[0];
}

},
width: 448,
extraParams: { languageCode: lang, format: "script", limit: "10" }
});
}

