var KMPRunning = false;
var KMPPhrase = null;
var toReturn;
var store = 0;
var interval = 300;
var selectedLi = 0;
var sumLi = 0;

function addAutocompleter(element) {
    //------------------------------ adding choices DIV ---------------------
    var choicesDiv = document.createElement('ul');
    choicesDiv.id = element.name + '_choices';
    choicesDiv.className = 'suggest';
    choicesDiv.style.display = 'none';
//    if (!Prototype.Browser.IE) {
    	if ((window.location.hostname == 'iflight.pl' || window.location.hostname == 'www.iflight.pl') && !Prototype.Browser.IE) {
    		choicesDiv.style.top = Number(element.offsetTop + element.offsetHeight + 2) + 'px';
    		choicesDiv.style.left = element.offsetLeft + 'px';
    	} else if (window.location.hostname == 'www.uni-fly.pl' || window.location.hostname == 'uni-fly.pl') {
			choicesDiv.style.top = Number(83 + element.getDimensions().height + 1) + 'px';
			choicesDiv.style.left = Number(element.cumulativeOffset().left - 162) + 'px';
		} else {
			choicesDiv.style.top = Number(element.cumulativeOffset().top + element.getDimensions().height + 1) + 'px';
			choicesDiv.style.left = element.cumulativeOffset().left + 'px';
		}
//    }
    element.insert({after: choicesDiv});
	element.setAttribute('autocomplete', 'off');
	Event.observe(element, 'focus', function(event) {
        element.activate(); 
    });
	Event.observe(element, 'keyup', function(event) {
		switch(event.keyCode) {
	       case Event.KEY_RETURN:
	       case Event.KEY_ESC:
	       case Event.KEY_LEFT:
	       case Event.KEY_RIGHT:
	       case Event.KEY_UP:
	       case Event.KEY_DOWN:
	         return;
	       default:
	    	   element = new Event.element(event);
				KMPPhrase = element.value.toLowerCase();
				if ((new Date()).getTime() - store > interval) {
					if (KMPRunning == false) {
						if (element.value.length > 2) {
							store = (new Date()).getTime();
							choicesDiv.innerHTML = getMatches(element.value.toLowerCase());
							sumLi = getChoicesSum(element);
							selectedLi = 0;
							renderChoicesDiv(element);
							addAutocompleterLiObservers(element);
							choicesDiv.style.display = '';
						} else {
							choicesDiv.style.display = 'none';
							selectedLi = 0;
						}
					}
				}
	      }
	});
	Event.observe(element, 'keypress', function(event) {
		var airportId = $(element.id + 'id');
		switch(event.keyCode) {
	       case Event.KEY_RETURN:
	         selectEntryChoicesDiv(element);
	         Event.stop(event);
	       case Event.KEY_ESC:
	    	 hideChoicesDiv(element);
	         Event.stop(event);
	         return;
	       case Event.KEY_LEFT:
	       case Event.KEY_RIGHT:
	         return;
	       case Event.KEY_UP:
	         markPreviousChoicesDiv(element);
	         renderChoicesDiv(element);
	         Event.stop(event);
	         return;
	       case Event.KEY_DOWN:
	         markNextChoicesDiv(element);
	         renderChoicesDiv(element);
	         Event.stop(event);
	         return;
	       default:
	    	 airportId.value = "";
	      }
	});
	Event.observe(element, 'blur', function(event) {
		choicesDiv.innerHTML = '';
		choicesDiv.style.display = 'none';
	});
	Event.observe(choicesDiv, 'mouseover', function(event) {
		element.stopObserving('blur');
	});
	Event.observe(choicesDiv, 'mouseout', function(event) {
		renderChoicesDiv(element);
		Event.observe(element, 'blur', function(event) {
			choicesDiv.innerHTML = '';
			choicesDiv.style.display = 'none';
		});
	});
}

function hideChoicesDiv(element) {
	var choicesDiv = $(element.name+'_choices');
	hideElement(choicesDiv);
	selectedLi = 0;
}

function getChoicesSum(element) {
	var choicesDiv = $(element.name+'_choices');
	var sum = 0;
	choicesDiv.descendants().each(function(elem) {
		if (elem.tagName == 'LI') {
			++sum;
		}
	});
	return sum;
}

function getSelectedLi(element) {
	var toRet = null;
	var choicesDiv = $(element.name+'_choices');
	choicesDiv.descendants().each(function(elem) {
		if (elem.tagName == 'LI') {
			if (elem.hasClassName('selected')) {
				toRet = elem;
				return;
			}
		}
	});
	return toRet;
}

function getSelectedId(element) {
	var toRet = null;
	var choicesDiv = $(element.name+'_choices');
	var c = 0;
	choicesDiv.descendants().each(function(elem) {
		if (elem.tagName == 'LI') {
			if (elem.hasClassName('selected')) {
				toRet = c;
				return;
			}
			++c;
		}
	});
	return toRet;
}

function selectEntryChoicesDiv(element) {
	var elem = getSelectedLi(element);
	var choicesDiv = $(element.name+'_choices');
	var airportId = $(element.id+'id');
	
	if (choicesDiv.style.display != 'none') {
		airportId.value = elem.down('span').innerHTML;
		element.value = elem.down('strong').innerHTML;
		choicesDiv.innerHTML = '';
		choicesDiv.style.display = 'none';
		selectedLi = 0;
	}
}

function markNextChoicesDiv(element) {
	var choicesDiv = $(element.name+'_choices');
	if (selectedLi < sumLi - 1) {
		++selectedLi;
	} else {
		selectedLi = 0;
	}
}

function markPreviousChoicesDiv(element) {
	var choicesDiv = $(element.name+'_choices');
	if (selectedLi > 0) {
		--selectedLi;
	} else {
		selectedLi = sumLi - 1;
	}
}

function resetChoicesDiv(element) {
	var choicesDiv = $(element.name+'_choices');
	choicesDiv.descendants().each(function(elem) {
		if (elem.tagName == 'LI') {
			if (elem.hasClassName('selected'))
				elem.removeClassName('selected');
		}
	});
}

function renderChoicesDiv(element) {
	var choicesDiv = $(element.name+'_choices');
	var c = 0;
	choicesDiv.descendants().each(function(elem) {
		if (elem.tagName == 'LI') {
			if (selectedLi == c) {
				elem.addClassName('selected');
			} else {
				if (elem.hasClassName('selected'))
					elem.removeClassName('selected');
			}
			++c;
		}
	});
}

function addAutocompleterLiObservers(element) {
	var choicesDiv = $(element.name+'_choices');
	var airportId = $(element.id+'id');
	
	choicesDiv.descendants().each(function(elem) {
		if (elem.tagName == 'A') {
			Event.observe(elem, 'click', function(event) {
				airportId.value = elem.down('span').innerHTML;
				element.value = elem.down('strong').innerHTML;
				choicesDiv.innerHTML = '';
				choicesDiv.style.display = 'none';
				selectedLi = 0;
				event.preventDefault();
			});
		}
		if (elem.tagName == 'LI') {
			Event.observe(elem, 'mouseover', function(event) {
				resetChoicesDiv(element);
				elem.addClassName('selected');
				selectedLi = getSelectedId(element);
				renderChoicesDiv(element);
			});
			Event.observe(elem, 'mouseout', function(event) {
				elem.removeClassName('selected');
			});
		}
	});
}

function getMatches(pattern) {
	KMPRunning = true;
	toReturn = KMPRun(pattern);
	if (KMPPhrase != pattern) {
		toReturn = getMatches(KMPPhrase);
	}
	return toReturn;
}

function KMPRun(pattern) {
	var matches = new Array();
	if (airportsLowercase) {
		var matchesPos = kmp(airportsLowercase, '*'+pattern);
		
		matchesPos.each(function(pos) {
			matches.push(_makeHTML(airports.substring(airports.lastIndexOf(';', pos) + 1, airports.indexOf(';', pos))));
		});
	} else {
		throw 'Airports array not found';
	}
	matches = matches.uniq();
	
	var html = '';
	matches.each(function(string) {
		html += string;
	});
	KMPRunning = false;
	return html;
}

function _makeHTML(string) {
	var temp = string.split("*");
	return '<li><a href=""><span>'+temp[0]+'</span> <strong>'+temp[2]+' ('+temp[1]+')</strong><br/>'+temp[3].substring(1)+'</a></li>';
}

function kmp (text, pattern) {
   var kmpResults = new Array();
   var fail = computeFailFunction(pattern);
   var i = 0;
   var j = 0;

   while (i < text.length) {
     if (pattern.charAt(j) == text.charAt(i)) {
       if (j == pattern.length - 1)
         kmpResults.push(i - pattern.length + 1); // match
       i++;
       j++;
     } 
     else if (j > 0)
       j = fail[j - 1];
     else
       i++;
   }
   return kmpResults;
 }

function computeFailFunction(pattern) {
   var fail = new Array(pattern.length); 
   fail[0] = 0;
   var j = 0;
   var i = 1;
   while (i < pattern.length) {
     if (pattern.charAt(j) == pattern.charAt(i)) { // j + 1 characters match
       fail[i] = j + 1;
       i++;
       j++;
     }
     else if (j > 0) // j follows a matching prefix
       j = fail[j - 1];
     else { // no match
       fail[i] = 0;
       i++;
     }
   }
   return fail;
 }

