function $(id)
{
    return document.getElementById(id);
}

function msiev()
{ //javascript:alert(document.compatMode)
	if (msiev.cache !== undefined)
		return msiev.cache;

	switch (navigator.appName)
	{
		case 'Netscape': //Fx
			return msiev.cache = 0;
		case 'Opera':
			return msiev.cache = 0;
	}

	var msievn = navigator.appVersion.split('MSIE');
	msievn = parseFloat(msievn[1]);
	if (!(msievn)) msievn = 0;
	msiev.cache = msievn;
	return msievn;
}

function isWebKit()
{
	if (isWebKit.cache !== undefined)
		return isWebKit.cache;

	if (navigator.userAgent.toLowerCase().indexOf('safari') >= 0)
		isWebKit.cache = true;
	else if (navigator.userAgent.toLowerCase().indexOf('chrome') >= 0)
		isWebKit.cache = true;
	else
		isWebKit.cache = false;
	return isWebKit.cache;
}

function className(obj)
{
	if (obj && obj.constructor && obj.constructor.toString)
	{
		var constructorMatches =
			obj.constructor.toString().match(/function\s*(\w+)/);

		if (constructorMatches && constructorMatches.length == 2)
			return constructorMatches[1];
	}
	return undefined;
}

function removeObj(obj)
{
	obj.parentNode.removeChild(obj);
}

function removeChilds(obj)
{
	if (!obj)
		throw new Exception('removeChilds(): obiekt nie istnieje');
	while (obj.firstChild)
		obj.removeChild(obj.firstChild);
}

function createDOMObj(xmltext)
{
	if (window.ActiveXObject) //IE
	{
		var xmlobject = new ActiveXObject('Microsoft.XMLDOM');
		xmlobject.async = 'false';
		xmlobject.loadXML(xmltext);
	}
	else //normalne przegladarki
		var xmlobject = (new DOMParser()).parseFromString(xmltext, 'text/xml');
	return xmlobject;
}

function nextSiblingNamed(obj, name)
{
	if (!obj)
		return false;
	var currObj = obj.nextSibling;
	if (!currObj)
		return false;
	name = name.toUpperCase();
	while (currObj)
	{
		if (currObj.nodeName.toUpperCase() == name)
			return currObj;
		currObj = currObj.nextSibling;
	}
	return false;
}

function firstChildNamed(obj, name)
{
	if (!obj)
		return false;
	var currObj = obj.firstChild;
	if (!currObj)
		return false;
	name = name.toUpperCase();
	if (!currObj)
		return false;
	if (currObj.nodeName.toUpperCase() == name)
		return currObj;
	return nextSiblingNamed(currObj, name);
}

function timestamp()
{
	return (new Date()).getTime();
}

String.prototype.trim = function()
{
	return this.replace(/^\s+|\s+$/g, '');
};

function textContent(obj)
{
	if (obj.textContent)
		return obj.textContent.trim();
	else
		return obj.innerText.trim();
}

function log(obj)
{
	if ((typeof console == 'object') && console && console.log)
		console.log(obj);
}

advAJAXObj.prototype.helperVars = {};

advAJAXObj.prototype.getHelper = function(varName)
{
	if (this.helperVars === undefined)
		throw new Exception('advAJAXObj.prototype.getHelper: nie ma tablicy');
	if (this.helperVars[varName] === undefined)
		throw new Exception('advAJAXObj.prototype.getHelper: element '+varName+' nie istnieje');
	return this.helperVars[varName];
};

advAJAXObj.prototype.raiseEventOriginal = advAJAXObj.prototype.raiseEvent;
advAJAXObj.prototype.raiseEvent = function(name, obj)
{
	switch (name)
	{
		case 'Initialization':
			this.errorMayHappen = true;
			break;
		case 'Error': //znaczy, że error jest już złapany i nie potrzeba go wywoływać przy onFinalization
		case 'Success':
			this.errorMayHappen = false;
			break;
		case 'Finalization':
			if (this.errorMayHappen)
			{
				this.errorMayHappen = false;
				this.raiseEventOriginal('Error', obj);
			}
			break;
	}

	this.raiseEventOriginal(name, obj);
};

function nothing()
{
}

/*****************************************/

function fieldLimit(obj, maxLength)
{
	if (obj.value.length > maxLength)
	{
		var scroll = obj.scrollTop;
		var oldPos = obj.selectionStart;
		obj.value = obj.value.substr(0, maxLength);
		obj.scrollTop = scroll;
		obj.selectionStart = oldPos;
		obj.selectionEnd = obj.selectionStart;
	}
	setTimeout(function()
	{
		fieldLimit(obj, maxLength);
	}, 250);
}

/*****************************************/

//(new Date()).getTime()

function PlaceHint(container)
{
	if (className(this) != 'PlaceHint')
		throw 'Złe wywołanie nowego obiektu';

	this.container = container;
	this.field = firstChildNamed(container, 'input');
	this.menu = document.createElement('div');

	this.pokazWojewodztwa = true;
	this.pokazMiasta = true;

	PlaceHint.queriesCache = new Object();

	this.field.placeHint = this;
	this.field.spellcheck = false;

	this.formSubmitTimeout = timestamp(); //kiedy najwcześniej można wysłać formularz
	var phObj = this;
	this.field.onkeypress = function(e)
	{
		var e = (e)?e:((window.event) ? event : null);
		if (!e)
			return;

		switch (e.keyCode)
		{
			case 38: // w górę
				phObj.selectionMove(false);
				break;
			case 40: // w dół
				phObj.selectionMove(true);
				break;
			case 10:
			case 13:
				if (phObj.currentActivatedItem !== null)
				{
					phObj.menuStateReady = false;
					phObj.formSubmitTimeout = timestamp() + 250;
					phObj.menuListItems[phObj.currentActivatedItem].linkObj.onclick();
				}
				break;
		}
	};

	if (msiev() || isWebKit())
	{
		this.field.onkeydown = this.field.onkeypress;
		this.field.onkeypress = null;
	}

	var contForm = this.container;
	while (contForm)
	{
		if (contForm.tagName.toLowerCase() == 'form')
			break;
		contForm = contForm.parentNode;
	}

	if (contForm)
	{
		contForm.placeHintObj = this; //obsługa tylko jednego hinta w jednym formularzu
		contForm.oldOnsubmit = contForm.onsubmit;
		contForm.onsubmit = function()
		{
			if (this.placeHintObj.formSubmitTimeout > timestamp())
				return false;
			if (this.oldOnsubmit)
				return this.oldOnsubmit();
			else
				return true;
		};
	}

	this.menuStateIsShown = false; // czy menu wyświetlone
	this.menuStateReady = false; //czy zapytanie gotowe (można wyświetlić menu)
	this.menuStateFocused = false; //czy pole aktywne (można wyświetlić menu)
	this.menuStateRefreshAfter = timestamp();
	this.displayedQuery = null; // jakie zapytanie zostało wygenerowane
	this.doQuery = null; // jakie zadać zapytanie

	//style
	this.container.style.position = 'relative';

	var menuTop, menuWidth;
	if (this.field.offsetHeight)
	{
		menuTop = this.field.offsetHeight - 1; // bo 1px zachodzi
		menuWidth = this.field.offsetWidth - 2; // bo 2*1px border
	}
	else
	{
		menuTop = 18;
		menuWidth = 150;
	}

	if (msiev() == 6)
	{
		menuWidth += 2;
		menuTop += 1;
	}
	else if (msiev() == 7)
		menuTop += 1;
	else if (msiev() == 8)
		menuTop -= 2;

	this.container.className = 'placeHintContainer';
	this.menu.className = 'placeHintMenu';
	this.menu.style.width = menuWidth + 'px';
	this.menu.style.height = '20px';
	this.menu.style.top = menuTop + 'px';
	this.menu.style.display = 'none';

	this.container.appendChild(this.menu);

	this.field.onfocus = function()
	{
		this.placeHint.menuStateFocused = true;
		this.placeHint.menuStateRefreshAfter = timestamp() + 500;
	}

	this.field.onblur = function()
	{
		this.placeHint.menuStateFocused = false;
		this.placeHint.menuStateRefreshAfter = timestamp() + 250;
	}

	this.menuStateProcess();
	this.watchingProcess();
	this.runQueryProcess();
}

PlaceHint.prototype.menuStateProcess = function()
{
	var showMenu = (this.menuStateReady && this.menuStateFocused);

	if (this.menuStateIsShown != showMenu &&
		this.menuStateRefreshAfter < timestamp())
	{
		this.menuStateIsShown = showMenu;
		if (showMenu)
			this.menu.style.display = 'block';
		else
		{
			this.menu.style.display = 'none';
			this.selectionRemove();
		}
	}
	var phobj = this;
	setTimeout(function() { phobj.menuStateProcess(); }, 50);
};

PlaceHint.prototype.watchingProcess = function()
{
	if (this.menuStateFocused)
	{
		var fieldText = this.field.value;
		var queryText = fieldText.trim();

		if (queryText == '')
			this.menuStateReady = false;
		else if (queryText == this.displayedQuery)
			{}
		else if (PlaceHint.queriesCache[queryText])
		{
			this.displayedQuery = queryText;
			var displayData = PlaceHint.queriesCache[queryText];

			var emptyList =
				((!this.pokazWojewodztwa || displayData.wojewodztwa.length == 0) &&
				(!this.pokazMiasta || displayData.miasta.length == 0));

			if (!emptyList)
			{
				this.displayHint(displayData);
				this.menuStateReady = true;
			}
			else
				this.menuStateReady = false;
		}
		else
			this.doQuery = queryText;
	}

	var phobj = this;
	setTimeout(function() { phobj.watchingProcess(); }, 50);
};

PlaceHint.prototype.queryProcess = function()
{
	if (this.doQuery != null)
	{
		var queryText = this.doQuery;
		this.doQuery = null;
		if (PlaceHint.queriesCache[queryText])
		{
			this.runQueryProcess();
			return;
		}

		advAJAX.post({
			url: '/placeHint.xml',
			query: queryText,
			helperVars:
			{
				phObj: this,
				queryText: queryText
			},
			onSuccess: function(obj)
			{
				var ph = obj.getHelper('phObj');
				var queryText = obj.getHelper('queryText');
				var respDoc = createDOMObj(obj.responseText);
				if (!respDoc)
				{
					if (this.responseText == BLAD)
						log('Blad PHP');
					else
						log('Niepoprawny dokument w odpowiedzi')
					ph.runQueryProcess();
					return;
				}

				var resp = respDoc.documentElement;
				if (!resp || !resp.nodeName || resp.nodeName != 'placeHint')
				{
					log('Zła odpowiedź (nie pasujący xml)');
					ph.runQueryProcess();
					return;
				}

				var wojObj = firstChildNamed(resp, 'wojewodztwa');
				var miasObj = firstChildNamed(resp, 'miasta');

				var wojewodztwa = new Array();
				var miasta = new Array();

				var woj = firstChildNamed(wojObj, 'wojewodztwo');
				while (woj)
				{
					wojewodztwa[wojewodztwa.length] = woj.firstChild.data;
					woj = nextSiblingNamed(woj, 'wojewodztwo');
				}

				var mias = firstChildNamed(miasObj, 'miasto');
				while (mias)
				{
					miasta[miasta.length] = mias.firstChild.data;
					mias = nextSiblingNamed(mias, 'miasto');
				}

				var queryResult = new Object();
				queryResult.wojewodztwa = wojewodztwa;
				queryResult.miasta = miasta;

				PlaceHint.queriesCache[queryText] = queryResult;

				ph.runQueryProcess();
			},
			onError: function(obj)
			{
				obj.getHelper('phObj').runQueryProcess();
			}
			});
		return;
	}

	this.runQueryProcess();
};

PlaceHint.prototype.runQueryProcess = function()
{
	var phobj = this;
	setTimeout(function() { phobj.queryProcess(); }, 50);
};

PlaceHint.prototype.displayHint = function(data)
{
	var wojCnt = this.pokazWojewodztwa?data.wojewodztwa.length:0;
	var miaCnt = this.pokazMiasta?data.miasta.length:0;
	if (wojCnt == 0 && miaCnt == 0)
	{
		removeChilds(this.menu);
		this.menu.style.height = '20px';
		return 'asdf';
	}

	var phObj = this;
	var useHintCallback = function()
	{
		var hint = textContent(this);
		phObj.field.value = hint;
		phObj.displayedQuery = hint;
	};

	this.menuListItems = new Array();
	this.currentActivatedItem = null;

	var wojList, miaList;
	if (wojCnt > 0)
	{
		wojList = document.createElement('ul');
		wojList.className = 'placeHintMenuListWoj';
		for (i in data.wojewodztwa)
		{
			var wojName = data.wojewodztwa[i];

			var link = document.createElement('a');
			link.appendChild(document.createTextNode(wojName));
			link.onclick = useHintCallback;
			link.podID = this.menuListItems.length;
			link.phObj = this;
			link.onmouseover = function()
			{
				this.phObj.selectionSet(this.podID);
			};
			if (msiev() == 6)
				link.href = 'javascript:nothing()';

			var woj = document.createElement('li');
			woj.appendChild(link);
			woj.linkObj = link;
			wojList.appendChild(woj);
			this.menuListItems[this.menuListItems.length] = woj;
		}
	}

	if (miaCnt > 0)
	{
		miaList = document.createElement('ul');
		miaList.className = 'placeHintMenuListMia';
		for (i in data.miasta)
		{
			var miaName = data.miasta[i];

			var link = document.createElement('a');
			link.appendChild(document.createTextNode(miaName));
			link.onclick = useHintCallback;
			link.podID = this.menuListItems.length;
			link.phObj = this;
			link.onmouseover = function()
			{
				this.phObj.selectionSet(this.podID);
			};
			if (msiev() == 6)
				link.href = 'javascript:nothing()';

			var mia = document.createElement('li');
			mia.appendChild(link);
			mia.linkObj = link;
			miaList.appendChild(mia);
			this.menuListItems[this.menuListItems.length] = mia;
		}
	}

	var menuHeight = (wojCnt + miaCnt) * 16;

	/*if (wojCnt > 0 && miaCnt > 0)
	{
		wojList.style.borderBottomWidth = '1px';
		menuHeight++;
	}*/

	removeChilds(this.menu);
	this.menu.style.height = menuHeight + 'px';
	if (wojCnt > 0)
		this.menu.appendChild(wojList);
	if (miaCnt > 0)
		this.menu.appendChild(miaList);
};

PlaceHint.prototype.selectionMove = function(down)
{
	var curr;
	if (this.currentActivatedItem === null)
		curr = down?0:(this.menuListItems.length - 1);
	else
	{
		curr = this.currentActivatedItem;
		this.menuListItems[curr].linkObj.className = '';
		if (down)
		{
			curr++;
			if (curr >= this.menuListItems.length)
				curr = 0;
		}
		else
		{
			curr--;
			if (curr < 0)
				curr = this.menuListItems.length - 1;
		}
	}
	this.currentActivatedItem = curr;
	this.menuListItems[curr].linkObj.className = 'placeHintMenuListActive';
};

PlaceHint.prototype.selectionRemove = function()
{
	if (this.currentActivatedItem === null)
		return;
	this.menuListItems[this.currentActivatedItem].linkObj.className = '';
	this.currentActivatedItem = null;
};

PlaceHint.prototype.selectionSet = function(pos)
{
	this.selectionRemove();
	this.currentActivatedItem = pos;
	this.menuListItems[pos].linkObj.className = 'placeHintMenuListActive';
};
