/*******************************************************************************
	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. Jezeli miejsc bedzie bardzo duzo, to powinno
			to korzystac z AJAX, natomiast jezeli lokalizacji
			nie bedzie zbyt wiele to mozemy przekazac ich liste
			wpisana w htmla lub zaszyta w jakis dodatkowy javascript.

			Wymaga:	cms/external/cdajax/cdajax.js

	$Id: destination.js,v 1.1 2007/10/31 10:27:19 mwlodar Exp $
*******************************************************************************/


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

	/**
	 * element, ktory nasluchujemy
	 */
	this.inputElement = iInputElement;
	/**
	 * Adres URL serwera
	 */
	this.rootUrl = iRootUrl ? iRootUrl : "www.adorohotels.com";
	/**
	 * Wlaczenie mapy, po wyborze punktu centrujemy mape ponownie na wskazany punkt,
	 * uwaga, parametr odwrotny do inicjacji, domyslnie jest wylaczone
	 * Jezeli jest wlaczone, to szukamy statycznej funkcji przesuwajacej mapke
	 * Domyslnie, mozemy przesuwac tylko jedna mapke - to ostatnia ze strony
	 */
	this.enableCitymap = iEnableCitymap ? true : false;



	/**
	 * akcja http - wyszukiwanie elementow
	 *	FIXME
	 */
	 
	this.searchAction =  "http://www.adorohotels.com/index.php?pid=301";


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

	/**
	 * 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
	 * zapamietamy ta funkcja w momencie rysowania listy a skasujemy w momencie usuniecia narysowanej listy
	 */
	this.documentBodyOnClick = null;

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


	/**
	 * Wskaznik na siebie
	 */
	var 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;
	
	/**
	 * Dodatkowa akcja, ktora bedzie wykonana gdy zaladujemy juz dane
	 */

	this.onload = function() {
		oThis.filter();
		oThis.repaint();
	}
}

/**
 * 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 ) {
		this.loadingStarted = false;
		this.loadingDone = false;
		clearTimeout( this.searchTimeout ) ;
		this.dropList();
		return;
	}
	// gdy juz szukalismy tego
	if ( this.inputElement.value == this.oldSearchRequest ) {
		clearTimeout( this.searchTimeout ) ;
		return;
	}
	// ladowanie danych, jezeli nie zostalu juz zaladowane
	this.load();
	
	if ( this.loadingDone ) 
	{
		this.filter();
		this.repaint();
	}
}
/**
 * Ladowanie danych, jezeli nie zostalu juz wczesniej zaladowane 
 */
DestinationAutoComplete.prototype.load = function( oEvent ) {
	var oThis = this;
	if ( ! ( this.loadingStarted || this.loadingDone ) ) {
		this.loadingStarted = true;
		this.loadingDone    = false;

		cdAJAX.setDefaultParameters({
			group: null,
			unique: true
		});
		cdAJAX.get({
			url: oThis.searchAction,
			parameters : {
				"search" : oThis.inputElement.value,
				"addhotels": oThis.kozak 
			},
			onSuccess : function ( obj ) {
				var destinations = getDestinationsResponse();
				oThis.loadList( destinations );
				oThis.loadingDone = true;
				getDestinationsResponse = null;
				if ( oThis.onload ) {
					if( oThis.kozak )
					{
						oThis.onload();
					}
					oThis.kozak = true;
				}
			},
			onError : function( obj ) {
				oThis.raiseError( "Error while fetching destinations: " + obj.status );
			}
		});
	}
}


/** 
 * 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
			if ( this.elements.length > 0 ) {
				this.select( this.elements[ this.currentList ] );
			}
			break;
		case 9:
			// TAB 
			if ( this.elements.length > 0 ) {
				this.select( this.elements[ this.currentList ] );
			} else {
				this.dropList();
			}
			break;
		default:
			//
			this.activeElement = null;
			break;
	}
	return false;
}

/**
 * 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;
	this.documentBodyOnClick = null;
}

/**
 * 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 );
}

DestinationAutoComplete.prototype.raiseError = function( message ) {
	alert( message );
}


/**
 * Wczytanie danych
 */
DestinationAutoComplete.prototype.loadList = function( destinations ) {
	this.allElements = destinations;
}

/**
 * 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
	if ( ! this.documentBodyOnClick ) {
		this.documentBodyOnClick = document.body.onclick;
	}
	var oThis = this;
	var tmpFn = function() {
		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;
	if(this.enableCitymap){
		this.citymapMoveTo(element.lat,element.lng,element.zoom);
	}
	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;
}

/**
 * Pobranie elementu z listy wszystkich elementow,
 * Funkcja moze byc uzyteczna do sprawdzenie, czy element jest na liscie
 * Funkcja zaklada, ze elementy zostaly juz zaladowane
 */
DestinationAutoComplete.prototype._getFromAllElements = function( type, id ) {
	for ( var i = 0; i < this.allElements.length; i++ ) {
		var el = this.allElements[i]
		if ( el.type != type ) continue;
		if ( el.id != id ) continue;
		return el;
	}
	return null;
}


/**
 * Ustawienie wybranego elementu na liscie wyszukiwania,
 * pod warunkiem ze dane zostalu juz zaladowane
 */
DestinationAutoComplete.prototype._set = function( type, id ) {
	var el = this._getFromAllElements( type, id );
	if ( ! el ) return;
	this.activeElement = el;
	this.inputElement.value = el.name;
}


/**
 * Ustawienie wybranego elementu na liscie
 * Jezeli dane nie zostaly jeszcze zaladowane to je ladujemy
 */
DestinationAutoComplete.prototype.set = function( type, id ) {
	if ( this.loadingDone ) {
		this._set( type, id );
		return;
	}
	this.load();
}

DestinationAutoComplete.prototype.setOne = function( type, id, name, bookings ) {
	this.inputElement.value = name;
	this.kozak = false;
	this.load();
	var	el = new Array();
	el.type = type;
	el.id = id;
	el.name = name;
	el.bookings = bookings;
	this.activeElement = el;
	return;
}


/**
 * Przesuwanie mapka, 
 * Jezeli na stronie jest mapka - obiekt Citymap
 * To probuje wywolac statyczna funkcje przesuwajaca ten obiekt
 */
DestinationAutoComplete.prototype.citymapMoveTo = function( lat, lng, zoom ) {
	if("undefined" == typeof CityMap){
		return;
	}
	CityMap.moveCurrentMapTo(lat, lng, zoom);
}
