	// -- context class --

	function context_class() {
		var self = this;

		this.ic_collector = null;
		this.context = null;
		
		this.window_ref = window;
		this.document_ref = document;
		
		this.evt_destroy = null;
	}

	context_class.prototype.ifc_path = "http://perfecto-new.designplus.local/ifc.php";

	context_class.prototype.construct = function(widget_id, widget_ident) {
		this.ic_collector = new ic_collector(this);
	}

	context_class.prototype.destroy = function() {
		if (this.evt_destroy != null)
			this.evt_destroy();
	}

	context_class.prototype.createElement = function(input) {
		return this.document_ref.createElement(input);
	}

	context_class.prototype.confirm_wnd = function(message) {
		return confirm(message);
	}

	context_class.prototype.catch_error_flags = function(elms) {
		if (elms.length > 0) {
			for (f = 0; f < elms.length; f++) {
				switch (this.element_value(elms[f])) {
					case "unauthorized" :
						
						//this.env.inactive();
					
						break;
				}
			}
		
			return true;
		}
		
		return false;
	}

	context_class.prototype.layerX = function(evt, pos) {
		if (evt.layerX) return evt.layerX;
		else return evt.clientX - pos;
	}

	context_class.prototype.layerY = function(evt, pos) {
		if (evt.layerY) return evt.layerY;
		else return evt.clientY - pos;
	}

	context_class.prototype.wnd_x = function() {
		var result = 0;
		
		if (typeof(this.window_ref.innerWidth) == 'number') result = this.window_ref.innerWidth;
		else if (this.document_ref.documentElement && (this.document_ref.documentElement.clientWidth || this.document_ref.documentElement.clientHeight)) result = this.document_ref.documentElement.clientWidth;
		else if (this.document_ref.body && (this.document_ref.body.clientWidth || this.document_ref.body.clientHeight)) result = this.document_ref.body.clientWidth;

		return result;
	}

	context_class.prototype.wnd_y = function() {
		var result = 0;
		
		if (typeof(this.window_ref.innerWidth) == 'number') result = this.window_ref.innerHeight;
		else if (this.document_ref.documentElement && (this.document_ref.documentElement.clientWidth || this.document_ref.documentElement.clientHeight)) result = this.document_ref.documentElement.clientHeight;
		else if (this.document_ref.body && (this.document_ref.body.clientWidth || this.document_ref.body.clientHeight)) result = this.document_ref.body.clientHeight;

		return result;
	}

	context_class.prototype.get_scX = function() {
		var a = this.document_ref.body.scrollLeft;
		var b = this.document_ref.documentElement.scrollLeft;
		
		return a != 0 ? a : b;
	}

	context_class.prototype.get_scY = function() {
		var a = this.document_ref.body.scrollTop;
		var b = this.document_ref.documentElement.scrollTop;
		
		return a != 0 ? a : b;
	}

	context_class.prototype.get_elementX = function(ref) {
		var loop = ref;
		var out = 0;
		
		while (loop != null) {
			out += loop.offsetLeft;
			loop = loop.offsetParent;
		}
		
		return out;
	}

	context_class.prototype.get_elementY = function(ref) {
		var loop = ref;
		var out = 0;
		
		while (loop != null) {
			out += loop.offsetTop;
			loop = loop.offsetParent;
		}
		
		return out;
	}

	context_class.prototype.get_elementWidth = function(ref) {
		return ref.offsetWidth;
	}

	context_class.prototype.get_elementHeight = function(ref) {
		return ref.offsetHeight;
	}

	context_class.prototype.get_parent_index = function(ref) {
		var founded = false;
		var pos = 0;
		
		while (!founded && pos < ref.parentNode.childNodes.length)
			if (ref.parentNode.childNodes[pos] === ref) founded = true;
			else pos++;
			
		return founded ? pos : null;
	}

	context_class.prototype.center_by = function(target, source) {
		// vycentruje target na stred source
		var sX = this.get_elementX(source);
		var sY = this.get_elementY(source);
		var sW = this.get_elementWidth(source);
		var sH = this.get_elementHeight(source);
		
		var tW = this.get_elementWidth(target);
		var tH = this.get_elementHeight(target);
		
		var pX = sW > tW ? (sX + (sW - tW) / 2) : sX;
		var pY = sH > tH ? (sY + (sH - tH) / 2) : sY;
		
		target.style.position = "absolute";
		target.style.left = pX + "px";
		target.style.top = pY + "px";
	}

	context_class.prototype.element_value = function(ref) {
		return ref.firstChild == null ? '' : ref.firstChild.nodeValue;
	}

	context_class.prototype.element_value_null = function(ref) {
		return ref.firstChild == null ? null : ref.firstChild.nodeValue;
	}

	context_class.prototype.sub_element_value = function(ref, name) {
		var subs = ref.getElementsByTagName(name);
		if (subs != null && subs.length > 0) return this.element_value(subs[0]);
		return "";
	}

	context_class.prototype.sub_element_value_null = function(ref, name) {
		var subs = ref.getElementsByTagName(name);
		if (subs != null && subs.length > 0) return this.element_value_null(subs[0]);
		return null;
	}

	context_class.prototype.error = function(value) {
		// !!! ERROR PRO WEB NEBUDE
		alert("error: `" + value + "`");
	}

	context_class.prototype.object_create = function(ref) {
		return ref;
	}

	context_class.prototype.object_destroy = function(ref) {
	}

	context_class.prototype.path_explode = function(input) {
		var out = new Array();
		var f, ch, last = '', len = input.length;
		
		for (f = 0; f <= len; f++) {
			ch = f == len ? '/' : input.substr(f, 1);
			
			switch (ch) {
				case '/' :
					if (last != '') out[out.length] = last;
					last = '';
					break;
					
				default :
					last += ch;
					break;
			}
		}
		
		return out;
	}

	context_class.prototype.purge = function(d) {
		var a = d.attributes, i, l, n;
		if (a) {
			l = a.length;
			for (i = 0; i < l; i++) {
				n = a[i].name;
				if (typeof d[n] === 'function') d[n] = null;
			}
		}
	}

	context_class.prototype.structure_destroy = function(ref) {
		if (ref != null) {
			var stack = new Array();
			var current, f;
			stack[stack.length] = ref;
			
			while (stack.length > 0) {
				current = stack.pop();

				if (current.childNodes != null && current.childNodes.length > 0) {
					stack[stack.length] = current;
					for (f = 0; f < current.childNodes.length; f++)
						stack[stack.length] = current.childNodes[f];
					
				} else {
					this.purge(current);
					if (current.parentNode != null) current.parentNode.removeChild(current);
				}
			}
		}
	}

	context_class.prototype.object_destroy = function(ref) {
		for (var i in ref) {
			ref[i] = null;
		}
	}
	
	// --- ic_range_box_class --
	
	function ic_range_box(parent, type) {
		this.parent = parent;
		this.type = type;
		
		this.container = null;
		this.info = null;
		this.before_position = -1;
		this.position = 0;
	}
	
	ic_range_box.prototype.construct = function() {
		var self = this;
		this.container = document.createElement("DIV");
		this.container.className = this.type == 0 ? "slide_left" : "slide_right";
		this.container.ondragstart = function(trgEvent) { return false; }
		this.container.onselectstart = function(trgEvent) { return false; }
		this.container.onmousedown = function(trgEvent) { self.evt_mousedown(trgEvent == null ? event : trgEvent); }
		this.container.onmouseup = function(trgEvent) { self.evt_mouseup(trgEvent == null ? event : trgEvent); }
		this.container.onmousemove = function(trgEvent) { self.evt_motion(trgEvent == null ? event : trgEvent); }
		
		this.container.onmouseover = function() { self.evt_over(); }
		this.container.onmouseout = function() { self.evt_out(); }
		
		this.info = document.createElement("DIV");
		this.info.innerHTML = "blabla";
		this.info.onmousemove = function(trgEvent) { self.evt_motion(trgEvent == null ? event : trgEvent); }
		
		this.container.appendChild(this.info);
		
		this.parent.area.appendChild(this.container);
	}
	
	ic_range_box.prototype.is_active = function() {
		return this.parent.slide_motion == this;
	}
	
	ic_range_box.prototype.activate = function() {
		//this.info.style.display = "block";
	}
	
	ic_range_box.prototype.deactivate = function() {
		//this.info.style.display = "none";
	}
	
	ic_range_box.prototype.evt_over = function() {
		if (!this.is_active()) {
			this.update_info();
			//this.info.style.display = "block";
		}
	}
	
	ic_range_box.prototype.evt_out = function() {
		if (!this.is_active()) {
			//this.info.style.display = "none";
		}
	}
	
	ic_range_box.prototype.evt_mousedown = function(trgEvent) {
		this.parent.slide_drag_x = context.layerX(trgEvent, context.get_elementX(this.container));
		this.parent.slide_motion = this;
		this.touch();
		this.activate();
		
		cancelEvent(trgEvent, true);
	}
	
	ic_range_box.prototype.evt_mouseup = function(trgEvent) {
		this.parent.evt_mouseup(trgEvent);
	}
	
	ic_range_box.prototype.evt_motion = function(trgEvent) {
		this.parent.evt_motion(trgEvent);
	}
	
	ic_range_box.prototype.set_position = function(pos, drag) {
		this.position = pos - drag + (this.type == 1 ? -this.parent.slide_size : 0);
		this.touch();
	}
	
	ic_range_box.prototype.update_info = function() {
		if (this.type == 1) {
			this.info.innerHTML = this.parent.get_value(this.parent.slide_right.position);
		} else {
			this.info.innerHTML = this.parent.get_value(this.parent.slide_left.position);
		}
		//this.info.innerHTML = this.parent.info_container.innerHTML + "<br/>" + this.parent.get_value(this.parent.slide_left.position) + " - " + this.parent.get_value(this.parent.slide_right.position);
	}
	
	ic_range_box.prototype.touch = function(no_value_update) {
		if (this.position < 0) this.position = 0;
		else if (this.position > this.parent.area_size) this.position = this.parent.area_size;
		
		if (this.type == 0) {
			if (this.position > this.parent.slide_right.position) this.position = this.parent.slide_right.position;
		} else {
			if (this.position < this.parent.slide_left.position) this.position = this.parent.slide_left.position;
		}
		
		//this.update_info();
		
		if (this.position != this.before_position) {
			this.before_position = this.position;
			
			this.container.style.left = (this.position + (this.type == 0 ? 0 : this.parent.slide_size)) + "px";
			this.parent.touch(no_value_update);
		}
	}
	
	// --- ic_range_class ---
	
	function ic_range(base, area_size, slide_min, slide_max, slide_med, slide_step) {
	
		this.reg_ident = null;
		this.base = base;
		this.change_event = null;
		
		this.field_from = null;
		this.field_to = null;
		
		this.info_container = null;
		
		this.area_container = null;
		this.area_left = null;
		this.area_right = null;
		this.area_bg = null;
		this.area = null;
		this.area_btw = null;
		this.area_size = area_size;
		
		this.slide_size = 12;
		this.slide_min = slide_min
		this.slide_max = slide_max;
		this.slide_med = slide_med;
		this.slide_step = slide_step;
		
		this.slide_left = null;
		this.slide_right = null;
		
		this.slide_motion = null;
		this.slide_drag_x = null;
		
		this.e_left = 0;
		this.e_right = 0;
		this.exp_base = null;
		this.exp_left = 0;
		this.exp_right = 0;
	}
	
	ic_range.prototype.construct = function(field_from, field_to) {
		
		// vypocet indexu exponencialy
		this.e_left = this.slide_med - this.slide_min;
		this.e_right = this.slide_max - this.slide_med;
		
		this.exp_base = 2;
		
		this.exp_left = (this.slide_min == 0 ? -1 : Math.log(this.slide_min / this.slide_med)) / Math.log(this.exp_base);
		this.exp_right = Math.log(this.slide_max / this.slide_med) / Math.log(this.exp_base);
		
		if (isNaN(this.exp_left)) this.exp_left = 0;
		if (this.exp_left == "Infinity") this.exp_left = 0;
		if (isNaN(this.exp_right)) this.exp_right = 0;
		if (this.exp_right == "Infinity") this.exp_right = 0;
		
		// build
		var self = this;
		this.reg_ident = context.ic_collector.register(this);
		
		if (field_from == null || field_to == null) {
			var td_num = 0, f, current, stack = new Array();
			stack[0] = this.base;
			
			while (stack.length > 0) {
				current = stack.pop();
				
				switch (current.tagName.toUpperCase()) {
					case "INPUT" :
						if (current.type == "text") {
							if (this.field_from == null) this.field_from = current;
							else if (this.field_to == null) this.field_to = current;
						}
						break;
						
					case "TD" :
						td_num++;
						if (td_num == 1) this.info_container = current;
						else if (td_num == 3) this.area_container = current;
						break;
				}
				
				for (f = current.childNodes.length - 1; f >= 0; f--)
					if (current.childNodes[f].nodeType == 1) stack[stack.length] = current.childNodes[f];
			}
			
			var tmp = document.createElement("INPUT");
			tmp.type = "hidden";
			tmp.name = this.field_from.name;
			tmp.value = this.field_from.value;
			this.field_from.parentNode.appendChild(tmp);
			
			context.structure_destroy(this.field_from);
			this.field_from = tmp;
			
			var tmp = document.createElement("INPUT");
			tmp.type = "hidden";
			tmp.name = this.field_to.name;
			tmp.value = this.field_to.value;
			this.field_to.parentNode.appendChild(tmp);
			
			context.structure_destroy(this.field_to);
			this.field_to = tmp;
			
		} else {
			this.field_from = field_from;
			this.field_to = field_to;
			
			this.area_container = this.base;
		}
		
		this.area_container.innerHTML = "";
		
		this.area = document.createElement("DIV");
		this.area.innerHTML = "";
		this.area.style.width = (this.area_size + 2 * this.slide_size) + "px";
		this.area.className = "ic_range";
		this.area.ondragstart = function(trgEvent) { return false; }
		this.area.onselectstart = function(trgEvent) { return false; }
		this.area.onmouseup = function(trgEvent) { self.evt_mouseup(trgEvent == null ? event : trgEvent); }
		this.area.onmousemove = function(trgEvent) { self.evt_motion(trgEvent == null ? event : trgEvent); }
		
		this.area_left = document.createElement("SPAN");
		this.area_left.className = "ic_area_left";
		
		this.area_right = document.createElement("SPAN");
		this.area_right.className = "ic_area_right";
		
		this.area_bg = document.createElement("DIV");
		this.area_bg.className = "ic_area_bg";
		
		this.area.appendChild(this.area_left);
		this.area.appendChild(this.area_right);
		this.area.appendChild(this.area_bg);
		
		this.area_container.appendChild(this.area);
		
		this.area_btw = document.createElement("DIV");
		this.area_btw.className = "btw";
		
		this.area.appendChild(this.area_btw);
		
		this.slide_left = new ic_range_box(this, 0);
		this.slide_right = new ic_range_box(this, 1);
		
		this.slide_left.construct();
		this.slide_right.construct();
		
		var num_left = this.get_num(this.field_from);
		var num_right = this.get_num(this.field_to);
		this.slide_left.position = this.get_position(num_left == null ? this.slide_min : num_left);
		this.slide_right.position = this.get_position(num_right == null ? this.slide_max : num_right)
		
		this.slide_left.touch(true);
		this.slide_right.touch(true);
		
		if (field_from != null && field_to != null) {
			this.field_from.onchange = function() {
				self.slide_left.position = self.get_position(self.get_num(this));
				self.slide_left.touch(true);
				self.slide_right.touch(true);
			}
			
			this.field_to.onchange = function() {
				self.slide_right.position = self.get_position(self.get_num(this));
				self.slide_left.touch(true);
				self.slide_right.touch(true);
			}
		}
	}
	
	ic_range.prototype.get_num = function(field) {
		var val = parseInt(field.value);
		return isNaN(val) ? null : val;
	}
	
	ic_range.prototype.get_value = function(position) {
		if (position <= 0) return this.slide_min;
		else if (position >= this.area_size) return this.slide_max;
		
		var value, ratio, mid = Math.round(this.area_size / 2);
		
		if (position <= mid) {
			if (this.e_left > this.e_right) ratio = (position / mid);
			else ratio = 1.0 - (position / mid);
			
			value = Math.pow(this.exp_base, this.exp_left * ratio) * this.slide_med;
			
			if (this.e_left > this.e_right) {
				value = this.slide_med - value;
			}
			
		} else {
			ratio = (position - mid) / (this.area_size - mid);
			value = Math.pow(this.exp_base, this.exp_right * ratio) * this.slide_med;
		}
		
		value = Math.round(value);
		
		if (value < this.slide_min) value = this.slide_min;
		else if (value > this.slide_max) value = this.slide_max;
		
		return value;
	}
	
	ic_range.prototype.get_position = function(value) {
		if (value <= this.slide_min) return 0;
		else if (value >= this.slide_max) return this.area_size;
		
		var pos, ratio, mid = Math.round(this.area_size / 2);
		
		if (value <= this.slide_med) {
			if (this.e_left > this.e_right) value = this.slide_med - value;
			
			ratio = Math.log(value / this.slide_med) / (this.exp_left * Math.log(this.exp_base));
			if (this.e_left <= this.e_right) ratio = 1.0 - ratio;
			
			pos = ratio * mid;
			
		} else {
			ratio = Math.log(value / this.slide_med) / (this.exp_right * Math.log(this.exp_base));
			pos = ratio * (this.area_size - mid) + mid;
		}
		
		if (pos <= 0) this.pos = 0;
		else if (pos >= this.area_size) this.pos = this.area_size;
		
		return Math.round(pos);
	}
	
	ic_range.prototype.touch = function(no_value_update) {
		var diff = this.slide_right.position - this.slide_left.position;
		this.area_btw.style.width = diff + "px";
		this.area_btw.style.left = (this.slide_left.position + this.slide_size) + "px";
		
		if (no_value_update == null) {
			this.field_from.value = this.get_value(this.slide_left.position);
			this.field_to.value = this.get_value(this.slide_right.position);
		}
	}
	
	ic_range.prototype.get_values = function() {
		return new Array(
			this.field_from.value,
			this.field_to.value
		);
	}
	
	ic_range.prototype.global_evt_mouseup = function(trgEvent) { this.evt_mouseup(trgEvent); }
	ic_range.prototype.global_evt_motion = function(trgEvent) { this.evt_motion(trgEvent); }
	
	ic_range.prototype.evt_mouseup = function(trgEvent) {
		if (this.slide_motion != null) {
			var tmp = this.slide_motion;
			this.slide_motion = null;
			tmp.deactivate();
			this.evt_change();
		}
	}
	
	ic_range.prototype.evt_motion = function(trgEvent) {
		if (this.slide_motion != null) {
			//var pos = context.layerX(trgEvent, context.get_elementX(this.area));
			var pos = trgEvent.clientX - context.get_elementX(this.area);
			this.slide_motion.set_position(pos, this.slide_drag_x);
			
			cancelEvent(trgEvent, true);
		}
	}
	
	ic_range.prototype.evt_change = function(ref) {
		if (this.change_event != null)
			this.change_event(this, ref);
	}
	