/*
	AJAX-Search-Mask-Refresh v2

	Last modification 27.10.2011 by JeDu

	Tested in FF7, IE6/7/8/9, OP11.5, SF5

	Normaler Reset-Button mit Aktualisieren der Suchmaske:
		mdxSearchForm.insertRefreshButton('bauart');

	Nur Auswahl zurücksetzen ohne Suchmasken-Reload:
		mdxSearchForm.insertRefreshButton('sort', true);

	Mehrere Felder über einen Reset-Button zurücksetzen (der Reset-Button wird hinter dem letzten Feld in der Liste eingefügt):
		mdxSearchForm.insertRefreshButton(['km_from', 'km_to']);
*/

function SearchForm(_config) {
	var	_this = this,
		_refreshing = false;

	// Create a dummy-config-object if the _config object is invalid
	if (!_config || typeof _config !== 'object') { _config = {}; }

	this.id = _config.id || 'suchmaske';							// <form>-ID
	this.mKey = _config.mKey;								// Market Key (SERVER-KID-MODID)
	this.dKey = _config.dKey || '';								// Dealer Key (SERVER-KID-MODID)
	this.locale = _config.locale || 'de';							// %mdx_localeshort%
	this.translations = _config.translations || {};						// Translations object (keys: 'from', 'to', 'doors', 'searchzip')
	this.preProcess = _config.preProcess || [];						// Function or Array of Functions
	this.postProcess = _config.postProcess || [];						// Function or Array of Functions
	this.showVehiclesFoundInSelect = _config.showVehiclesFoundInSelect || false;		// Show vehicles found for each select option (on/off)
//	this.showVehiclesFoundInCheckbox = _config.showVehiclesFoundInCheckbox || false;	// Show vehicles found for each extras label (on/off)
	this.debugging = _config.debugging || false;						// Debugging (on/off)
	this.vehiclesFoundElems = _config.vehiclesFoundElems || ['vehiclesFound'];
	this.noVehiclesFoundElems = _config.noVehiclesFoundElems || ['noVehiclesFound'];
	this.domain = _config.domain || '';

	// Translates dealer group query string parameter names to vehicle server query string parameter names
	this.paramTranslate = {
		'hersteller': 'manufacturer',
		'bauart': 'build',
		'farbe': 'color',
		'age': 'days_in_stock',
		'dealer_country': 'dealerCountry',
		'customer': 'dkey',
		'companycar': 'companyCar',
		'company_car': 'companyCar',
		'tueren': 'doors',
		'doors_grouped': 'doors',
		'tueren': 'doors',
		'euronorm': 'euroNorm',
		'antrieb': 'gears',
		'getriebe': 'gears',
		'km_ab': 'km_from',
		'km_bis': 'km_to',
		'kw_ab': 'kw_from',
		'kw_bis': 'kw_to',
		'hersteller': 'manufacturer',
		'preis_ab': 'price_from',
		'preis_bis': 'price_to',
		'ez': 'reg_date_from',
		'ez_ab': 'reg_date_from',
		'ez_bis': 'reg_date_to',
		'fart': 'selltype',
		'type_series': 'type_series_id',
		'electric_seats': 'electricSeats',
		'parkdistancecontrol': 'parkDistanceControl',
		'park_distance_control': 'parkDistanceControl',
		'bidvehicle': 'bidVehicle',
		'bid_vehicle': 'bidVehicle',
		'warrantyprogram': 'warrantyProgram',
		'warranty_program': 'warrantyProgram'
	};

	this.customSelectFields = {
		'customer': { updateOptions: function (elem, json, q) { return elem.selectedIndex; } },
		'sort': { updateOptions: function (elem, json, q) { return elem.selectedIndex; } },
		'radius': { updateOptions: function (elem, json, q) { return elem.selectedIndex; } },
		'max': { updateOptions: function (elem, json, q) { return elem.selectedIndex; } },
		'bauart': {
			setQuery: function (elem, q) {
				/*
					Wenn Build gefüllt ist, muss auch CType gefüllt sein, ansonsten kann im Falle von 0 Treffer
					nicht der CType-Name zum Build ermittelt werden.
				*/
				/*
					Auskommentiert am 18.10.2010: Anscheinend nicht mehr nötig durch Fahrzeugserver-Update.
					Kann gelöscht werden, wenn über längere Zeit keine Fehler beobachtet werden.

					if (elem.options[elem.selectedIndex].value !== '') {
						var searchFormElems = document.getElementById(_this.id).elements;
						if (!searchFormElems['ctype'] || searchFormElems['ctype'].value === '') {
							q['ctype'] = '1||2||3||4||5||6||7||8||9||10||11||12||13';
						}
					}
				*/
			},
			updateOptions: function (elem, json, q) {
				clearOptions(elem);

				var selectedIndex = 0;
				var id;
				var ctypes = {};
				var ctypesUsed = {};
				var noOfCtypes = json['ctype'] ? jsonArrayLength(json['ctype']['option']) : 0;
				var option;

				if (json['ctype']) {
					for (var i = 0; i < noOfCtypes; i++) {
						id = jsonArray(json['ctype']['option'], i)['@value'];
						ctypes[id] = document.createElement('optgroup');
						ctypes[id].label = jsonArray(json['ctype']['option'], i)['#'];
						ctypesUsed[id] = false;
					}
				}

				if (json['build']) {
					for (var i = 0; i < jsonArrayLength(json['build']['option']); i++) {
						var option = document.createElement('option');
						option.value = jsonArray(json['build']['option'], i)['@value'];
						option.text = jsonArray(json['build']['option'], i)['#'];
						option.selected = jsonArray(json['build']['option'], i)['@selected'];
						if (typeof(ctypes[jsonArray(json['build']['option'], i)['@ctype']]) === 'undefined') {
							elem.appendChild(option);
						} else {
							ctypes[jsonArray(json['build']['option'], i)['@ctype']].appendChild(option);
							ctypesUsed[jsonArray(json['build']['option'], i)['@ctype']] = true;
						}
						option.innerHTML = jsonArray(json['build']['option'], i)['#'];

						if (jsonArray(json['build']['option'], i)['@selected'] === 'yes') {
							selectedIndex = i + 1;
						}
					}
				}

				for (var i in ctypes) {
					if (ctypesUsed[i]) { elem.appendChild(ctypes[i]); }
				}

				return selectedIndex;
			}
		},
		'doors_grouped': {
			updateOptions: function (elem, json, q) {
				clearOptions(elem);

				if (json['doors']) {
					var group23Available = false;
					var group45Available = false;

					for (var i = 0; i < jsonArrayLength(json['doors']['option']); i++) {
						switch (jsonArray(json['doors']['option'], i)['@value']) {
							case '2':
							case '3':
								group23Available = true;
								break;
							case '4':
							case '5':
								group45Available = true;
						}
					}

					if (group23Available) { addOption(elem, '2||3', '2/3' + getTranslation('doors'), q['doors'] === '2||3'); }
					if (group45Available) { addOption(elem, '4||5', '4/5' + getTranslation('doors'), q['doors'] === '4||5'); }

					switch (q['doors']) {
						case '2||3': return 1;
						case '4||5': return 2;
					}
				}
				return 0;
			}
		},
		'first_reg_age': {
			updateOptions: function (elem, json, q) {
				clearOptions(elem);

				var selectedIndex = 0;
				if (json['reg_date_from'] || json['reg_date_to']) {
					var regDateFrom = parseInt((json['reg_date_from'] ? jsonArray(json['reg_date_from']['option'], 0) : jsonArray(json['reg_date_to']['option'], 0))['@value'], 10);
					var regDateTo = parseInt((json['reg_date_to'] ? jsonArray(json['reg_date_to']['option'], jsonArrayLength(json['reg_date_to']['option']) - 1) : jsonArray(json['reg_date_to']['option'], jsonArrayLength(json['reg_date_to']['option']) - 1))['@value'], 10); 
					var thisYear = (new Date()).getFullYear();
					var selectedYear = 0;

					if (json['reg_date_from']) {
						for (var i = 0; i < jsonArrayLength(json['reg_date_from']['option']); i++) {
							if (jsonArray(json['reg_date_from']['option'], i)['@selected'] === 'yes') {
								selectedYear = jsonArray(json['reg_date_from']['option'], i)['@value'];
								break;
							}
						}
					}

					for (var i = regDateTo, j = 1; i > regDateFrom; i--, j++) {
						if ((i - 1) === selectedYear) { selectedIndex = j; }
						addOption(
							elem,
							(i - 1) + '-01-01',
							(thisYear - i) + 1,
							((i - 1) === selectedYear)
						);
					}
				}
				return selectedIndex;
			}
		},
		'reg_date_from': { /* as well as 'reg_date_from', 'ez_ab', 'ez_bis', 'doors' referenced after the object declaration */
			updateOptions: function (elem, json, q) {
				clearOptions(elem);

				var name = getParamTranslate(elem.name),
				    selectedIndex = 0;

				if (json[name]) {
					var text = '';
					for (var i = 0; i < jsonArrayLength(json[name]['option']); i++) {
						switch (name) {
							case 'reg_date_from':	text = getTranslation('from') + jsonArray(json[name]['option'], i)['#']; break;
							case 'reg_date_to':	text = getTranslation('to') + jsonArray(json[name]['option'], i)['#']; break;
							case 'doors':		text = jsonArray(json[name]['option'], i)['#'] + getTranslation('doors'); break;
							default:		text = jsonArray(json[name]['option'], i)['#'];
						}

						addOption(
							elem,
							jsonArray(json[name]['option'], i)['@value'],
							text,
							jsonArray(json[name]['option'], i)['@selected'] === 'yes'
						);
						if (jsonArray(json[name]['option'], i)['@selected'] === 'yes') {
							selectedIndex = i + 1;
						}
					}
				}
				return selectedIndex;
			}
		}
	};
	this.customSelectFields['build'] = this.customSelectFields['bauart'];
	this.customSelectFields['reg_date_to'] = this.customSelectFields['reg_date_from'];
	this.customSelectFields['doors'] = this.customSelectFields['reg_date_from'];
	this.customSelectFields['ez_ab'] = this.customSelectFields['reg_date_from']; // this.customSelectFields['first_reg_age'];
	this.customSelectFields['ez_bis'] = this.customSelectFields['reg_date_to'];

	this.customExtras = {
		'seven_seats': {
			isAvailable: function (json, q) {
				if (json['seats']) {
					var value;
					for (var i = 0; i < jsonArrayLength(json['seats']['option']); i++) {
						value = jsonArray(json['seats']['option'], i)['@value'];
						if (value === '7') { return true; }
					}
				}
				return false;
			},
			isChecked: function (json, q) {
				return (q['seats'] === '7');
			},
			setQuery: function (q, checked) {
				if (checked) { q['seats'] = '7'; }
			}
		},
		'automatic': {
			isAvailable: function (json, q) {
				if (json['gears']) {
					var value;
					for (var i = 0; i < jsonArrayLength(json['gears']['option']); i++) {
						value = jsonArray(json['gears']['option'], i)['@value'];
						if (value === '1' || value === '7' || value === '1||7') { return true; }
					}
				}
				return false;
			},
			checked: false,
			isChecked: function (json, q) {
				return this.checked;
			},
			setQuery: function (q, checked) {
				if (checked) { q['gears'] = '1||7'; }
				this.checked = checked;
			}
		}
	};

	this.resetFields = {};
	this.insertRefreshButton = function (field, justReset) {
		var	searchForm = document.getElementById(_this.id),
			resetElem = document.createElement('div'),
			lastField, fieldName;

		if (typeof(field) === 'string') {
			resetElem.className = 'reset' + (searchForm.elements[field].selectedIndex != 0 ? 'Enabled' : 'Disabled');
			lastField = field;
			fieldName = field;
		} else if (typeof(field) === 'object') {
			var enabled = false;
			for (var f in field) {
				lastField = field[f];
				if (searchForm.elements[lastField].selectedIndex != 0) {
					enabled = true;
					break;
				}
			}
			resetElem.className = 'reset' + (enabled ? 'Enabled' : 'Disabled');
			fieldName = field.join(';');
		}

		resetElem.onclick = function () {
			if (this.className === 'resetEnabled') {
				if (typeof(field) === 'string') {
					document.getElementById(_this.id).elements[field].selectedIndex = 0;
					lastField = field;
				} else if (typeof(field) === 'object') {
					for (var f in field) {
						lastField = field[f];
						document.getElementById(_this.id).elements[lastField].selectedIndex = 0;
					}
				}

				if (!justReset) {
					_this.refresh(lastField);
				} else {
					this.className = 'resetDisabled';
				}
			}
		}
		_this.resetFields[fieldName] = searchForm.elements[lastField].parentNode.appendChild(resetElem);
	}

	this.isRefresh = function () {
		return _refreshing;
	}

	this.refresh = function (which) {
		_refreshing = true;

		var searchForm = document.getElementById(_this.id),
		selectElems = searchForm.getElementsByTagName('SELECT'),
		inputElems = searchForm.getElementsByTagName('INPUT'),
		labelElems = searchForm.getElementsByTagName('LABEL');

		if (which) {
			for (var r in _this.resetFields) {
				if ((';' + r + ';').indexOf(';' + which + ';') != -1) {
					_this.resetFields[r].className = 'resetLoading';
					break;
				}
			}
		}

		// Initialize the query-string object.
		var query = {
			'gw': 'search_form',
			'mkey': _this.mKey,
			'dkey': _this.dKey,
			'random': '1',
			'allow_no_price': '1',
			'noAvTs': '1',
			'show_extras': '10,44,13,73,50,102,35,37,67,414,8,99,metallic,has_pic,vat,36,51,340,private_ad,64,38,53,39,60,62,148,46,accident,371,42,43',
			'locale': _this.locale,
			'xsl': 'http://content.modix.de/userdata/11111/layout/xhr/xml2json_searchform.xsl',
			'preventCache': (new Date()).getTime()
		};

		var elem;

		// Extend the query-string by custom Extra-CHECKBOX-fields
		for (var extra in _this.customExtras) {
			_this.customExtras[extra].setQuery(query, (searchForm[extra] && searchForm[extra].checked));
		}

		// Extend the query-string object by SELECT-fields
		for (var i = 0; i < selectElems.length; i++) {
			elem = selectElems[i];
			if (
				(elem.name.length > 0) &&
				(elem.selectedIndex >= 0) &&
				(elem.options[elem.selectedIndex].value.length > 0)
			) {
				if (elem.multiple) {
					query[getParamTranslate(elem.name)] = '';
					for (var j = 0; j < elem.options.length; j++) {
						if (elem.options[j].selected) {
							query[getParamTranslate(elem.name)] += '||' + elem.options[j].value;
						}
					}
					query[getParamTranslate(elem.name)] = query[getParamTranslate(elem.name)].substr(2);
				} else {
					query[getParamTranslate(elem.name)] = elem.options[elem.selectedIndex].value;
				}
			}
			selectElems[i].disabled = 'true';
		}

		// Extend the query-string object by Custom-SELECT-fields
		for (var i = 0; i < selectElems.length; i++) {
			elem = selectElems[i];
			if (_this.customSelectFields[elem.name] && typeof _this.customSelectFields[elem.name].setQuery === 'function') {
				// _this.customSelectFields[elem.name].setQuery(elem, query);
				_this.customSelectFields[elem.name].setQuery.call(_this, elem, query);
			}
		}

		// Extend the query-string object by INPUT- and CHECKBOX-fields
		for (var i = 0; i < inputElems.length; i++) {
			elem = inputElems[i];

			// (elem.name !== 'search_vehicles' && elem.name !== 'version' && elem.name !== 'max' && elem.name !== 'sort' && elem.name !== 'request_uid' && elem.name !== 'logLimit') &&
			if (
				(elem.name.length > 0) &&
				(elem.value.length > 0) &&
				(elem.type !== 'checkbox' || (elem.checked && !_this.customExtras[elem.name])) &&
				(elem.type !== 'radio' || elem.checked) &&
				(!/^(search_vehicles|version|max|sort|request_uid|logLimit)$/.test(elem.name)) &&
				(elem.name !== 'zip' || (/^\d+$/.test(elem.value)))
			) {
				query[getParamTranslate(elem.name)] = elem.value;
			}
			if (elem.type !== 'hidden') {
				elem.disabled = 'true';
				if (elem.type === 'checkbox' || elem.type === 'radio') {
					if (elem.parentNode.nodeName.toUpperCase() === 'LABEL') {
						elem.parentNode.className = 'DISABLED';
					}
					if (elem.id) {
						for (var j = 0; j < labelElems.length; j++) {
							if (labelElems[j].getAttribute('for') === elem.id) {
								labelElems[j].className = 'DISABLED';
							}
						}
					}
				}
			}
		}

		if (typeof _this.preProcess === 'function') {
			_this.preProcess.call(_this, query);
		} else if (Object.prototype.toString.call(_this.preProcess) === '[object Array]') {
			for (var i = 0; i < _this.preProcess.length; i++) {
				if (typeof _this.preProcess[i] === 'function') {
					_this.preProcess[i].call(_this, query);
				}
			}
		}

		if (searchForm.elements['state'] || searchForm.elements['district'] || searchForm.elements['region']) {
			query['addRegions'] = '1';
		}

		// Convert some Dealer group parameters to SOAP parameters
		if ((!query['manufacturer'] && query['model']) || (which && which === 'manufacturer')) {
			query['model'] = null;
		}
		if (query['days_in_stock']) {
			query['created_timestamp'] = Math.floor((new Date()).getTime() / 1000) - (parseInt(query['days_in_stock'], 10) * 24 * 60 * 60);
			query['days_in_stock'] = null;
		}
		if (query['country']) {
			switch(query['country'].toLowerCase()) {
				case 'at': query['country'] = '14'; break;
				case 'be': query['country'] = '21'; break;
				case 'de': query['country'] = '1'; break;
				case 'es': query['country'] = '198'; break;
				case 'fr': query['country'] = '73'; break;
				case 'gb': query['country'] = '223'; break;
				case 'it': query['country'] = '105'; break;
				case 'lu': query['country'] = '123'; break;
				case 'nl': query['country'] = '149'; break;
			}
		}
		if (query['pr_days']) {
			query['lastPriceChange'] = '{>=' + Math.floor((new Date()).getTime() / 1000) - (parseInt(query['pr_days'], 10) * 24 * 60 * 60).toString() + '}';
			query['pr_days'] = null;
		}
		if (query['pr_value']) {
			query['price'] = '{<=lastPrice-' + query['pr_value'] + '}';
			query['pr_value'] = null;
		}
		if (query['lower_dealer_price']) {
			if (parseInt(query['lower_dealer_price'], 10) > 1) {
				query['dealer_price'] = '{<=price-' + query['lower_dealer_price'] + ' AND dealer_price > 0}';
			} else {
				query['price'] = '{>dealer_price}';
			}
			query['lower_dealer_price'] = null;
		}
		if (query['lower_internal_dealer_price']) {
			if (parseInt(query['lower_internal_dealer_price'], 10) > 1) {
				query['internal_dealer_price'] = '{<=price-' + query['lower_internal_dealer_price'] + ' AND internalDealerPrice > 0}';
			} else {
				query['price'] = '{>internalDealerPrice}';
			}
			query['lower_internal_dealer_price'] = null;
		}

		// Request data from server
		httpRequest(_this.domain + '/soap/kfz/' + getQueryString(query), function (json) {
			json = json['mdx_form'];

			// Output the number of found vehicles
			for (var i = 0; i < _this.vehiclesFoundElems.length; i++) {
				if (document.getElementById(_this.vehiclesFoundElems[i])) {
					document.getElementById(_this.vehiclesFoundElems[i]).innerHTML = json['found']['#'];
				}
			}
			for (var i = 0; i < _this.noVehiclesFoundElems.length; i++) {
				if (document.getElementById(_this.noVehiclesFoundElems[i])) {
					document.getElementById(_this.noVehiclesFoundElems[i]).style.display = (json['found']['#'] === 0) ? 'block' : 'none';
				}
			}
			for (var i = 0; i < inputElems.length; i++) {
				if (inputElems[i].type === 'submit' || inputElems[i].type === 'button') {
					inputElems[i].value = inputElems[i].value.replace(/[0-9]+/, json['found']['#']);
				}
			}

			var name = '';
			var selectedIndex = 0;
			for (var i = 0; i < selectElems.length; i++) {
				elem = selectElems[i];
				if (_this.customSelectFields[elem.name] && typeof _this.customSelectFields[elem.name].updateOptions === 'function') {
					selectedIndex = _this.customSelectFields[elem.name].updateOptions.call(_this, elem, json, query);
				} else {
					clearOptions(elem);
					name = getParamTranslate(elem.name);
					selectedIndex = 0;
					if (json[name] && json[name]['option']) {
						for (var j = 0; j < jsonArrayLength(json[name]['option']); j++) {
							addOption(
								elem,
								jsonArray(json[name]['option'], j)['@value'],
								jsonArray(json[name]['option'], j)['#'] + (_this.showVehiclesFoundInSelect && jsonArray(json[name]['option'], j)['@found'] != '' ? ' (' + jsonArray(json[name]['option'], j)['@found'] + ')' : ''),
								jsonArray(json[name]['option'], j)['@selected'] === 'yes'
							);
							if (jsonArray(json[name]['option'], j)['@selected'] === 'yes') {
								selectedIndex = j + 1;
							}
						}
					}
				}
				if (elem.name) {
					for (var r in _this.resetFields) {
						if ((';' + r + ';').indexOf(';' + elem.name + ';') != -1) {
							var enabled = (selectedIndex != 0);
							if (!enabled) {
								var fields = r.split(';')
								for (var j = 0; j < fields.length; j++) {
									if (searchForm.elements[fields[j]].selectedIndex > 0) {
										enabled = true;
										break;
									}
								}
							}
							_this.resetFields[r].className = (enabled ? 'resetEnabled' : 'resetDisabled');
							break;
						}
					}
				}
				elem.disabled = '';
			}

			var checked = false;
			var disabled = true;
			for (var i = 0; i < inputElems.length; i++) {
				elem = inputElems[i];
				if (elem.type !== 'hidden' && !_this.customExtras[elem.name]) {
					name = getParamTranslate(elem.name);
					if (name.length > 0 && elem.type === 'checkbox') {
						checked = false;
						disabled = true;

						for (var j = 0; j < jsonArrayLength(json['extras']['extra']); j++) {
							if (jsonArray(json['extras']['extra'], j)['@id'] === name) {
								checked = (jsonArray(json['extras']['extra'], j)['@checked'] === 'yes');
								disabled = (jsonArray(json['extras']['extra'], j)['@disabled'] === 'yes');
								break;
							}
						}

						elem.checked = checked ? 'checked' : '';
						if (!disabled) {
							elem.disabled = '';
							if (elem.parentNode.nodeName.toUpperCase() === 'LABEL') {
								elem.parentNode.className = 'DISABLED';
							}
							if (elem.id) {
								for (var j = 0; j < labelElems.length; j++) {
									if (labelElems[j].getAttribute('for') === elem.id) {
										labelElems[j].className = '';
									}
								}
							}
						}
					} else if (name.length > 0 && elem.type === 'radio') {
						if (elem.value.length === 0) {
							elem.disabled = '';
						} else {
							if (json[name] && json[name]['option']) {
								for (var j = 0; j < jsonArrayLength(json[name]['option']); j++) {
									if (jsonArray(json[name]['option'], j)['@value'] == elem.value) {
										elem.disabled = '';
										if (jsonArray(json[name]['option'], j)['@selected'] === 'yes') {
											elem.checked = 'checked';
										}
									}
								}
							}
						}
					} else {
						if (elem.name === 'zip') {
							elem.value = json[name]['#'] || getTranslation('searchzip');
						}
						elem.disabled = '';
					}
				}
			}

			for (var extra in _this.customExtras) {
				elem = searchForm[extra];
				if (elem) {
					elem.checked = _this.customExtras[extra].isChecked(json, query);
					if (_this.customExtras[extra].isAvailable(json, query) || elem.checked) {
						elem.disabled = '';
						for (var j = 0; j < labelElems.length; j++) {
							if (labelElems[j].getAttribute('for') === elem.id) {
								labelElems[j].className = '';
							}
						}
					}
				}
			}

			if (typeof _this.postProcess === 'function') {
				_this.postProcess.call(_this, query, json);
			} else if (Object.prototype.toString.call(_this.postProcess) === '[object Array]') {
				for (var i = 0; i < _this.postProcess.length; i++) {
					if (typeof _this.postProcess[i] === 'function') {
						_this.postProcess[i].call(_this, query, json);
					}
				}
			}

			_refreshing = false;
		}, function (e) {
			_refreshing = false;
			if (_this.debugging) { alert('AJAX Error\n\n' + e.msg + '\n\nConstructor: ' + e.constructor + '\nSystem message:\n' + e.sys_msg + '\n\nURL: ' + e.url + '\n\nResponse:\n' + e.responseText); }
		}, { "cache":true });

		function getQueryString(obj) {
			var queryString, param;
			for (param in obj) {
				if (obj[param]) {
					queryString = (queryString ? queryString + '&' : '?') + encodeURIComponent(param) + '=' + encodeURIComponent(obj[param]);
				}
			}
			return (queryString || '');
		}
	}

	/* --- INTERNAL FUNCTIONS --- */

	function getTranslation(token) {
		return (_this.translations[token] || '');
	}
	_this.getTranslation = getTranslation;

	function getParamTranslate(name) {
		if (name.substr(name.length - 2) === '[]') { name = name.substr(0, name.length - 2); }
		return (_this.paramTranslate[name] || name || '');
	}
	_this.getParamTranslate = getParamTranslate;

	// Remove all options from a SELECT-field excepting the first
	function clearOptions(elem) {
		var opt = elem.firstChild, nextOpt;
		var removeOpt = false;
		while (opt) {
			nextOpt = opt.nextSibling;
			if (removeOpt) {
				elem.removeChild(opt);
			}
			if (opt.nodeName.toLowerCase() == 'option') {
				removeOpt = true;
			}
			opt = nextOpt;
		}
	}
	_this.clearOptions = clearOptions;

	// Add a new option to a SELECT-field
	function addOption(elem, value, text, selected) {
		var option = document.createElement('option');
		option.value = value;
		option.text = text;
		try {
			// standards compliant; doesn't work in IE
			elem.add(option, null);
		} catch (e) {
			// IE only
			elem.add(option);
		}
		option.selected = selected;
		option.innerHTML = text;
		return option;
	}
	_this.addOption = addOption;
}
