/* ---------------------------------
  @ CingoKit.Form.AutoComplete
  
  Registers a form element to utilize the autocomplete function
  This object will need to handle all data/json passing and autocomplete DOM element creation
  
  Required parameters
  - form elem ref
  - ajax xfa to send keypress data to
  
----------------------------------- */

// dialog constructor
CingoKit.Form.AutoComplete = function ( properties )
{
	// register baseclass
	this._class = CingoKit.Form.AutoComplete;
	// initialize
	this.init(properties);
}


// main functions
CingoKit.Form.AutoComplete.prototype = {

	init : function( properties )
	{
		// store properties for this dialog
		this.applyObject(properties);
		
		if (typeof(this.allowMultipleEntries) == "string") {
			switch(this.allowMultipleEntries.toLowerCase())
			{
				case "true":
				case "1":
					this.allowMultipleEntries = true;
					break;
				case "false":
				case "0":
				default:
					this.allowMultipleEntries = false;
			};
		};
		
		// set up element that will be monitored
		this.formElement = this.mgr.elem;
		this.formElement._autoComplete = this;
		
		// disable browser-level autocomplete on this form element
		setNodeAttribute(this.formElement, 'autocomplete', 'off');
		
		this.setHandler();
	},
	
	setHandler : function()
	{
		this.formElement.onkeydown = function(e)
		{
			if (window.event) {
				var e = window.event;
				var keyCode = e.keyCode;
				e.cancelBubble=true;
			} else if (e) {
				var keyCode = e.keyCode;
				if (e.stopPropagation) { e.stopPropagation() }
			} else {
				return true;
			};
			
			this._autoComplete.routeKeyPress( keyCode );
			
			if (keyCode == 13 || keyCode == 38 || keyCode == 40) return false;
		};
	},
	
	
	/**
	 * Send/receive data.
	 * Use a delayed-sending routine so ajax is not called if user is typing fast
	 */
	routeKeyPress : function( keyCode )
	{
		switch (keyCode) {
		
			case 9: // tab
			case 13: // enter
				this.selectCurrent();
				return false;
				break;
				
			case 27: // esc
				this.clearList();
				return;
				
			case 38: // up
				this.selectPrevious();
				break;
				
			case 40: // down
				this.selectNext();
				break;
				
			default:
				this.prepSend();
				break;
		}
	},
	
	prepSend : function()
	{
		// clear the interval if it's present now
		if (!isUndefinedOrNull(this.interval)) clearInterval(this.interval);
		
		// set up another one...
		var self = this;
		this.interval = setInterval( function() { self.sendData(); }, 250);
	},
	
	sendData : function()
	{
		// clear the interval
		clearInterval(this.interval);
		
		if ( !this.mgr.isTextElementValueEmpty() && this.mgr.getElementValue().length > 1 ) {
		
			var latestElements = this.mgr.getElementValue().split(",");
			var latestElement = latestElements[ latestElements.length-1 ];
			
			if (latestElement.length > 0 && latestElement != " ") {
			
				// -- begin ajax call ----------------
				var url = this.xfa;
				var qs = { 'search_value' : latestElement };
		
				var self = this;
				var d = loadXMLDoc( url, qs );
				d.addCallback(
					function(req) { self.captureResponse(req); }
				);
				d.addErrback( function( err ) {
					 if (err instanceof CancelledError) { return; }
					 logError(err);
				});
				// -- end ajax call ---------------
					
			} else {
			
				// clear out the panel if either the latest element past the comma is empty or just a space
				this.clearList();
			
			}
		} else {
		
			// clear out the panel if field is empty
			this.clearList();
			
		};
	},
	
	captureResponse : function( req )
	{
		var html = this.extractResponseHTML(req);
		
		// only run if valid html is returned
		if (!isUndefinedOrNull(html) && html.length > 0) {
			
			// show the overlay
			overlayMgr.show(0);
			overlayMgr.setClickHandler(this, 'clearList');
				
			// if the autocomplete window is not set up yet, create it
			if (isUndefinedOrNull( this.elem )) {
				this.createElement();
			};
			
			// update the innerHTML of the element
			this.elem.innerHTML = html;
			
			// initialize/reinitialize the html content
			this.registerList();
			
		}
	},
	
	
	
	/**
	 * Create the main autocomplete element
	 */
	createElement : function()
	{
		// create the main parent div element
		this.elem = DIV({ 'id' : 'autocomplete' });
		
		// set the width to match the form element
		this.elem.style.width = this.formElement.offsetWidth;
		
		// place it
		if (!isUndefinedOrNull(this.formElement.nextSibling)) {
			var insertedElement = this.formElement.parentNode.insertBefore( this.elem, this.formElement.nextSibling );
		} else {
			var insertedElement = appendChildNodes( this.formElement.parentNode, this.elem );
		}
	},
	
	/**
	 * Register the innerHTML content of the main <div> element
	 */
	registerList : function()
	{
		if (!isUndefinedOrNull(this._registration)) {
			this.clearRegistration();
		};
	
		// reset registration
		this._registration = new Array;
		
		// get the list
		var list = getFirstElementByTagAndClassName('ul', null, this.elem);;
		if (!isUndefinedOrNull(list)) {
		
			var listitems = this.sortElementsByPosition( list.getElementsByTagName('li') );
			
			// establish list items for each list item
			for (var i=0; i<listitems.length; i++) {
				
				// first, capture the previous sibling
				var prevSibling = (this._registration.length > 0) ? this._registration[ this._registration.length-1 ] : null;
				
				// register it
				this._registration.push(
					new CingoKit.Form.AutoCompleteListElement({
						'mgr' : this,
						'elem' : listitems[i],
						'prevSibling' : prevSibling
					})
				);
				
			};
		};
		
		// set the first one as the current
		if (this._registration.length > 0) {
			this._registration[0].activate();
		};
	},
	
	sortElementsByPosition : function( elements )
	{
		// first, build an array of all y-positions
		var positions = new Array;
		var sorted = new Array;
		
		// loop through the children
		for (var i=0; i<elements.length; i++) {
			var element = elements[i];
			// get y-pos
			var y = getElementPosition(element).y
			// apply an id to the child
			element.__ypos = y;
			// add the position to the array
			positions.push(y);
		};
		
		// sort the positions array
		positions.sort( function (a,b){return a-b} );
		
		// now, go through the positions
		while (positions.length > 0)
		{
			// get the position to test
			var testPos = positions.shift();
			
			// loop through the children
			for (var i=0; i<elements.length; i++) {
				var element = elements[i];
				if (element.__ypos == testPos) {
					sorted.push( element );
					break;
				};
			};
		};

		return sorted;
	},
	
	clearRegistration : function()
	{
		if (!isUndefinedOrNull(this._registration)) {
			for (var i=0; i<this._registration.length; i++) {
				delete(this._registration[i]);
			};
		};
	},
	
	clearList : function()
	{
		// hide the overlay
		overlayMgr.hide();
		
		// clear registration
		this.clearRegistration();
		
		// reset the current list element
		this._currentListElement = null;
		
		// remove the node entirely
		if (!isUndefinedOrNull(this.elem)) {
			removeElement(this.elem);
			this.elem = null;
		};
	},
	
	
	/**
	 * Manage list elements
	 */
	resetCurrent : function()
	{
		if (!isUndefinedOrNull(this._currentListElement)) {
			this._currentListElement.reset();
		};
	},
	
	selectCurrent : function()
	{
		if (!isUndefinedOrNull(this._currentListElement)) {
			
			// set the value
			var newvalue = this._currentListElement._value;
			var comma = this.allowMultipleEntries ? ", " : "";
			
			// if multipleEntries is allowed, only replace the latest entry
			var preface = "";
			
			if (this.allowMultipleEntries && this.mgr.getElementValue().indexOf(",") != -1) {
			
				var elements = this.mgr.getElementValue().split(",");

				if (elements.length > 0) {
					
					// remove the latest element
					var removedElement = elements.pop();
					
					// convert to string
					preface = elements.toString() + ", ";
					
				};
			};
			
			this.mgr.setElementValue( preface + newvalue + comma );
			
		};
		
		// clear the list
		this.clearList();
	},
	
	selectPrevious : function()
	{
		if (!isUndefinedOrNull(this._currentListElement)) {
			this._currentListElement.selectPrevious();
		};
	},
	
	selectNext : function()
	{
		if (!isUndefinedOrNull(this._currentListElement)) {
			this._currentListElement.selectNext();
		};
	}
	
	
};





/* ---------------------------------
  @ CingoKit.Form.AutoCompleteListElement
  
  Registers a list element that has been returned from an autocomplete ajax call
----------------------------------- */

// dialog constructor
CingoKit.Form.AutoCompleteListElement = function ( properties )
{
	// register baseclass
	this._class = CingoKit.Form.AutoCompleteListElement;
	
	this.init(properties);
}


// main functions
CingoKit.Form.AutoCompleteListElement.prototype = {

	init : function( properties )
	{
		// store properties but don't init yet...
		this.applyObject(properties);
		
		this._value = getNodeAttribute(this.elem, 'value');
		
		// set the nextSibling
		this.nextSibling = null;
		if (!isNull(this.prevSibling)) {
			this.prevSibling.nextSibling = this;
		};
		
		// set up mouse handlers
		this.elem._obj = this;
		this.elem.onmouseover = function() { this._obj.activate() };
		this.elem.onclick = function(e)
		{
			this._obj.mgr.selectCurrent()
			if(!e)var e=window.event;e.cancelBubble=true;if(e.stopPropagation)e.stopPropagation();
		};
	},
	
	activate : function()
	{
		this.mgr.resetCurrent();
		
		if (!hasElementClass(this.elem, 'active')) {
			addElementClass(this.elem, 'active');
		};
		
		this.setAsCurrent();
	},
	
	reset : function()
	{
		removeElementClass(this.elem, 'active');
	},
	
	
	// management of which one is current
	setAsCurrent : function()
	{
		this.mgr._currentListElement = this;
	},
	
	
	// navigation
	selectPrevious : function()
	{
		// reset current
		if (!isNull(this.prevSibling)) {
			this.prevSibling.activate();
		};
	},
	
	selectNext : function()
	{
		// reset current
		if (!isNull(this.nextSibling)) {
			this.nextSibling.activate();
		};
	}
	
};




// Inherit from CingoKit.Base
setdefault(CingoKit.Form.AutoComplete.prototype, CingoKit);	
setdefault(CingoKit.Form.AutoCompleteListElement.prototype, CingoKit);