/*******************************************************************************
	EasyWEB	5

	@Copyright 	Synerway Sp. z o. o. http://www.synerway.pl/
			All rights reserved

	@Author		Antoni Jakubiak <a.jakubiak@synerway.pl>


	@Description
			Wyszukiwarka docelowych miejsc pobytu.

			Zadaniem wyszukiwarki jest automatyczne kompletowanie
			nazwy lokalizacji na bazie liter wprowadzonych
			przez internaute.

			TODO. Jeżeli miejsc będzie bardzo dużo, to powinno
			to korzystać z AJAX, natomiast jeżeli lokalizacji
			nie będzie zbyt wiele to możemy przekazać ich listę
			wpisana w htmla lub zaszyt± w jaki¶ dodatkowy javascript.

			Wymaga:	cms/external/advajax/advajax.js

	$Id: destination.js,v 1.1.4.2 2007/04/06 11:52:39 mgil Exp $
*******************************************************************************/


/**
 * Utworzenie elementu automatycznej listy
 */
function DestinationAutoComplete( iInputElement )   {
	/**
	 * Prefix, identyfikator tworzonych elementow
	 */
	this.idPrefix = 'destinationAutoCompleteElement_';

	/**
	 * element, ktory nasluchujemy
	 */
	this.inputElement = iInputElement;

	/**
	 * akcja http - wyszukiwanie elementow
	 */
	this.searchAction = 'index.php?pid=301';

	/**
	 * Po ilu znakach mamy rozpoczac wyszukiwania
	 */
	this.minChars = 1;

	/**
	 * Maksymalna liczba elementow na liscie
	 */
	this.maxElementsOnList = 9;


	/**
	 * Wskaznik, na liste (element) w tym elemencie beda sie zawierac kolejne elementy
	 */
	this.listRootElement = null;

	/**
	 * Elementy na liscie
	 */
	this.elements = new Array();
	/**
	 * Wszystkie elementy
	 */
	this.allElements = new Array();

	/**
	 * Aktualnie podswietlany element listy
	 */
	this.currentList = 0;
	/**
	 * Aktualnie podswietlany element listy
	 */
	this.startList = 0;

	/**
	 * To czego szukalismy wczesniej
	 */
	this.oldSearchRequest = '';


	/**
	 * Czy rozpoczelismy juz wczytywanie danych
	 */
	this.loadingStarted = false;
	/**
	 * Czy wczytalismy juz dane
	 */
	this.loadingDone = false;



	/**
	 * Funkcja aktywowana po kliknieciu gdziekolwiek na dokumencie
	 */
	this.documentBodyOnClick = document.body.onclick;

	/**
	 * czy ruch myszka jest aktywny
	 */
	this.mouseMoveActive = true;


	/**
	 * Wskaznik na siebie
	 */
	oThis = this;



	/**
	 * keyup
	 */
	iInputElement.onkeyup = function() {
		var oEvent = arguments[0] || window.event;
		oThis.keyUp( oEvent );
	}
	/**
	 * keydown
	 */
	iInputElement.onkeydown = function() {
		var oEvent = arguments[0] || window.event;
		oThis.keyDown( oEvent );
	}

	/**
	 * aktualnie wybrany element
	 */
	this.activeElement = null;
}


/**
 * gdy user podniesie klawisz to wyszukujemy
 */
DestinationAutoComplete.prototype.keyUp = function( oEvent ) {
	a = oEvent.keyCode;
	switch ( oEvent.keyCode ) {
		case 38:
		case 40:
		case 13:
		case 9:
			return false;
	}

	// gdy nic nie ma do szukania
	if ( this.inputElement.value.length < this.minChars ) {
		clearTimeout( this.searchTimeout ) ;
		this.dropList();
		return;
	}
	// gdy juz szukalismy tego
	if ( this.inputElement.value == this.oldSearchRequest ) {
		clearTimeout( this.searchTimeout ) ;
		return;
	}

	this.searchList();

}

DestinationAutoComplete.prototype.searchList = function() {
	var oThis = this;

	if ( ! this.loadingStarted ) {
		this.loadingStarted = true;
		this.loadingDone    = false;
		advAJAX.get({
			url: oThis.searchAction,
			parameters : {
				"search" : oThis.inputElement.value
			},
			onSuccess : function ( obj ) {
				oThis.loadList( obj );
				oThis.filter();
				oThis.repaint();
			}
		});
	}
	if ( this.loadingDone ) {
		this.filter();
		this.repaint();
	}
}


/**
 * Gdy nacisniemy klawisz to
 */
DestinationAutoComplete.prototype.keyDown = function ( oEvent ){
	a = oEvent.keyCode;
	switch ( oEvent.keyCode ) {
		case 38:
			// do gory
			this.currentList--;
			if ( this.currentList < 0 ) this.currentList = 0;
			this.stopMouseMove();
			this.repaint();
			break;
		case 40:
			// do dolu
			this.currentList++;
			if ( this.currentList >= this.elements.length ) this.currentList = this.elements.length - 1;
			this.stopMouseMove();
			this.repaint();
			break;
		case 13:
			// enter
			this.selectCurrentElement();
			break;
		case 9:
			// TAB
			this.selectCurrentElement(1);
			break;
		default:
			//
			this.activeElement = null;
			break;
	}
	return false;
}

DestinationAutoComplete.prototype.selectCurrentElement = function(drop) {
			if ( this.elements.length > 0 ) {
				this.select( this.elements[ this.currentList ] );
			} else if (drop) {
				this.dropList();
			}
}
/**
 * Ukrywanie listy elementow
 */
DestinationAutoComplete.prototype.dropList = function() {
	this.showSelect();
	if ( this.listRootElement ) {
		document.body.removeChild( this.listRootElement );
		this.listRootElement = null;
	}
	this.elements = new Array();
	this.currentList = 0;
	this.startList = 0;
	this.oldSearchRequest = '';
	document.body.onclick = this.documentBodyOnClick;
}

/**
 * Utworzenie elementu nadrzednego dla listy
 */
DestinationAutoComplete.prototype.createRootListElement = function() {
	this.listRootElement = document.createElement('div');
	var p = this.getAbsolutePos( this.inputElement );
	this.listRootElement.className      = 'autocomplete';
	this.listRootElement.style.position = 'absolute';
	this.listRootElement.style.top      = ( p[3] ) + 'px';
	this.listRootElement.style.left     = ( p[0] ) + 'px';			// TODO, pozycja z jakiegos konfiga
	this.listRootElement.style.width    = ( p[2] - p[0] + 10 ) + 'px';
	document.body.appendChild( this.listRootElement );
}

/**
 * Element na liscie do utworzenia
 */
DestinationAutoComplete.prototype.createListElement = function ( element, display, id ) {
	this.elements.push( element );
	var div             = document.createElement('div');
	div.className       = 'element';
	var underLine       = element.name.replace( new RegExp( '(' + this.inputElement.value + ')', 'i'  ), '<u>$1</u>' );
	div.innerHTML       = '<span classname="'+element.type+'">' + underLine + '</span>';
	div.style.display   = display ? 'block' : 'none';
	div.id              = this.idPrefix + this.inputElement.id + id;
	var oThis           = this;
	div.onmouseover     = function() { me = arguments[0] || window.event; return oThis.mouseOver( me ); };
	div.onmouseout      = function() { me = arguments[0] || window.event; return oThis.mouseOut( me ); };
	div.onclick         = function() { me = arguments[0] || window.event; return oThis.click( me ); };
	this.listRootElement.appendChild( div );
}


/**
 * Wczytanie danych
 */
DestinationAutoComplete.prototype.loadList = function( obj ) {
	// przed narysowaniem listy czyscimy liste
	if ( ! obj.responseXML ) return;

	// mozemy wyswietlic liste elementow
	var a = obj.responseXML.getElementsByTagName('destination');
	for ( var i = 0; i < a.length; i++ ) {
		// interesuja nas tylko obiekty
		if ( 'object' != typeof a.item(i) ) continue;
		var type = a.item(i).getAttribute('type');
		var id   = a.item(i).getElementsByTagName('id').item(0).firstChild.nodeValue;
		var name = a.item(i).getElementsByTagName('name').item(0).firstChild.nodeValue;
		this.allElements.push( {id:id,name:name,type:type} );
	}
	this.loadingDone = true;
}

/**
 * Filtrowanie i sortowanie danych
 */
DestinationAutoComplete.prototype.filter = function() {
	this.dropList();
	this.createRootListElement();
	var j = 0;
	var re = new RegExp( this.inputElement.value, 'i' );
	var toSort = new Array();
	// filtrowanie
	for ( var i = 0; i < this.allElements.length; i++ ) {
		var e = this.allElements[i];
		// sprawdzenie, czy tekst pasuje
		if ( ! re.test( e.name ) ) continue;
		toSort.push( e );
	}
	// sortowanie, jezeli pasuje z przodu to lepiej
	var reSort = new RegExp( '^' + this.inputElement.value, 'i' );
	toSort.sort( function( a, b ) {
		var ac = reSort.test( a.name );
		var bc = reSort.test( b.name );
		if ( ac == bc ) return 0;
		if ( ac ) return -1;
		if ( bc ) return  1;
		return 0;
	} );
	// dopisywanie
	for ( var i = 0; i < toSort.length; i++ ) {
		var e = toSort[i];
		// dopisanie elementu do listy elementow wyswietlanych
		this.createListElement( e, j < this.maxElementsOnList, j );
		j++;
	}
	if ( 0 == j ) {
		this.dropList();
	}
}



/**
 * Odswiezenie elementow na liscie
 */
DestinationAutoComplete.prototype.repaint = function() {
	this.activeElement = null;
	if ( ! this.listRootElement ) return;
	var divs = this.listRootElement.getElementsByTagName('div');
	var j = 0;
	if( this.currentList >= this.startList + this.maxElementsOnList ) {
		this.startList = this.currentList - this.maxElementsOnList + 1;
	} else if ( this.currentList < this.startList ) {
		this.startList = this.currentList;
	}
	for ( var i in divs ) {
		if ( 'object' != typeof divs[i] ) continue;
		divs[i].style.display = j >= this.startList && j < this.startList + this.maxElementsOnList ? 'block' : 'none';
		divs[j].className = j == this.currentList ? 'element over' : 'element';
		j++;
	}
	// ukrycie selektow pod spodem listy, poprawka dla IE
	this.hideSelect();
	// wylaczenie listy gdy ktos kliknie gdziekolwiek myszka
	var oThis = this;
	var tmpFn = function() {
		oThis.documentBodyOnClick = document.body.onclick;
		document.body.onclick = function() {
			oThis.dropList();
		}
	}
	setTimeout( tmpFn, 50 );
}

/**
 * gdy myszka jest nad elementem
 */
DestinationAutoComplete.prototype.mouseOver = function() {
	if ( ! this.mouseMoveActive ) return;
	var mouseEvent = arguments[0] || window.event;
	this.currentList = this.getTargetIdForMouseEvent( mouseEvent );
	this.repaint();
}
/**
 * gdy myszka oposcila element
 */
DestinationAutoComplete.prototype.mouseOut = function() {
}
/**
 * po kliknieciu przyciskiem myszki na element
 */
DestinationAutoComplete.prototype.click = function() {
	var mouseEvent = arguments[0] || window.event;
	var currentList = this.getTargetIdForMouseEvent( mouseEvent );
	this.select( this.elements[ currentList ] );
}
/**
 * po wybranie czegos ma sie uruchomi ta funkcja
 */
DestinationAutoComplete.prototype.select = function( element ) {
	this.inputElement.value = element.name;
	this.activeElement = element;
	this.dropList();
}


/**
 * Czasowe zatrzymanie poruszanie aktywnosci myszki
 */
DestinationAutoComplete.prototype.stopMouseMove = function() {
	this.mouseMoveActive = false;
	var oThis = this;
	var tmpFn = function() {
		oThis.mouseMoveActive = true;
	}
	setTimeout( tmpFn, 100 );
}


/**
 * Znalezienie elementu listy powiazanego z zdarzeniem myszki
 */
DestinationAutoComplete.prototype.getTargetIdForMouseEvent = function( mouseEvent ) {
	var target;
	if (mouseEvent.target) {
		target = mouseEvent.target;
	} else if (mouseEvent.srcElement) {
		target = mouseEvent.srcElement;
	}
	if ( ! target ) return;

	if (target.nodeType == 3) {
		// defeat Safari bug
		target = target.parentNode;
	}
	while( 'DIV' != target.tagName.toUpperCase() ) {
		target = target.parentNode;
	}
	var re = new RegExp( this.idPrefix + this.inputElement.id + "([0-9]+)" );
	var ma = re.exec( target.id );
	return ma[1];

}



/**
 * Pozycja elementu absolutna na stronie
 */
DestinationAutoComplete.prototype.getAbsolutePos = function ( oElem ) {
	var oTemp = typeof oElem == 'string' ? document.getElementById( oElem ) : oElem;
	oElem = oTemp;
	var absLeft = 0, absTop = 0;
	while ( oTemp ) {
		absTop += oTemp.offsetTop;
		absLeft += oTemp.offsetLeft;
		oTemp = oTemp.offsetParent;
	}
	return new Array(absLeft, absTop, absLeft + oElem.offsetWidth, absTop + oElem.offsetHeight );
}


/**
 * Pobranie aktualnej wartosci
 *	sprawdzamy, czy aktualna wartosc jest zapisane w zmiennej prywatnej.
 *	jezeli tak to jupi
 *	jezeli nie to probujemy znalezc wartosc, ktorej nazwa jest rowna szukanemu tekstowi
 *	jezeli sie udalo, to zwracamy pierwsza znaleziona wartosc
 *	jezeli sie nie udalo to zwracamy null
 */
DestinationAutoComplete.prototype.get = function() {
	if ( this.activeElement ) return this.activeElement;
	var v = this.inputElement.value.toUpperCase();
	for ( var i = 0; i < this.allElements.length; i++ ) {
		var e = this.allElements[i];
		if ( v == e.name.toUpperCase() ) {
			this.activeElement = e;
			return e;
		}
	}
	return null;
}

/**
 * Ukrycie selektow pod spodem listy
 */
DestinationAutoComplete.prototype.hideSelect = function() {
	this.showSelect();
	this._selects = new Array();
	if ( ! this.listRootElement ) return;
	var pm = this.getAbsolutePos( this.listRootElement );
	var selects = document.getElementsByTagName('select');
	for ( var i in selects ) {
		var el = selects[i];
		if ( this._inSelects( el ) ) continue;
		if( 'object' != typeof el ) continue;
		var ps = this.getAbsolutePos( el );
		if ( ( pm[2] < ps[0] || pm[3] < ps[1] ) || ( pm[0] > ps[2] || pm[1] > ps[3] ) ) continue;
		var lastVisibility = el.style.visibility;
		el.style.visibility='hidden';
		this._selects.push( new Array( el, lastVisibility ) );
	}
}

/**
 * Pokazanie ukrytych selektow
 */
DestinationAutoComplete.prototype.showSelect = function() {
	if ( ! this._selects ) return;
	var i;
	while( i = this._selects.pop() ) {
		i[0].style.visibility = i[1];
	}
}


/**
 * Sprawdzamy, czy element jest juz na liscie ukrytych selektow
 */
DestinationAutoComplete.prototype._inSelects = function( iTest ) {
	var i;
	while( i in this._selects ) {
		if ( this._selects[i][0] == iTest ) return true;
	}
	return false;
}


