/*
 * Code based on: http://www.webreference.com/programming/javascript/gr/column5/index.html
 * Modified by Peter Bryant (for RimuHosting.com and Pingability.com)
 */

/*
 * ANWB specific code
 */

/*
 * To remove the lookup button. This is only necessary if AJAX is disabled 
 * for this field or Javascript is disabled for the client's browser.
 */
function removeElementById(id) {
	var element = document.getElementById(id);
	if (element != null) {
		element.parentNode.removeChild(element);
	}
}

function readValueOfInputByName(name) {
	var inputs = document.getElementsByTagName('input');
	if (inputs != null) {
		var i, n = inputs.length;
		for ( i = 0; i < n; i++ ) {
			if (inputs[i].name ==  name) {
				return inputs[i].value;
			}
		}
	}
	alert(name + " = null");
	return null;
}

var timedAutocomplete = null;
var timedTypeAhead = false;

/*
 * Generic code for the Autocomplete
 */
function AutoComplete(oId, oText, oDiv, aArguments, aValidations, vrijeInvoer, fLoad){
	// initialize member variables
	this.oId = oId; // the id (hidden) box
	this.oText = oText; // the text box
	this.oDiv = oDiv; // a hidden <div> for the popup auto-complete
	var self = this;
	//Prevent IE from destroying the autocomplete box when user uses scroll-bar.
	oDiv.onfocus = function() {
		//JSDebugger.debug("focus");
		window.clearTimeout(self.focusProtection);
		self.showDiv();
	};
	//this.nMaxSize = 250;
	this.aArguments = aArguments;
	this.aValidations = aValidations;
	this.vrijeInvoer = vrijeInvoer;
	this.fLoad = fLoad;
	// attach handlers to the text-box
	this.oText.AutoComplete = this;
	this.oId.AutoComplete = this;
	if (this.oText.onkeyup) {
		this.oText.oldonkeyup = this.oText.onkeyup;
	}
    this.oText.onkeyup = function(event) { 
    	this.AutoComplete.sourceElemChanged(event);
    	if (self.oText.oldonkeypup) self.oText.oldonkeypup;
    };
    // Er moet een onkeypress komen om de enter toets af te vangen en form-submit te cancelen in een autocomplete veld. (issue: 0001164.6)
	if (this.oText.onkeypress) {
		this.oText.oldonkeypress = this.oText.onkeypress;
	}
    this.oText.onkeypress = function(e) {
	    var key = 0;
		var e = e||window.event;
	    if (e.keyCode) { 
	    	key = e.keyCode; 
	    } else if (typeof(e.which)!= 'undefined') { 
	    	key = e.which;
	    }
	    if (self.oText.oldonkeypress) {
	    	self.oText.oldonkeypress;
	    }
    	if (key==13) {
    		//Selecteer de huidige selectie (autocomplete zorgt hier al voor)
    		//Verberg suggestie lijst (Bestaande functionaliteit zorgt hier al voor)
    		//Cancel key13, voorkom dat formulier submit.
    		return false;
    	}
    	else return true; //ignore all other keypresses
    }
    if (this.oText.onblur) {
    	this.oText.oldonblur = this.oText.onblur;
    }
    //Aan de onblur moet een beter cancelation toegevoegt worden, zoals cancelen van timeouts en huidige httprequests. (issue 0001164.8)
    var self = this; //Closure to get a js hook back to this instance of Autocomplete
	this.oText.onblur = function() {
		//JSDebugger.debug("blur");
		//Cancel current timout (issue 0001164.8)
		window.clearTimeout(self.timeouttimer);
		//Cancel current httprequest. No access to DWR requests, setting property to keep further linked scripts from firing (issue 0001164.8).
		self.blurred = true;
		//The following code was already here before (issue 0001164.8).
		//Setting a short timeout before killing the dropdown, this gives IE a chance to keep it open.
		window.clearTimeout(self.focusProtection);
		self.focusProtection = window.setTimeout(function() {
			//JSDebugger.debug("te laat!");
			self.hideDiv();
			if (self.oText.oldblur) self.oText.oldonblur();
			if (self.oId && self.oText.value.replace(/^\s+|\s+$/g, '') == "") self.oId.value = "";
		}, 5);
	};
    this.suggestList = new Array();
    this.currentIndex = 0;
    this.timeoutbeforecall = 250; //milliseconds between keypresses 
	this.timeouttimer=null;
    this.currentTextLength = 0;
}

AutoComplete.prototype.onchange = function() {
	// set throbbing style on
	this.setThrobbingStyle();

	// validation
	var valid = this.doValidate();
	
	//Do autocomplete after at least two characters are typed and leading spaces don't count (issue 0001164.3)
	if (valid && this.oText.value.replace(/^ +/,"").length > 1) {
		// arguments buildup
		var argumentValues = null;
		if (this.aArguments != null) {
			argumentValues = new Array(this.aArguments.length);
			var i, n = this.aArguments.length;
			for ( i = 0; i < n; i++ ) {
				argumentValues[i] = readValueOfInputByName(this.aArguments[i]);
			}
		}
		// invoke the loader function
		this.fLoad(this.oText.value, argumentValues);
	} else {
		this.resetThrobbingStyle();
	}
}

AutoComplete.prototype.doValidate = function() {
	if (this.aValidations != null) {
		var i, n = this.aValidations.length;
		for ( i = 0; i < n; i++ ) {
			if (!this.aValidations[i].validate()) {
				return false;
			}
		}
	}
	return true;	
}

AutoComplete.prototype.repopulate = function(aStr) {

	this.resetThrobbingStyle();
	if (this.blurred) return true; //If the element has been blurred don't repopulate (issue 0001164.8)

	// count the number of strings that match the text-box value.
	var nCount = aStr.length;
	
	// if a suitable number then show the popup-div
	if (nCount==0 && !this.vrijeInvoer) {
//		this.oDiv.innerHTML = "";
		// Mantis 1253, geen automatische rode omlijning
//		this.addClassName("fout");
      	this.hideDiv();
		return;
	} else {
		// Mantis 1253, geen automatische rode omlijning
//		this.removeClassName("fout");
	}
	
	// clear the popup div.
    this.oDiv.innerHTML = "";

    var ul = document.createElement("ul");
    
    var self = this;

	// add each string to the popup-div
	var i, n = aStr.length;
	for ( i = 0; i < n; i++ ) { //TODO: serverside should limit suggestions default limit has been removed.
	    var li = document.createElement("li");
	    li.setAttribute("id", aStr[i].gebiedId);
	    li.naam = aStr[i].naam;
	    li.onmousedown = AutoComplete.prototype.onDivMouseDown;
		li.onmouseover = AutoComplete.prototype.onDivMouseOver;
		li.onmouseout = AutoComplete.prototype.onDivMouseOut;
		li.AutoComplete = this;
	      
	    //var liText = document.createTextNode("<![CDATA[" + aStr[i].omschrijving + "]]>");
	    //li.appendChild(liText);
	    li.innerHTML = aStr[i].omschrijving;
	    ul.appendChild(li);
    }

    this.oDiv.appendChild(ul);
    this.setSelected();
    if (timedTypeAhead) {
    	this.searchSuggestionForTypeAhead();
    }
   	this.showDiv();
    //TODO: Resize the iframe to reflect new size of the dropdown
}

AutoComplete.prototype.onDivMouseDown = function() {
	// set the text-box value to the word
//	var text = this.innerText;
//	if (!text){
//		text = "";
//		for (var i=0;i<this.childNodes.length;i++){
//			if (this.childNodes[i].nodeType==3){
//				text+=this.childNodes[i].nodeValue;
//			}
//		}
//	}
//	this.AutoComplete.oText.value = text;
    this.AutoComplete.oText.value = this.AutoComplete.suggestList[this.AutoComplete.currentIndex].naam;
    this.AutoComplete.oId.value = this.AutoComplete.suggestList[this.AutoComplete.currentIndex].id;
    if (this.AutoComplete.oId.onchange) this.AutoComplete.oId.onchange();
	if (this.AutoComplete.oText.oldblur){
		this.AutoComplete.oText.oldblur();
	}
	this.AutoComplete.hideDiv();
}

AutoComplete.prototype.onDivMouseOver = function() {
    this.AutoComplete.suggestList[this.AutoComplete.currentIndex].className = '';
    this.AutoComplete.currentIndex = this.index;
    this.AutoComplete.suggestList[this.AutoComplete.currentIndex].className = 'selected';

}

AutoComplete.prototype.onDivMouseOut = function() {
// aanzetten als laatste geselecteerde uit moet bij verlaten...
//	this.className = "";
}

AutoComplete.prototype.setThrobbingStyle = function() {
	this.addClassName('throbbing');
}

AutoComplete.prototype.resetThrobbingStyle = function() {
	this.removeClassName('throbbing');
}

AutoComplete.prototype.sourceElemChanged = function(e) {
    var key = 0;
	if (!e) var e = window.event;
    if (e.keyCode) { 
    	key = e.keyCode; 
    } else if (typeof(e.which)!= 'undefined') { 
    	key = e.which;
    }
    // default do not type Ahead
    timedTypeAhead = false;
    // if a key has been pressed this element can't be blurred... (issue 0001164.8)
    this.blurred = false;

    //up arrow
    if (key == 38) {
      if (this.currentIndex > 0) {
        this.suggestList[this.currentIndex].className = '';
        this.currentIndex--;
        this.suggestList[this.currentIndex].className = 'selected';
        //this.suggestList[this.currentIndex].scrollIntoView(false);
        this.scrollSuggest(this.suggestList[this.currentIndex], true);
        //this.selectRange(this.currentTextLength, this.oText.value.length);
        this.oText.value =  this.suggestList[this.currentIndex].naam;
        this.oId.value = this.suggestList[this.currentIndex].id;
        if (this.oId.onchange) this.oId.onchange();
      }

    //down arrow
    } else if (key == 40) {
      if (this.currentIndex >= 0 && 
          this.currentIndex < this.suggestList.length - 1) {
        this.suggestList[this.currentIndex].className = '';
        this.currentIndex++;
        this.suggestList[this.currentIndex].className = 'selected';
        // oeps, misschien is het verstandiger om te kijken waar op de pagina we staan en dan een x pixels scrollen.
        //this.suggestList[this.currentIndex].scrollIntoView(false);
        this.scrollSuggest(this.suggestList[this.currentIndex], false);
        //this.selectRange(this.currentTextLength, this.oText.value.length);
        this.oText.value =  this.suggestList[this.currentIndex].naam;
        this.oId.value = this.suggestList[this.currentIndex].id;
        if (this.oId.onchange) this.oId.onchange();
      }

    //enter
    } else if (key == 13 && (this.oDiv.style.visibility != "hidden" || this.oDiv.style.display == "none")) {
      if (this.currentTextLength == this.oText.value.length) {
        this.oText.value =  this.suggestList[this.currentIndex].naam;
        this.oId.value = this.suggestList[this.currentIndex].id;
        if (this.oId.onchange) this.oId.onchange();
      } else {
		this.selectRange(0, this.oText.value.length);      
	  }
      this.currentIndex = -1;
      this.hideDiv();
      this.stopEvent(e);

    //escape / tab / backspace while less than 2 characters are typed
    } else if (key == 27 || key == 9 || ((key == 8 && this.oText.value.replace(/^ +/,"").length <= 1))) {
      this.currentIndex = -1;
      this.hideDiv();
      this.stopEvent(e);
    	
    // all other keys  
    } else {
    	timedAutocomplete = this;
    	window.clearTimeout(this.timeouttimer);
    	if (this.oText.value.replace(/^ +/,"").length > 1) { //Start autocompleting after at least two characters are typed and leading spaces don't count (issue 0001164.3)
			this.timeouttimer = window.setTimeout("timedAutocomplete.onchange()", this.timeoutbeforecall);
		    if (key < 32 || (key >= 33 && key < 47) || (key >= 112 && key <= 123)) {
	    		timedTypeAhead = false;
		    } else {
	    		timedTypeAhead = true;
		    }
		}
		return true;
    }
    return false;
}

AutoComplete.prototype.setSelected = function() {
    this.currentIndex = 0;
    this.suggestList = this.oDiv.getElementsByTagName("li");
    if ((this.suggestList.length > 1)
       || (this.suggestList.length == 1
           && this.suggestList[0].innerHTML != this.oText)) {
      for (var i = 0; i < this.suggestList.length; i++) {
        this.suggestList[i].index = i;
      }
      this.suggestList[0].className = 'selected';
    } else {
      this.hideDiv();
    }
    return null;
}

AutoComplete.prototype.searchSuggestionForTypeAhead = function() {
	var i, n = this.suggestList.length;
	for (i = 0; i < n; i++) {
		var currentText = this.oText.value;
		this.currentTextLength = currentText.length;
		var startSuggest = this.suggestList[i].id.substring(0, this.currentTextLength);
		if (startSuggest.toUpperCase() == currentText.toUpperCase()) {
	    	window.clearTimeout(this.timeouttimer);
			this.typeAhead(this.suggestList[i].id);
		    this.suggestList[this.currentIndex].className = '';
		    this.currentIndex = i;
		    this.suggestList[this.currentIndex].className = 'selected';
	        //this.suggestList[this.currentIndex].scrollIntoView(false);
			break;
		}
	}
}


/**
 * Inserts a suggestion into the textbox, highlighting the 
 * suggested part of the text.
 * @scope private
 * @param sSuggestion The suggestion for the textbox.
 */
AutoComplete.prototype.typeAhead = function (sSuggestion /*:String*/) {

    //check for support of typeahead functionality
    if (this.oText.createTextRange || this.oText.setSelectionRange){
        var iLen = this.oText.value.length; 
        this.oText.value = sSuggestion; 
        this.selectRange(iLen, sSuggestion.length);
    }
}

/**
 * Selects a range of text in the textbox.
 * @scope public
 * @param iStart The start index (base 0) of the selection.
 * @param iLength The number of characters to select.
 */
AutoComplete.prototype.selectRange = function (iStart /*:int*/, iLength /*:int*/) {

    //use text ranges for Internet Explorer
    if (this.oText.createTextRange) {
        var oRange = this.oText.createTextRange(); 
        oRange.moveStart("character", iStart); 
        oRange.moveEnd("character", iLength - this.oText.value.length);      
        oRange.select();
        
    //use setSelectionRange() for Mozilla
    } else if (this.oText.setSelectionRange) {
        this.oText.setSelectionRange(iStart, iLength);
    }     

    //set focus back to the textbox
    this.oText.focus();      
} 

AutoComplete.prototype.stopEvent = function(event) {
	event.cancelBubble = true;
	if (event.stopPropagation) event.stopPropagation();
    if (event.preventDefault) { 
      event.preventDefault(); 
    } else {
      event.returnValue = false;
    }
}

AutoComplete.prototype.showDiv = function() {
	this.oDiv.style.visibility = "visible";
	this.oDiv.style.display = "block"; //FIX voor intranet, scripts waren niet universeel uitwisselbaar (issue mondeling gemeld)
	this.oDiv.scrollTop = 0;
	if (this.oDiv.currentStyle && !this.oIFrame) { //IE only, this is a fix for IE only, this is a safe check. (issue 0001164.2)
		var top = 0;
		var left = 0;
		
		//Get correct offset relative to div#content
		var obj = this.oDiv;
		while (obj.offsetParent && !obj.id=="content") {
			top += obj.offsetTop;
			left += obj.offsetLeft;
			obj = obj.offsetParent;			
		}
		top += obj.offsetTop;
		left += obj.offsetLeft;
		
		if (top < 1 && confirm("top: " + top)) throw error("Custom Error: Incorrect behaviour in javascript");
		
		//Create iFrame
		this.oIFrame = document.createElement("iframe");
		this.oIFrame.style.position = "absolute";
		this.oIFrame.style.left = left + "px";
		this.oIFrame.style.top = top + "px";
		this.oIFrame.src="ajaxbg.html";
		
		//Make iFrame 100% transparent
		this.oIFrame.style.filter='progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)';
		this.oIFrame.style.zIndex = "105";
		this.oDiv.style.zIndex = "106";
		
		//Append iFrame
		document.getElementById("content").appendChild(this.oIFrame);
	}
	//reset iframe height on each showDiv call (amount of items has changed)(issue 0001463)
	if (this.oIFrame) {
		//Copy dimensions
		var width = this.oDiv.offsetWidth;
		var height = this.oDiv.offsetHeight;

		//Set dimensions on iframe
		this.oIFrame.style.width = width + "px";
		this.oIFrame.style.height = height + "px";
	}
	//Calculate current position and scoll down if there's not enough space to show the div (issue 0001164.5)
	this.setSaveScrollPosition(this.oDiv.parentNode, "content", this.oDiv);
}

AutoComplete.prototype.setSaveScrollPosition = function(node, id, dropdown) { //Workaround to prevent use of .scrollIntoView issues in IE (issue 0001164.5)
	var dropHeight = dropdown?dropdown.offsetHeight:50;
	//Get dimensions and other relevant info of the scrolling container...
	var id = id||"crashtestdummy";
	var div = document.getElementById(id);
	var height = div.offsetHeight;
	var scrollHeight = div.scrollHeight;
	var scrollPosition = div.scrollTop;

	//Get dimensions and placement of target node
	var tHeight = 18;
	var top = 0;
	var left = 0;
	//Get correct offset relative to div#[id]
	var obj = dropdown;
	while (obj.offsetParent && !obj.id==id) {
		top += obj.offsetTop;
		left += obj.offsetLeft;
		obj = obj.offsetParent;
	}
	top += obj.offsetTop;
	left += obj.offsetLeft;
	
	//Set scrollTop to a safe position
	//scrollTop + height = bottom of current vissible content
	var scrollBottom = scrollPosition + height;
	//top + tHeight + dropdown's height = bottom of current dropdown
	var dropBottom = top + tHeight + dropHeight;
	//bottom of dropdown = bottom of vissible content = offset to scroll by (if negative, don't scroll)
	var scrollOffset = dropBottom - scrollBottom;
	var nScrollPosition = scrollPosition + scrollOffset + 10;
	//Prevent input field from getting scrolled out of view.
	//if (nScrollPosition > top) nScrollPosition = top;

	if (scrollOffset > 0) div.scrollTop = nScrollPosition;

	return true;
}

AutoComplete.prototype.scrollSuggest = function (li, up) {
	var parent = li.parentNode;
	while (parent!=null && parent.className!="suggest") parent = parent.parentNode;
	if (parent == null) return; //Silently drop out if no suggest box can be found...

	//Get correct offset relative to parent
	var top = 0;
	var left = 0;
	var obj = li;
	while (obj.offsetParent && obj!=parent) {
		top += obj.offsetTop;
		left += obj.offsetLeft;
		obj = obj.offsetParent;
	}
	//JSDebugger.debug("top:" + top);
	var height = li.offsetHeight;
	//JSDebugger.debug("height:" + height);
	var topPosition = parent.scrollTop;
	var bottomPosition = topPosition + parent.offsetHeight;
	//JSDebugger.debug("scroll-top/bottom:" + topPosition + "/" + bottomPosition);
	if (up && topPosition > 0 && topPosition > top) {
		parent.scrollTop = top;
	}
	else if (!up && bottomPosition < top + height) {
		var offset = top + height - bottomPosition;
		parent.scrollTop = topPosition + offset;
	}
}

AutoComplete.prototype.hideDiv = function() {
	this.oDiv.style.visibility = "hidden";
	if (this.oIFrame && this.oIFrame.parentNode) { //If this abomination was nessecary, remove it. (issue 0001164.2)
		this.oIFrame.parentNode.removeChild(this.oIFrame);
		this.oIFrame = null;
	}
}

/* from prototype.js */
AutoComplete.prototype.addClassName = function(className) {
    this.removeClassName(className);
    this.oText.className += ' ' + className;
}

/* from prototype.js */
AutoComplete.prototype.removeClassName = function(className) {
    var newClassName = '';
    var a = this.oText.className.split(' ');
    for (var i = 0; i < a.length; i++) {
      if (a[i] != className) {
        if (i > 0)
          newClassName += ' ';
        newClassName += a[i];
      }
    }
    this.oText.className = newClassName;
}

var JSDebugger = {
	DEBUG_ID:"my_little_debug_screen",
	makeDiv:function() {
		var div = document.createElement("DIV");
		div.id = this.DEBUG_ID;
		div.style.overflow = "auto";
		div.style.height = "20em";
		div.style.width = "40ex";
		div.style.position = "absolute";
		div.style.bottom = "0";
		div.style.right = "0";
		div.style.zIndex = "10000";
		div.style.backgroundColor = "#EEE";
		document.getElementsByTagName("body")[0].appendChild(div);
		return div;
	},
	debug:function(str) {
		var div = document.getElementById(this.DEBUG_ID);
		if (!div) div = this.makeDiv();
		var p = document.createElement("p");
		p.appendChild(document.createTextNode(str));
		div.appendChild(p);
		div.scrollTop = div.scrollHeight;
		//alert(str);
	}
}
