

var $dom = {
	_createIEListener: function(fn) {
		return function() {
			fn.call(event.srcElement, event);
		}
	},
	is: {
		ie7: (function() {
			var agt=navigator.userAgent.toLowerCase();
			var is_major = parseInt(navigator.appVersion);
			return (is_major == 4) && (agt.indexOf("msie 7.")!=-1);
		})(),
		ie6: (function() {
			var agt=navigator.userAgent.toLowerCase();
			var is_major = parseInt(navigator.appVersion);
			return (is_major == 4) && (agt.indexOf("msie 6.")!=-1);
		})(),
		ie: (function() {
			var agt=navigator.userAgent.toLowerCase();
			return (agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1);
		})(),
		firefox: (function() {
			return navigator.userAgent.toLowerCase().indexOf('firefox')!=-1
		})(),
		opera: (function() {
			return navigator.userAgent.toLowerCase().indexOf('opera')!=-1;
		})(),
		safari: (function() {
			return navigator.userAgent.toLowerCase().indexOf('safari')!=-1;
		})(),
		chrome: (function() {
			return navigator.userAgent.toLowerCase().indexOf('chrome')!=-1;
		})()
	},
	_cssToJSCache: {
		"float": "cssFloat"
	},
	_cssToJS: function(cssName) {
		if($dom._cssToJSCache[cssName])
			return $dom._cssToJSCache[cssName];
		else {
			return $dom._cssToJSCache[cssName] =
				cssName.split(/-/).map(
					function(i, part) {
						if(i!=0)
							return part.charAt(0).toUpperCase() + part.slice(1);
						else
							return part;
					}).accumulate("",
						function(sum, x) {
							return sum + x;
					});
		}
	},
	add: function(node) {
		if(typeof node == 'string')
			node = document.getElementById(node);
		if(!node)
			return node;
		if(node instanceof Array) {
			var args = Array.fromObject(arguments);
			args.shift();
			return node.map(function(v) {
				return $dom.add(v, args);
			});
		}
		for(var i=1; i<arguments.length; i++) {
			var child = arguments[i];
			if(!child)
				continue;
			if(child.nodeName)
				node.appendChild(child);
			else if(child.constructor==Array && !child.childType)
				child.foreach(function(c) {
					$dom.add(node, c);
				});
			else switch(child.childType) {
			case 1: //attribute
				switch(child[0]) {
				case "class":
					if(!$dom.haveClass(node, child[1])) {
						if(node.className)
							node.className += " " + child[1];
						else
							node.className = child[1];
					}
					break;
				default:
					node.setAttribute(child[0], child[1]);
				}
				break;
			case 2: //style
				if(child[0]=='opacity' && $dom.is.ie) {
					var opacity = child[1] * 100;
					var prop = node.filters['DXImageTransform.Microsoft.alpha'] || node.filters.alpha;
					if(prop)
						prop.opacity = opacity;
					else
						node.style.filter += "progid:DXImageTransform.Microsoft.Alpha(opacity="+opacity+")";

				} else if(node.style)
					node.style[$dom._cssToJS(child[0])] = child[1];
				break;
			case 3: //event
				if(child[0]=='language') {
					if(!node.onlanguage)
						node.onlanguage = $handler();
					node.onlanguage.add(function() {
							child[1].call(node);
						});
				} else if(node.addEventListener) {
					node.addEventListener(child[0],
						function(e) {
							if(!window.event)
								window.event = e;
							return child[1].call(node, e);
						},
						window.opera==undefined);
				} else
					node.attachEvent("on" + child[0], $dom._createIEListener(child[1]));
				break;
			case 4: //text node
				node.appendChild(document.createTextNode(child[0]));
				break;
			default:
				throw new Error("Invalid argument.");
			}
		}
		return node;
	},
	element: function(name) {
		var res = document.createElement(name);
		for(var i=1; i<arguments.length; i++)
			$dom.add(res, arguments[i]);
		return res;
	},
	attr: function(name, value) {
		var res = [name, value];
		res.childType = 1;
		return res;
	},
	style: function(name, value) {
		var res = [name, value];
		res.childType = 2;
		return res;
	},
	event: function(type, handler) {
		if(type instanceof Array)
			return type.map(function(v) {
					return $dom.event(v, handler);
				});
		if(handler instanceof Array) {
			return handler.map(function(v) {
				return $dom.event(type, v);
			});
		}
		if(type=="mouseover" && $dom.is.ie)
			type = "mouseenter";
		else if(type=="mouseout" && $dom.is.ie)
			type = "mouseleave";
		return [type, handler].extend({childType: 3});
	},
	text: function(txt) {
		var res = [txt];
		res.childType = 4;
		return res;
	},
	removeClass: function(el, cl) {
		if(el instanceof Array)
			return el.map(function(v) {
				return $dom.removeClass(v, cl);
			});
		if(cl instanceof Array)
			return cl.map(function(v) {
				return $dom.removeClass(el, v);
			});
		if(typeof el == 'string')
			el = document.getElementById(el);
		if(!el)
			return el;
		if(!el.className)
			return el;
		el.className = el.className.split(/\s+/g).filter(function(s) {
				return s!=cl;
			}).accumulate(false, function(res, v) {
				return res ? (res + " " + v) : v;
			});
		return el;
	},
	haveClass: function(el, cl) {
		if(typeof el == "string")
			el = document.getElementById(el);
		if(!el)
			return false;
		if(!el.className)
			return false;
		return el.className.split(/\s+/g).accumulate(false, function(res, v) {
			return res || (v==cl);
		});
	},
	children: function(el) {
		if(typeof el == 'string')
			el = document.getElementById(el);
		if(!el || !el.childNodes)
			return [];
		if(el instanceof Array) {
			return el.map($dom.children).accumulate([], function(res, v) {
					return res.concat(v);
				});
		} else {
			return Array.fromObject(el.childNodes).filter(function(v) {
				return v!=null;
			});
		}
	},
	childNodes: function(el) {
		return $dom.children(el);
	},
	ancestors: function(el) {
		if(typeof el == 'string')
			el = document.getElementById(el);
		if(!el)
			return [];
		var res = [];
		for(var i=el.parentNode; i!=document.documentElement; i=i.parentNode)
			res.push(i);
		return res;
	},
	parent: function(nd) {
		if(!nd)
			return null;
		if(nd instanceof Array)
			return nd.map(function(nd) { return $dom.parent(nd) });
		else
			return nd.parentNode;
	},
	remove: function(el) {
		if(typeof el == 'string')
			el = document.getElementById(el);
		if(!el)
			return;
		if(el instanceof Array)
			el.foreach($dom.remove);
		else if(el.parentNode)
				el.parentNode.removeChild(el);
			
	},
	removeChildNodes: function(el) {
		if(typeof el == 'string')
			el = document.getElementById(el);
		if(!el)
			return el;
		while(el.firstChild)
			el.removeChild(el.firstChild);
		return el;
	},
	get: {
		opacity: function(el) {
			if(typeof el=='string')
				el = document.getElementById(el);
			if(!el)
				return null;
			if(el.style.opacity)
				return new Number(el.style.opacity);
			else if(el.style.MozOpacity)
				return new Number(el.style.MozOpacity);
			else if(el.filters && (el.filters['DXImageTransform.Microsoft.alpha'] || el.filters.alpha))
				return new Number((el.filters['DXImageTransform.Microsoft.alpha'] || el.filters.alpha).opacity)/100;
			return 1;
		}
	},
    textValue: function(el) {
        if(!el)
            return "";
        if(typeof el=='string')
		    el = document.getElementById(el);
        return $dom.children(el).filter($jsxt.pName("#text")).accumulate("", function(s1, s2) { return s1 + s2.nodeValue; });
    }
}

var $event = function() {
	return {
		keys: {
			"alt": event.altKey,
			"ctrl": event.ctrlKey,
			"shift": event.shiftKey
		},
		cancel: function() {
			event.returnValue = false;
		},
		target: event.target ? event.target : event.srcElement
	}
}

var $effect = {
	_cancelEffect: function(el) {
		if(el._effect && el._effect.finished && !el._effect.finished()) {
			el._effect.cancel();
			el._effect = null;
		}
	},
	fadeIn: function(el, time) {
		if(typeof el=='string')
			el = document.getElementById(el);
		if(!el)
			return;
		$effect._cancelEffect(el);
		var framesCount = Math.min(Math.max(Math.round((24/1000)*time), 1), 256);
		var start_opacity = el.style.display=='none' ? 0 : $dom.get.opacity(el);
		if(start_opacity==1)
			return;
		$dom.add(el, $dom.style('opacity', start_opacity), $dom.style('display', 'block'));
		el._effect = $range(0, framesCount).timerMap(function(frame) {
				$dom.add(el, $dom.style('opacity', start_opacity + (1-start_opacity)*(frame+1)/framesCount));
			}, Math.round(time/framesCount));
	},
	fadeOut: function(el, time) {
		if(typeof el=='string')
			el = document.getElementById(el);
		if(!el)
			return;
		$effect._cancelEffect(el);
		framesCount = Math.max(Math.round((24/1000)*time), 1);
		var start_opacity = el.style.display=='none' ? 0 : $dom.get.opacity(el);
		if(start_opacity==0) {
			$dom.add('el', $dom.style('display', 'none'));
			return;
		}
		$dom.add(el, $dom.style('opacity', start_opacity), $dom.style('display', 'block'));
		el._effect = $range(0, framesCount).timerMap(function(frame) {
				$dom.add(el, $dom.style('opacity', start_opacity - start_opacity*(frame+1)/framesCount))
			}, Math.round(time/framesCount));
		el._effect.onfinish.add(function() {
				$dom.add(el, $dom.style('display', 'none'));
			});
	}
}
