function DropDownMapper(map, request, input_mask) {
	this.Map = map;
	this.Request = request;
	this.InputMask = input_mask;
	this.Objects = new Object();
	this.WatchFields = [];
	this.UpdateFields = {};
	this.Init()
}

DropDownMapper.prototype.Init = function()
{
	this.AssignDrills(this.Map);
	this.DrillDownRequests(this.Map,'root');
	for (var i = 0; i < this.WatchFields.length; i++) {
		var elem = document.getElementById(this.InputMask.replace('#FIELD#', this.WatchFields[i]));
		elem.fieldName = this.WatchFields[i];
		addEvent(elem, 'change', function(ev) {
			var el = !is.ie ? ev.currentTarget : window.event.srcElement;
			mapper.Changed(el.fieldName);
		})
	}
}

DropDownMapper.prototype.GetFilters = function(map, o)
{
	if (!map) map = this.Map;
	if (!o) o = '';
	for (var i in map) {
		if (map[i].Field) o += escape(map[i].Field+'='+this.GetValue(map[i].Field)+'&');
		if (map[i].Pass) { // additional fields to pass to the ajax query
			for (var x in map[i].Pass) {
				o += escape(map[i].Pass[x]+'='+this.GetValue(map[i].Pass[x])+'&');
			}
		}
		if (map[i].SubNodes) {
			o += this.GetFilters(map[i].SubNodes)
		}
	}
	return o;
}

DropDownMapper.prototype.GetValue = function(field)
{
	elem = document.getElementById(this.InputMask.replace('#FIELD#', field));
	if (elem.type && elem.type == 'checkbox') return elem.checked ? 1:0;
	return elem.value;
}

DropDownMapper.prototype.Changed = function(field)
{
	var branch = this.FindBranch(field);
	this.DrillDownRequests(branch, field);
	if (this.UpdateFields[field]) {
		for (var i in this.UpdateFields[field]) {
			this.Objects[this.UpdateFields[field][i]].Query();
		}
	}
}

DropDownMapper.prototype.AssignDrills = function(map)
{
	var mapper = this;
	for (var i in map) {
		if ( map[i].Field ) {
			this.WatchFields.push(map[i].Field);
			if ( map[i].Pass ) {
				for (var p in map[i].Pass) {
					if (!in_array(map[i].Pass[p], this.WatchFields)) {
						this.WatchFields.push(map[i].Pass[p]);
					}
					if (!this.UpdateFields[map[i].Pass[p]]) this.UpdateFields[map[i].Pass[p]] = new Array();
					if (!in_array(map[i].Field, this.UpdateFields[map[i].Pass[p]])) {
						this.UpdateFields[map[i].Pass[p]].push(map[i].Field);
					}
				}
			}
		}
		if ( typeof(map[i].Dependent) == 'undefined' || i.Dependent ) {
			var val = map[i].Value ? map[i].Value : null
			var obj = new AjaxDropdownPreloader(this.Request, this.InputMask, null, map[i].Field, val );
			obj.prepareURL = function()
			{
				return this.URL.replace('#QUESTIONED#', this.DependendField).replace('#FILTERS#', mapper.GetFilters().replace(/%26$/, ''))
			}
			this.Objects[map[i].Field] = obj;
		}

		if (typeof(map[i].SubNodes) == 'object') {
			if ( typeof(map[i].Dependent) == 'undefined' || i.Dependent ) {
				var ii = i; // we need this, otherwise AfterProcess will use the wrong i (be reference)
				obj.AfterProcess = function() {
//					mapper.DrillDownRequests(map[ii].SubNodes, ii);
				}
			}
			this.AssignDrills(map[i].SubNodes);
		}
	}
}

DropDownMapper.prototype.FindBranch = function(branch, map)
{
	if (!map) map = this.Map;
	for (var i in map) {
		if (typeof(map[i].SubNodes) == 'object') {
			if (map[i].Field == branch) return map[i].SubNodes;
			var res = this.FindBranch(branch, map[i].SubNodes);
			if (res) return res;
		}
	}
	return false;
}

DropDownMapper.prototype.DrillDownRequests = function(map,item)
{
	for (var i in map) {
		if (map[i].Field && this.Objects[map[i].Field]) {
			this.Objects[map[i].Field].Query();
		}
		else {
			this.DrillDownRequests(map[i].SubNodes,item); //if there is no object for current item, try its children
		}
	}
}

DropDownMapper.prototype.QueryByField = function(field)
{
	this.Objects[field].Query();
}