	// classes
	function Item()
	{
		var _property = new Object();
		var _id = "";

	    this.setId = function(id)
	    {
	    	_id = id;
	    }
	    this.getId = function()
	    {
	    	return _id;
	    }
	    this.setProperty = function(name, value)
	    {
	        if (name == null || name.length == 0)
	            throw new Error("[Item.setProperty] No property name was specified");
	            
	        _property[name] = value;
	    }
	    this.getProperty = function(name)
	    {
	        if (name == null || name.length == 0)
	            throw new Error("[Item.getProperty] No property name was specified");
	            
	        return _property[name];
	    }
	    this.getProperties = function()
	    {
	        return Util.copyObject(_property);
	    }
	}
	
	
	/////////////////////////////////////////////////////////////////////////////////
	/////////////////////////////////////////////////////////////////////////////////
	/////////////////////////////////////////////////////////////////////////////////
	/////////////////////////////////////////////////////////////////////////////////
	/////////////////////////////////////////////////////////////////////////////////
	
	function ItemList()
	{
		var _items = new Array();
		
		this.clear = function()
		{
			_items = new Array();
		}
		
		this.size = function()
		{
			return _items.length;
		}
		
		this.addItem = function(item)
		{
			if (item != null)
			{
				_items.push(item);
				return true;
			}
			return false;
		}
		this.getItem = function(id)
		{
			var i = 0;
			for (i = 0; i != _items.length; i++)
			{
				var item = _items[i];
				if (item.getId() == id)
					return item;
			}
			return null;
		}
		
		this.getValuesByProperty = function(property)
		{
			return this.getValuesByProperty(property, false);
		}
		
		this.getValuesByProperty = function(property, onlyDifferent)
		{
			return this.getValuesByProperty(property, false, null);
		}
		
		this.getValuesByProperty = function(property, onlyDifferent, filterConds)
		{
			var i = 0;
			var values = Array();
			
			var items = _items;
			if ((filterConds != null) && (filterConds.length > 0))
				items = this.getItemsByProperty(filterConds);
			
			for (i = 0; i != items.length; i++)
			{
				var item = items[i];
				var value = item.getProperty(property);
				if (value == null) continue;
				
				if (!onlyDifferent)
				{
					values.push(value);
				}
				else	// look for repeated values
				{
					var found = false;
					var j = 0;
					for (j = 0; j != values.length; j++)
					{
						if (values[j] == value)
						{
							found = true;
							break;
						}
					}
					if (!found)
						values.push(value);
				}
			}
			return values;
		}
		
		// conditions: pair of property/value elements, in a bi dimensional array: i x 2 size
		this.getItemsByProperty = function(conditions)
		{
			var i = 0;
			var condIdx = 0;
			var items = Array();
			for (i = 0; i != _items.length; i++)
			{
				var currItem = _items[i];
				
				
				if ((conditions == null) || (conditions.length == 0))	// include all the items!
				{
					items.push(currItem);
				}
				else
				{
					var acceptedItem = true;
					for (condIdx = 0; condIdx != conditions.length; condIdx++)
					{
						var filterProperty = conditions[condIdx][0];
						var filterValue = conditions[condIdx][1];
						var currValue = currItem.getProperty(filterProperty);
						
					/*	alert("condIdx: " + condIdx +
								"\n" + "filterProperty: " + filterProperty +
								"\n" + "filterValue: " + filterValue +
								"\n" + "currValue: " + currValue);*/
								
						if (currValue == null)
						{
							acceptedItem = false;
							break;
						}
						if (currValue != filterValue)
						{
							acceptedItem = false;
							break;
						}
					}
					if (acceptedItem)
						items.push(currItem);
				}
				
			}
			return items;
		}
		this.getItems = function()
		{
			var i = 0;
			var items = Array();
			for (i = 0; i != _items.length; i++)
			{
				var currItem = _items[i];
				items.push(currItem);
			}
			return items;
		}
		this.getItemIds = function()
		{
			var i = 0;
			var items = Array();
			for (i = 0; i != _items.length; i++)
			{
				var currItem = _items[i];
				items.push(currItem.getId());
			}
			return items;
		}

		this.filterHTMLList = function(document, conditions)
		{
			var filteredList = this.getItemsByProperty(conditions);
			
			for (i = 0; i != _items.length; i++)
			{
				var currItem = _items[i];
				var currId = currItem.getId();
				
				var htmlObject = document.getElementById(currId);
				if (htmlObject == null) continue;
				
				var isFilteredItem = false;
				var filteredIdx = 0;
				for (filteredIdx = 0; filteredIdx != filteredList.length; filteredIdx++)
				{
					var filteredId = filteredList[filteredIdx].getId();
					if (filteredId == currId)
					{
						isFilteredItem = true;
						break;
					}
				}
				
				if (isFilteredItem)	// show this element
				{
					htmlObject.style.display = '';
				}
				else
				{
					htmlObject.style.display = 'none';
				}
			}
		}
		
		
		this.getOrderedItemsByProperties = function(property, order, datatype)
		{
			var list = new Array();
			var i = 0;
			for (i = 0; i < _items.length; i++)
			{

				var currItem = _items[i];
				var currId = currItem.getId();
				var currValue = currItem.getProperty(property);

				/*
				var dumpedList = this.dumpListByProperty(list, property);
				alert(
						'dumpedList: ' + dumpedList.length + '\n->' + dumpedList +
						'\n\n' +
						'\n' + 'i: ' + i +
						'\n' + 'currId: ' + currId +
						'\n' + 'currValue: ' + currValue
					);
				*/
				
				//insert into list
				
				if (list.length == 0)
				{
					list.push(currItem);
				}
				else
				{
					var res = 0;
					var j = 0;
					for (j = 0; j != list.length; j++)
					{
						var item = list[j];
						res = compareStr(currValue, item.getProperty(property), datatype);
						if (res > 0)
							break;
					}

					if (j > (list.length-1))
					{
						list.push(currItem);
					}
					else	// insert value in the correct position: j
					{
						list.push(currItem); // add one element into the array. does not matter its content
						var pos = 0;
					//	for (pos = j; pos < (list.length-1); pos++)
					//		list[pos+1] = list[pos];
						for (pos = list.length-1; pos > j; pos--)
							list[pos] = list[pos-1];
						list[j] = currItem;
					}

				}
				
			}
			/*
			var dumpedList = this.dumpListByProperty(list, property);
			alert(
					'dumpedList: ' + dumpedList.length + '\n->' + dumpedList
				);
			*/
			
			if (order == 'ASC')
			{
			//	alert("length: " + list.length);
				var list2 = new Array();
				var i = 0;
				for (i = list.length-1; i >= 0; i--)
					list2.push(list[i]);
				return list2;
			}
			return list;
		}
		
		this.dumpListByProperty = function(list, property)
		{
			var dumpedList = new Array();
			for (itemIdx = 0; itemIdx < list.length; itemIdx++)
			{
				var item = list[itemIdx];
				dumpedList.push(item.getProperty(property));
			}
			return dumpedList;
		}

		this.orderHTMLTable = function(document, tableName, property, orden, propertyDatatype)
		{
		//	alert('orderHTMLTable(document=' + document + ', tableName=' + tableName + ', property=' + property + ', orden=' + orden + ', propertyDatatype=' + propertyDatatype + ')');

			if ((propertyDatatype == null) || (propertyDatatype == ''))
				propertyDatatype = 'string';
			
			var orderedItems = this.getOrderedItemsByProperties(property, orden, propertyDatatype);
		//	alert("orderedItems: " + orderedItems.length);
			
			/*
			var dumpedList = this.dumpListByProperty(orderedItems, property);
			alert('dumpedList: ' + dumpedList.length + '\n' + dumpedList);
			*/
			
			var table = document.getElementById(tableName);
			if (table == null) return;
			var tablebody = table.tBodies.item(0);
			
			var itemIdx;
			for (itemIdx = 0; itemIdx < (orderedItems.length-1); itemIdx++)
			{
				var item = orderedItems[itemIdx];
				this.moveRow(tablebody, item.getId(), itemIdx+1);
			}
		}
		
		this.moveRow = function(tableBody, targetID, newPosition)
		{
		//	alert('moveRow(tableBody=' + tableBody + ', targetID=' + targetID + ', newPosition=' + newPosition + ')');
			
			var insertBeforeRowNode = null;
			var searchedRowNode = null;
			var currPos = 0;
			var i;
			for (i = 0; i < tableBody.childNodes.length; i++)
			{
				var node = tableBody.childNodes.item(i);
				var nodename = node.nodeName;
				if (nodename != 'TR') continue;
				currPos++;
				
				if (currPos == newPosition)
					insertBeforeRowNode = node;
								
				var tr_id = node.getAttribute("id");
			//	alert(node.nodeName + ": " +  "id=" + tr_id);
				
				if (tr_id == targetID)
					searchedRowNode = node;
			}
			
			if (insertBeforeRowNode == null)
				return false;
			if (searchedRowNode == null)
				return false;
			
			if (insertBeforeRowNode.getAttribute("id") == searchedRowNode.getAttribute("id"))
				return false;
				
		//	alert(	"searchedRowNode: " + searchedRowNode.getAttribute("id") + "\n" +
		//			"insertBeforeRowNode: " + insertBeforeRowNode.getAttribute("id") + "\n" );
			
			tableBody.removeChild(searchedRowNode);
			tableBody.insertBefore(searchedRowNode, insertBeforeRowNode);
		}
		
	}
	
	// returns:
	//	1 . str1 is greater then str2
	//	0 . str1 is equals then str2
	//	-1 . str1 is less then str2
	function compareStr(str1, str2, datatype)
	{
		if ((str1 == null) && (str2 == null))
		{
			return 0;
		}
		else if ((str1 == null) && (str2 != null))
		{
			return -1;
		}
		else if ((str1 != null) && (str2 == null))
		{
			return 1;
		}
		else if ((str1 != null) && (str2 != null))
		{
			if (datatype == 'int')
			{
				try
				{
					if (parseInt(str1) == parseInt(str2))
						return 0;
					else if (parseInt(str1) > parseInt(str2))
						return 1;
					else
						return -1;
				}
				catch (err1)
				{
					return 0;	// by default
				}
			}
			else	// 'string'
			{
				if (str1 == str2)
					return 0;
				else if (str1 > str2)
					return 1;
				else
					return -1;
			}
		}
		else
			return 0;
	}
		

	/****************************************************
	This functionality is used in SearchFormBuilder.xsl
	Its aim is to show layer/images according a value
	chosen in a drop-down list.
	*****************************************************/	
	
//	var fieldHandlers = Array();
//	var currLayer = null;
	
	/*
	function appendDependantFieldHandler(comboID, value, layerID)
	{
	//	alert("appendDependantFieldHandler");
		var entry = Array(comboID, value, layerID);
		fieldHandlers.push(entry);
	}
	
	function checkDependantFields(combo, defaultImage)
	{
	//	alert("checkDependantFields(comboid=" + combo.id + ", combovalue=" + combo.value + ", defaultImage=" + defaultImage + ")");
		if (currLayer != null)
		{
			currLayer.style.display = 'none';	// hide previous selection
			currLayer = null;
			replaceImage(defaultImage);	// force default image
		}
		
		var i;
		for (i = 0; i != fieldHandlers.length; i++)
		{
		//	alert("fieldHandlers[" + i + "]: " + fieldHandlers[i]);
			var entry = fieldHandlers[i];
			
			if ((combo.id == entry[0]) && (combo.value == entry[1]))
			{
				var layer = document.getElementById(entry[2]);
			//	alert("found element\n" + "layer: " + layer);
				if (layer != null)
				{
					currLayer = layer;
					currLayer.style.display = '';
					var layerImageName = "image_" + entry[2];
					replaceImage(layerImageName);
					break;
				}
			}
		}
	}
	*/
	
	/*
	function hasDependantFields()
	{
	}
	*/
	
	/*
	function setDependantFieldGroup(form)
	{
	//	alert("setDependantFieldGroup");
		var i;
		for (i = 0; i < form.elements.length; i++)
		{
			var elem = form.elements.item(i);
			try
			{
				if (elem.tagName.toUpperCase() != 'SELECT')		continue;
				var str = elem.onchange + ' ';	// force converting string in order to compare to
			//	alert("name: " + elem.name + "\nonchange: " + str);
				var idx = str.indexOf('hasDependantFields');
				if (idx >= 0)
					checkDependantFields(elem,'');
			}
			catch (e)
			{}
		}
	}
	*/
	
	/*
	function replaceImage(sourceImage)
	{
		return;
		if (!document.images) return;
		var targetImage = "image";
		
		var target = document.images[targetImage];
		var source = document.images[sourceImage];
		
		if (source == null)
		{
		//	alert("source image not found.");
			return;
		}
		if (target == null)
		{
		//	alert("source image not found.");
			return;
		}
		target.src = source.src;
	}
	*/



	/****************************************************
	This functionality is used in SearchFormBuilder.xsl
	Its aim is to work with visual elemens in the form.
	*****************************************************/	

	function fillComboItems(combo, values, keepFirstItem)
	{
		combo.options.length = (keepFirstItem) ? 1 : 0;
		if ((values != null) && (values.length != 0))
		{
			//combo.options[combo.options.length] = new Option('', '');
			values = values.sort();
			var i;
			for (i = 0; i != values.length; i++)
				combo.options[combo.options.length] = new Option(values[i], values[i]);
		}
	
	}
	
	
	function setUrlParameter(urlStr, param, value, beforeThisParam)
	{
	//	alert("setUrlParameter." +
	//			"\n" + "urlStr" + "=" + urlStr +
	//			"\n" + "param" + "=" + param +
	//			"\n" + "value" + "=" + value);
		var newUrl = "";
		var idx = urlStr.indexOf(param + "=");
	//	alert("setUrlParameter." + "\n" + "idx" + "=" + idx);
		if (idx >= 0)
		{
			newUrl = urlStr.substring(0, idx + param.length + 1);
			newUrl += value;
		//	alert("setUrlParameter." + "\n" + "newUrl" + "=" + newUrl);
			
			var idx2 = urlStr.indexOf("&", idx + param.length);
		//	alert("setUrlParameter." + "\n" + "idx2" + "=" + idx2);
			if (idx2 >= 0)
				newUrl += urlStr.substring(idx2);
		}
		else	// add parameter
		{
			var idx2 = -1;
			if (beforeThisParam != '')
				idx2 = urlStr.indexOf(beforeThisParam + "=");
			
			if (idx2 >= 0)
			{
				newUrl = urlStr.substring(0, idx2);
				newUrl += param + "=" + value + "&";
				newUrl += urlStr.substring(idx2);
			}
			else	// append parameter as the last one
				newUrl = urlStr + "&" + param + "=" + value;
		}
	//	alert("setUrlParameter." + "\n" + "newUrl" + "=" + newUrl);
		return newUrl;
	}


	/////////////////////////////////////////////////////////////////////////////////
	/////////////////////////////////////////////////////////////////////////////////
	// Search condition
	function SearchCondition()
	{
		var _conditions = new Array();
		
		this.clear = function()
		{
			_conditions = new Array();
		}
		
		this.setCondition = function(field, value)
		{
		//	alert("setCondition(field=" + field + ", value=" + value + ")");
			if (field == '') return;
			var pos;
			var newConditions = new Array();
			for (pos = 0; pos < _conditions.length; pos++)
			{
				if (field == _conditions[pos][0]) continue;
				newConditions.push( new Array(_conditions[pos][0], _conditions[pos][1]) );
			}
			if (value != '')
				newConditions.push( new Array(field, value) );
			
			_conditions = newConditions;
		}
		
		this.setConditions = function(searchConditions)
		{
			var conds = searchConditions.getConditions();
			var pos;
			for(pos = 0; pos < conds.length; pos++)
				this.setCondition(conds[pos][0], conds[pos][1]);
		}
		
		this.appendCondition = function(field, value)
		{
			if (field == '') return;
			_conditions.push( new Array(field, value) );
		}
		
		this.getConditions = function()
		{
			var conds = new Array();
			var i;
			for (i = 0; i < _conditions.length; i++)
			{
				conds.push(new Array(_conditions[i][0], _conditions[i][1]));
			}
			return conds;
		}
		

	}
	
	
	
