/*
 * created by Pavel Spacil, 2008-2009
 * modified by:
 */
// SJEL core (common properties, ...)
/*
TODO:
- udelat neco jako retezic udalosti :) -> (napr. skonci jedna, zacne druha, ...a)
- pridat bezpecne - AddAttr, RemoveAttr
- Timer - OnStop - pole funkci
- GStyle - moznost zadat vice hodnot oddelenych carkou ("width, height, ..."), vracet bude pole
- SHOW a HIDE funguji nejak blbe
*/
var SJEL = function () {
// private
var pr = {
	cl: {},
	log: null,
	logBl: 0,
	sho: new Array(),  // show/hide objects
	disps: new Array(),  // display values of sho
	regst: new RegExp("^-*\\d+\\.*\\d*([^\d]*)"),
	
	Pass: function () {}
	
};  // private

// protected
var pro = {
	/**
	 * print error message
	 */
	msg: function (_msg) {
		alert("SJEL error: " + _msg);
	}
};  // protected

// public
var pu = {
	ie:0,
	LEFT_BUTTON: 1,
	MIDDLE_BUTTON: 2,
	RIGHT_BUTTON: 3,
	//ww:0,  // window width
	//wh:0,  // window height
	
   
	/**
	 * _w - width (optional)	 
	 * _h - height (optional)	 
	 * _bl - buffer length - num rows (optional)	 
	 */	 	
	CreateLog: function (_w, _h, _bl) {
		if (pr.log == null) {
			pr.logBl = _bl||10;
			pr.log = SJEL.CE("div");
			SJEL.SStyle(pr.log, {top: "5px", right: "5px", zIndex: 10000, width: (_w||250) + "px", height: (_h||150) + "px", color: "#000", fontSize: "11px", backgroundColor: "#f6f6f6", border: "1px solid #ddd", overflow: "auto", padding: "5px 10px", textAlign: "left"});
			if (pu.ie == 6)
				SJEL.SStyle(pr.log, {position: "absolute"});
			else
				SJEL.SStyle(pr.log, {position: "fixed"});
					
			document.body.appendChild(pr.log);

			SJEL.Log("SJEL log is initialized ...");
		}
	},  // END CreateLog

	CloseLog: function () {
		if (pr.log != null) {
			document.body.removeChild(pr.log);
			pr.log = null;
		}
	},

	ClearLog: function () {
		if (pr.log != null) {
			pr.log.innerHTML = "";
		}
	},

	Log: function (_m) {
		if (pr.log != null) {
			var e = SJEL.CE("div");
			e.innerHTML = _m;
			pr.log.appendChild(e);
			if (pr.log.childNodes.length > pr.logBl)
				pr.log.removeChild(pr.log.firstChild);
		}
	},

	/**
	 * initialization of SJEL
	 */
	Init: function () {		
		var r = /^.*Microsoft.*$/;
		if (r.test(navigator.appName))
			pu.ie = 1;
		
		r = /^.*MSIE 6.*$/;
		var v = navigator.appVersion;
		if (r.test(v))
			pu.ie = 6;
		
		r = /^.*MSIE 7.*$/;
		if (r.test(v))
			pu.ie = 7;
		
		r = /^.*MSIE 8.*$/;
		if (r.test(v))
			pu.ie = 8;
			
		/*var v = pu.GWindowWH();
		pu.ww = v[0];
		pu.wh = v[1];*/
	},  // END Init
	   
	/**
	 * print info about SJEL methods and attributes
	 */
	/*Info: function () {      
		function I(_t, _o) {
			var r = /function\s*\((.*)\)/i;
			var m;
			var s = _t + ":\n";
			
			for (o in _o) {
				m = r.exec(_o[o]);
				s += '\t' + o;
				if ((m != null) && (m.length > 1) && (m[1] != ""))
					s +=  " (" + m[1] + ")\n";
				else
					s += '\n';
			}
			
			return s;
		}
		
		var s = "SJEL info\n--------------\n";
		s += I("public", pu);
		s += '\n';
		s += I("protected", pro);
		s += '\n';
		s += I("private", pr);        
		s += '\n';
		s += I("registered classes", pr.cl);        
		alert(s);
	},*/
    
	/**
	 * get element by id
	 */
	$: function (_id) {
		/*var id = pu.SP(_id, "", "str");
		if (*/
		/*el = document.getElementById(_id);
		if (el != null)
			return el;
		else {
			pro.msg("bad id '" + _id + "'");
			return null;
		}*/
		return document.getElementById(_id);
	},

	/**
	 * get element by id, if _id is element, return this element
	 */
	$$: function (_id) {
		if (typeof(_id) == "object")
			return _id;
		else if (typeof(_id) == "string")
			return pu.$(_id);
		else
			return null;
	},
    
	/**
	 * get elements by tag name
	 * _e - element	or id of element      
	 * _t - tag name
	 */
	$T: function (_e, _t) {
		_e = pu.$$(_e);
			
		if (_e)
			return _e.getElementsByTagName(_t);
		else
			return document.getElementsByTagName(_t);
	},

	/**
	 * trim string
	 */
	Trim: function (_s) {
		return _s.replace(/^\s*/, "").replace(/\s*$/, "");
	},

	/**
	 * get elements by attribute
	 * _e - element	or id of element
	 * _a - attribute
	 * _av - attribute value. if undefined, then finds all attributes _a
	 * _tn - tag name (optional)	    
	 */
	$A: function (_e, _a, _av, _tn) {
		var e = pu.$T(_e, (_tn != undefined) ? _tn : "*");
		var e2 = new Array(), av = new Array();
		
		if (_av)
			av = _av.split(',');
		
		var i = 0, j = 0, ta, idx, a;
		
		for (i = 0; i < av.length; i++)
			av[i] = pu.Trim(av[i]);
			
		for (i = 0; i < e.length; i++) {
			if (pu.ie && (_a == "class"))
				a = e[i].className;
			else
				a = e[i].getAttribute(_a);
			
			if (a != null) {
				if (av.length > 0) {
					ta = a.split(' ');
					for (j = 0; j < ta.length; j++)
						ta[j] = pu.Trim(ta[j]);
					
					for (j = 0; j < av.length; j++) {
						idx = pu.InArray(av[j], ta);
						if (idx != -1)  {
							e2.push(e[i]);
							break;
						}
					}
				} else
					e2.push(e[i]);
			}
		}
		
		return e2;
	},  // END $A

	/**
	 * get event target
	 * _e - event	 
	 */
	$ET: function (_e) {
		if ((_e == undefined) || pu.ie) {
			_e = window.event;
			return _e.srcElement;
		} else
			return _e.target;
	},

	/**
	 * get absolute position 
	 */
	GAbsPos: function (_el) {
		var pos = new Array();
		pos.push(0); pos.push(0);
		
		if (_el.offsetParent) {
			var ob = _el;
			do {
				pos[0] += parseInt(ob.offsetLeft);
				pos[1] += parseInt(ob.offsetTop);
			} while (ob = ob.offsetParent);
		}
		
		return pos;
	},  // END GAbsPos

	/**
	 * _el2 some parent of _el1 or equal -> true
	 */
	IsIn: function (_el1, _el2) {
		if (_el1 == _el2)
			return true;

		var i = false;
		
		if (_el1.parentNode) {
			var ob = _el1;
			while (ob = ob.parentNode)
				if (ob == _el2) {
					i = true;
					break;
				}
		}
		
		return i;
	},

	/**
	 * get external style
	 */
	GEStyle: function (_e) {
		if (!pu.ie)
			return document.defaultView.getComputedStyle(_e, "");
		else
			return _e.currentStyle;
	},

	/**
	 * get style (external or )
	 */
	GStyle: function (_e, _s) {
		if ((_e.style[_s] != "") && (_e.style[_s] != undefined))
			return _e.style[_s];
		else { 
		 	var es = pu.GEStyle(_e);
			if ((es[_s] != "") && (es[_s] != undefined)) {
				if (SJEL.ie) {
					if (es[_s] == "auto") {
						switch (_s) {
							case "width": return _e.offsetWidth;
							case "height": return _e.offsetHeight;
						}
					}
				}
				return es[_s];
			}
		}
		
		return 0;
	},

	/**
	 * set style, _style is object e.g. {width: 200, height: 100}
	 * _e - element or id of element
	 * _s - style	      
	 */
	SStyle: function (_e, _s) {
		_e = pu.$$(_e);
		var es = _e.style, s, m;
		for (s in _s) {
			if (es == undefined)
				continue;

//			if (pro.pxo(s, _s[s]))
//			if (pro.pxo(s))
			//m = pr.regst.exec(_s[s]);
			if (s == "opacity") {
				if (pu.ie) {
					es.zoom = 1;
					es.filter = "alpha(opacity = " + Math.round(100 * _s[s]) + ")";
					es.opacity = _s[s];
				} else {
					es[s] = _s[s];
				}
			} /*else if ((m != null) && (m.length > 1)) {
				es[s] = parseInt(_s[s]) + m[1];
				alert(es[s]);
			}*/ else {
				/*if (pu.ie)
					alert(s);*/
				es[s] = _s[s];
			}
		}
	},  // END SStyle
	
	/**
	 * safely hides element _el - it stores element display value
	 */
	Hide: function (_el) {
		pr.sho.push(_el);
		pr.disps.push(pu.GStyle(_el, "display"));
		pu.SStyle(_el, {display: "none"});
	},	 	

	/**
	 * shows element _el
	 */
	Show: function (_el) {
		var id = pu.InArray(_el, pr.sho);
		if (id > -1) {
			pu.SStyle(_el, {display: pr.disps[id]});
			pu.RemoveItem(_el, pr.sho);
			pu.RemoveItem(id, pr.disps, true);
		}
	},	 	

	/**
	 * get rgb color values from string (e.g. #eee, rgb(255, 0, 0))
	 * _c - color     
	 */
	ParseRGB: function (_c) {
		var r = 0;
		var g = 0;
		var b = 0;
		var col = pu.SP(_c, "#fff", "str");
		var m = /rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i.exec(col);
		
		if ((m != null) && (m.length > 1)) {
			r = m[1];
			g = m[2];
			b = m[3];
		} else {
			m = /#(\w{2})(\w{2})(\w{2})/i.exec(col);
			if ((m != null) && (m.length > 1)) {
				r = parseInt(m[1], 16);
				g = parseInt(m[2], 16);
				b = parseInt(m[3], 16);
			} else {
				m = /#(\w{1})(\w{1})(\w{1})/i.exec(col);
				if ((m != null) && (m.length > 1)) {
					r = parseInt(m[1] + m[1], 16);
					g = parseInt(m[2] + m[2], 16);
					b = parseInt(m[3] + m[3], 16);
				}
			}
		}
		
		return [r, g, b];
	},  // END ParseRGB
	
	/**
	 * convert rgb values to string, default is rgb() notation
	 * _h - hex     
	 */
	RGBToString: function (_r, _g, _b, _h) {
		if (_h == undefined)
			return "rgb(" + _r + "," + _g + "," + _b + ")";
		else {
			var r = _r.toString(16);
			var g = _g.toString(16);
			var b = _b.toString(16);
			
			if (r.length == 1)
				r = '0' + r;
			if (g.length == 1)
				g = '0' + g;
			if (b.length == 1)
				b = '0' + b;			

			return "#" + r + g + b;
		}
	},  // END RGBToString
	
	/**
	 *
	 */
	Color: function (_r, _g, _b) {
		this.r = 0;
		this.g = 0;
		this.b = 0;
		
		this.Set = function (_r, _g, _b) {
			this.r = pu.SP(_r, 0, "num");
			this.g = pu.SP(_g, 0, "num");
			this.b = pu.SP(_b, 0, "num");
		};
		
		this.Set(_r, _g, _b);

		this.FromString = function (_c) {
			var c = SJEL.ParseRGB(_c);
			this.Set(parseInt(c[0]), parseInt(c[1]), parseInt(c[2]));
		};
		
		this.ToString = function (_h) {
			return SJEL.RGBToString(this.r, this.g, this.b, _h);
		};
	},  // END Color
    
	/**
	 * add class
	 * _c - class code
	 * _n - class name	      
	 */
	RegisterClass: function (_c, _n) {
		pr.cl[_c] = _n;
	},

	/**
	 * adds event listener to element _el. handler will be executed in bubbling mode
	 * _el - element or id of element
	 * _e - event name (without 'on' prefix)
	 * _l - listener (function)	 	      
	 */
	AddEvent: function (_el, _e, _l) {
		_el = pu.$$(_el); 
		
		if (!_el) return;
		
		if (!pu.ie)
			_el.addEventListener(_e, _l, false);
		else
			_el.attachEvent("on" + _e, _l);  // toto jeste prokoumat, nemusi byt vzdy "on"
	},
	
	/**
	 * adds onload event on window	
	 * _l - listener (function)	 	      
	 */	
	OnPageLoad: function (_l) {
		pu.AddEvent(window, "load", _l);
	},

	/**
	 * adds onunload event on window	
	 * _l - listener (function)	 	      
	 */	
	OnPageUnload: function (_l) {
		pu.AddEvent(window, "unload", _l);
	},

	/**
	 * removes event listener from element _el
	 * _el - element
	 * _e - event name (without 'on' prefix)
	 * _l - listener (function)	 	      
	 */
	RemoveEvent: function (_el, _e, _l) {
		if (!_el) return;
		
		if (!pu.ie)
			_el.removeEventListener(_e, _l, false);
		else
			_el.detachEvent("on" + _e, _l);  // toto jeste prokoumat, nemusi byt vzdy "on"
	},
    
	/**
	 * stops bubbling
	 * _e - event     
	 */
	StopPropagation: function (_e) {
		var e = _e;
		/*if (!_e)
			e = window.event;
		e.cancelBubble = true;
		if (e.stopPropagation)*/
			e.stopPropagation();
	},

	/**
	 * create new instance of class
	 * _c - class code     
	 */
	New: function (_c) {
		if (pr.cl[_c] != undefined)
			return new pr.cl[_c](pro);
		else {
			pro.msg("New: class code '" + _c + "' doesn't exists.");
			return null;
		}
	},
	
	ForIn: function (_a, _f, _p1, _p2, _p3) {
		for (i in _a)
			if (!_f(_a[i], _p1, _p2, _p3))
				break;
	},
	
	ForI: function (_a, _f, _p1, _p2, _p3) {
		var i = 0;
		for (i = 0; i < _a.length; i++)
			if (!_f(_a[i], _p1, _p2, _p3))
				break;
	},
    
	/**
	 * get scroll values
	 */
	GScrollXY: function () {
		var x = 0;
		var y = 0;
		
		if (typeof(window.pageYOffset) == 'number') {
			x = window.pageXOffset;
			y = window.pageYOffset;
		} else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
			x = document.body.scrollLeft;
			y = document.body.scrollTop;
		} else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
			x = document.documentElement.scrollLeft;
			y = document.documentElement.scrollTop;
		}
		
		return [x, y];
	},  // END GScrollXY

	/**
	 * get browser window width and height
	 */
	GWindowWH: function () {
		var w = 0;
		var h = 0;
		
		if(typeof(window.innerWidth) == 'number') {
			w = window.innerWidth;
			h = window.innerHeight;
		} else if(document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
			w = document.documentElement.clientWidth;
			h = document.documentElement.clientHeight;
		} else if(document.body && (document.body.clientWidth || document.body.clientHeight)) {
			w = document.body.clientWidth;
			h = document.body.clientHeight;
		}
		
		return [w, h];
	},  // END GWindowWH

	/**
	 * linear interpolation, _t between <0, 1>
	 */
	Lerp: function (_a, _b, _t) {
		return ((1.0 - _t)*_a + _t*_b);
	},

	/**
	 * cosine interpolation, slower at the beginning, _t between <0, 1>
	 */
	EasyIn: function (_a, _b, _t) {
		var c = (1.0 - Math.cos(Math.PI / 2.0 * _t));
		return ((1.0 - c)*_a + c*_b);
	},
	
	/**
	 * cosine interpolation, slower at the end,_t between <0, 1>
	 */
	EasyOut: function (_a, _b, _t) {
		var c = (1.0 - Math.cos(Math.PI / 2.0 * (1.0 - _t)));
		return (c*_a + (1.0 - c)*_b);
	},

	EaseOutBounce: function (_a, _b, _t) {
		if (_t < (1 / 2.75)) {
			return _b * (7.5625 * _t * _t) + _a;
		} else if (_t < (2 / 2.75)) {
			return _b * (7.5625 * (_t -= (1.5/2.75)) * _t + 0.75) + _a;
		} else if (_t < (2.5/2.75)) {
			return _b * (7.5625 * (_t -= (2.25/2.75)) * _t + 0.9375) + _a;
		} else {
			return _b * (7.5625 * (_t -= (2.625/2.75)) * _t + 0.984375) + _a;
		}
	},

	EaseInBounce: function (_a, _b, _t) {
		return _b - pu.EaseOutBounce (0, _b, 1.0 - _t) + _a;
	},

	/**
	 * cosine interpolation, slower on both sides, _t between <0, 1>
	 */
	EasyBoth: function (_a, _b, _t) {
		var c = (1.0 - Math.cos(Math.PI * _t)) * 0.5;
		return ((1.0 - c)*_a + c*_b);
	},
	
	/**
	 * document.createElement
	 * _e - element 
	 */	 	
	CE: function (_e) {
		return document.createElement(_e);
	},

	/**
	 * document.createTextNode
	 * _e - element 
	 */	 	
	CTN: function (_tn) {
		return document.createTextNode(_tn);
	},

	/**
	 * retuns index of the first founded item _i in array _a, otherwise returns -1
	 */	 	
	InArray: function (_i, _a) {
	    var i = 0, f = -1;
	    
	    for (i = 0; i < _a.length; i++)
	        if (_i == _a[i]) {
	            f = i;
	            break;
	        }
	        
	    return f;
	},  // END InArray

	/**
	 * removes item _i from array _a. if _ii is defined and true, then _i means index in array _a
	 * returns item if item was deleted	 
	 */	 	
	RemoveItem: function (_i, _a, _ii) {
	    var i = 0;

		if ((_ii != undefined) && (_ii == true) && (_a[_i] != undefined))
			_i = _a[_i];

	    for (i = 0; i < _a.length; i++)
	        if (_i == _a[i])
	            return _a.splice(i, 1);
	        
	    return false;
	},  // END RemoveItem

	/**
	 * checks class existence. if exists, returns pair array of classes and index
	 * of founded class	 
	 */	 	
	ClassExists: function (_el, _cl) {
		if (_el == null) return;
		var ta = _el.className.split(' ');
		var idx = pu.InArray(_cl, ta);
		if (idx != -1)
			return [ta, idx];
		else 
			return false;
	},  // END ClassExists

	/**
	 * add class _cl to element _el
	 */	 	
	AddClass: function (_el, _cl) {
		//if (!pu.ClassExists(_el, _cl))
		_el.className += " " + _cl;
	},  // END AddClass

	/**
	 * remove safely class _cl from element _el
	 */
	RemoveClass: function (_el, _cl) {
		var ta = pu.ClassExists(_el, _cl);
		if (ta) { 
			ta[0].splice(ta[1], 1);
			_el.className = ta[0].join(' ');
		}
	},  // END RemoveClass
	
	/**
	 * set parameter, type checking
	 * _p - parameter
	 * _d - default
	 * _t - type	 	      
	 */
	SP: function (_p, _d, _t) {
		if (_p == undefined)
			_p = _d;
			
		if ((_t != undefined) && (_p != undefined)) {
			var s = "SP: parameter is not a ";
			switch (_t) {
				case "num":
					if (typeof(_p) != "number")
						pro.msg(s + "number");
					break;
				case "str":
					if (typeof(_p) != "string")
						pro.msg(s + "string");
					break;
				case "bool":
					if (typeof(_p) != "boolean")
						pro.msg(s + "boolean");
					break;
				case "func":
					if (typeof(_p) != "function")
						pro.msg(s + "function");
					break;
			}
		}
			
		return _p;
	},  // END SP
	
	/**
	 * timer class, _speed
	 * _f - function
	 * _d - duration
	 * _s - speed
	 * _o - oneShot	 	 	      
	 */
	Timer: function (_f, _d, _s, _o, _fps) {
		var ref = this,
		id = 0,
		f = _f||null,
		utl = ((typeof(f) == "string") && (f == "timeline")) ? true : false,  // use time line
		fs = p1 = p2 = p3 = p4 = null,  // on stop func + parameters
		d = pu.SP(_d, 1000, "num"),
		s = pu.SP(_s, 15, "num"),
		t = 0.0,  // <0, 1>
		fps = _fps||60, ifps = 1 / fps, tp = 1000.0/(d * fps), ctp = 0.0,
		fr = 0,  // frame counter
		o = pu.SP(_o, false, "bool"),
        	dt = 0.0,
        	ti = 0.0,
        	r = false,
        	inf = false,
        	tf = new Array(),  // pole casu a funkci (pro timeline)
        	tfId = 0,
        	stt = 0;  // start time
		
		// _inf - infinite loop
		this.Start = function (_inf) {
			if (((f == null) || (d <= 0)) && !utl)
				return false;

			inf = _inf||false;
			if (utl)
				inf = true;
			
			if (id != 0)
				this.Stop();
			
			r = true;
			stt = new Date().getTime();
			t = ctp = 0.0;
			
			if (o)
				id = setTimeout(OnTimer, s);
			else
				id = setInterval(OnTimer, s);
		};
		
		this.Stop = function(_cf) {  // _cf - call function
			var cf = (_cf == undefined) ? true : false;
			
			if (id != 0) {
				if (!inf)
					f();
					
				if (o)
					clearTimeout(id);
				else
					clearInterval(id);
					
				id = 0;
				r = false;
			}
			
			if ((fs != null) && cf)
				fs(p1, p2, p3, p4);
		};
		
		function OnTimer() {
			if (!inf) {
				var ct = new Date().getTime();  // current time
				if (ct >= stt + d) {
					t = 1.0;
					ref.Stop();
					return;
				} else
					t = (ct - stt) / d;
	
				if (t >= ctp + tp) {
					ctp += tp;
					f();
				}
			} else if (utl && (tf.length > 0)) {
				var ct = new Date().getTime();  // current time

				t = (ct - stt) / d;
				if (t >= ctp + tp) {
					ctp += tp;
					fr += 1;

					if (t >= tf[tfId].ti) {
						tf[tfId].fu(tf[tfId].p1, tf[tfId].p2, tf[tfId].p3);
																			
						if (++tfId >= tf.length)
							ref.Stop();

						var he = tfId;
						for (var ii = he; ii < tf.length; ii++) {
							if (t >= tf[ii].ti) {
								tf[ii].fu(tf[ii].p1, tf[ii].p2, tf[ii].p3);
								tfId++;
							} else {
								break;
							}
						}
						
						if (++tfId >= tf.length)
							ref.Stop();
					}
//					f();
				}
			} else
				f();
		};
		
		this.SetFps = function (_fps) {
			fps = _fps;
			ifps = 1 / fps;
			tp = 1000.0/(d * fps);
		};

		this.SetOneShot = function (_o) {
			o = pu.SP(_o, false);
		};
		
		this.SetDuration = function (_d) {
			d = pu.SP(_d, 1000, "num");
			tp = 1000.0/(d * fps);
		};
		
		this.SetSpeed = function (_s) {
			s = pu.SP(_s, 10, "num");
		};
		
		this.SetFunc = function (_f) {
			f = pu.SP(_f, null, "func");
		};
		
		this.IsRunning = function () {
			return r;
		};
		
		this.OnStop = function (_f, _p1, _p2, _p3, _p4) {
			p1 = _p1;
			p2 = _p2;
			p3 = _p3;
			p4 = _p4;
			fs = pu.SP(_f, null, "func");
		};
		
		this.GetT = function () {			
			return t;
		};

		this.GetDt = function () {
			return dt;
		};

		this.AddItem = function(_time, _func, _p1, _p2, _p3) {
			tf.push(new TF(_time, _func, _p1, _p2, _p3));
		};
		
		function TF(_time, _func, _p1, _p2, _p3) {
			this.ti = _time;
			this.fu = _func;
			this.p1 = _p1;
			this.p2 = _p2;
			this.p3 = _p3;
		};
	},  // END Timer

	/**
	 * returns , _v <0.0, 1.0>
	 */
	GetOpacity: function (_v) {
		if (_v < 0.0)
			_v = 0.0;
		else if (_v > 1.0)
			_v = 1.0;
			
		if (!pu.ie)
			return {opacity: _v.toString()};
		else {
			var op = "alpha(opacity = " + Math.round(100 * _v) + ")";
			// {filter: op, zoom: 1}
			return {filter: op};
		}
	},  // END GetOpacity
	
	Morph: function (_ifu) {
	 	// element, element style, style, duration, timer, from-to, interpolation function
	 	var e = null, es = null, st = null, d = 1000, fps = 60, ref = this,
			ti = new pu.Timer(OnMorph_), ft = new Array(), ifu = "", c = new pu.Color(), omFunc = null;  // omFunc - on morph function 
			
		if (_ifu != undefined)
			ifu = _ifu;  
	 	
	 	function FT () {
	 		this.fr = {v: 0, u: "px"};  // from
	 		this.to = {v: 0, u: "px"};
	 	};
	 	
	 	// parse style
	 	function PS (_s, _f) {
	 		var s = 0;
			
			if ((_s == "color") || (_s == "backgroundColor")) {
				var col = new pu.Color();
				col.FromString(_f);
				s = [col, ""];
			} else if (_s == "opacity") {
				s = [_f, ""];
			} else {
				var m = pr.regst.exec(_f);
				if ((m != null) && (m.length > 1)) {
					s = [parseInt(_f), m[1]];
					//alert('dddddddd', m[1]);
				}
			}

			return s;
	 	};
	
		/**
		 * _s - style
		 * _d - duration	 
		 */	 	
	 	this.Init = function (_id, _s, _d, _fps) {
	 		d = pu.SP(_d, 500, "num");
	 		fps = _fps||60;

	 		if (typeof(_id) == "function") {
	 			omFunc = _id;
	 			return;
	 		} else {
	 			e = SJEL.$$(_id);
	 			if (e == null)
	 				return;
	 		}

	 		es = pu.GEStyle(e);
	 		st = pu.SP(_s, null);
	 		if (st == null)
	 			return;
	 		/*if (timer == null)
	 			timer = new SJEL.Timer(OnMorph);*/
	 		
	 		var tmp = [];
	 		for (s in st) {
	 			ft[s] = new FT();
	 			ft[s].fr.v = pu.GStyle(e, s);

				/*if (s == "opacity")
					alert(e.style.opacity);*/
					//ft[s].fr = 0;
				// !!problemy v IE	 			
				if (pu.ie && (ft[s].fr.v == "auto"))
					ft[s].fr.v = 0;
				
				tmp = PS(s, ft[s].fr.v);
				ft[s].fr.v = tmp[0];
				ft[s].fr.u = tmp[1];
				
				tmp = PS(s, st[s]);
				ft[s].to.v = tmp[0];
				ft[s].to.u = tmp[1];
	 		}
	 	};
	 	
	 	this.Inte = function (_a, _b, _x, _t) {  // interpolace
	 		var fu = null;
	 		
			if ((_t == undefined) || (_t == ""))
	 			fu = pu.Lerp;
	 		else if (_t == "lerp")
	 			fu = pu.Lerp;
	 		else if (_t == "easyin")
	 			fu = pu.EasyIn;
	 		else if (_t == "easyout")
	 			fu = pu.EasyOut;
	 		else if (_t == "easyboth")
	 			fu = pu.EasyBoth;
	 		else if (_t == "easyoutbounce")
	 			fu = pu.EaseOutBounce;
	 		else if (_t == "easyinbounce")
	 			fu = pu.EaseInBounce;
	 		
			 return fu(_a, _b, _x)
		};
	 	
	 	function OnMorph_ () {
	 		var tm = ti.GetT();
	 		
			 if (omFunc != null)
	 			omFunc(tm);
			
			if (st == null)
				return;
			
	 		var t = {};
	 		for (f in ft) {
				switch (f) {
					case "backgroundColor": case "color":
						var ffr = ft[f].fr.v, tto = ft[f].to.v;
						c.r = Math.round(ref.Inte(ffr.r, tto.r, tm, ifu));
						c.g = Math.round(ref.Inte(ffr.g, tto.g, tm, ifu));
						c.b = Math.round(ref.Inte(ffr.b, tto.b, tm, ifu));
						t[f] = c.ToString();
						break;
					case "opacity":
						//t = pu.GetOpacity(pu.Lerp(ft[f].fr, ft[f].to, tm));
						t[f] = ref.Inte(ft[f].fr.v, ft[f].to.v, tm, ifu);
						//alert(t[f]);
						break;
					default:
						t[f] = Math.round(ref.Inte(ft[f].fr.v, ft[f].to.v, tm, ifu)) + ft[f].fr.u;
				}
	 		}
	 		
	 		//alert(t[f]);
	 		pu.SStyle(e, t);
	 	};
	 	
	 	this.Morph = function () {
	 		if (ti.IsRunning())
	 			ti.Stop();
	 		if ((st == null) && (omFunc == null))
	 			return;
	 		ti.SetDuration(d);
	 		ti.SetFps(fps);
	 		ti.Start();
	 	};
	 	
	 	this.Stop = function () {
			ti.Stop(false);
		};
	 	
	 	this.OnMorphFinished = function (_f, _p1, _p2, _p3, _p4) {
			var f = pu.SP(_f, null, "func");
			ti.OnStop(f, _p1, _p2, _p3, _p4);
	 	};
	 	
	 	this.SetOnMorphFunc = function (_f) {
	 		omFunc = _f;
		};
	 	
	 	this.GetMorphedObject = function(){
	 		return e;
		};
	},  // END Morph
	
	Mouse: function () {
		var ref = this;
		/*if (pu.Mouse.fi == undefined) 
			pu.Mouse.fi = true;  // first instance*/
		this.mx = 0;  // mouse x position
		this.my = 0;
		this.omx = 0;  // previous mouse x position
		this.omy = 0;
		this.dmx = 0;  // difference between current mouse x position and old mouse x position
		this.dmy = 0;
		this.fomm = null;  // function on mouse move
		this.fomd = null;  // function on mouse down
		this.fomu = null;  // function on mouse up
		this.mdevel = null;  // mouse down event element
		this.muevel = null;  // mouse up event element
		this.mmevel = null;  // mouse move event element
		
		this.SetMMousePos = function (_e) {
			var sc = pu.GScrollXY();
			ref.mx = _e.clientX + sc[0];
			ref.my = _e.clientY + sc[1];
			ref.dmx = ref.mx - ref.omx;
			ref.dmy = ref.my - ref.omy;
			ref.omx = ref.mx;
			ref.omy = ref.my;
		};

		this.OnMouseMove = function (_fomm) {
			this.fomm = _fomm;
		};
		
		this.OnMouseDown = function (_fomd) {
			this.fomd = _fomd;
		};
		
		this.OnMouseUp = function (_fomu) {
			this.fomu = _fomu;
		};
		
		this.MouseMove = function (_e) {
			if (pu.ie) {
				_e = window.event;
				ref.mmevel = _e.srcElement;
			} else
				ref.mmevel = _e.target;
			
			ref.SetMMousePos(_e);
			
			if (ref.fomm != null)
				ref.fomm(_e);
		};
		
		this.MouseDown = function (_e) {
			if (pu.ie) {
				_e = window.event;
				ref.mdevel = _e.srcElement;
			} else
				ref.mdevel = _e.target;

			ref.SetMMousePos(_e);
			
			if (ref.fomd != null)
				ref.fomd(_e, GetButton(_e));
		};
		
		this.MouseUp = function (_e) {
			if (pu.ie) {
				_e = window.event;
				ref.muevel = _e.srcElement;
			} else
				ref.muevel = _e.target;

			ref.SetMMousePos(_e);
		
			if (ref.fomu != null)
				ref.fomu(_e, GetButton(_e));
		};
		
		this.Close = function () {
			pu.RemoveEvent(document, "mousemove", this.MouseMove);
			pu.RemoveEvent(document, "mousedown", this.MouseDown);
			pu.RemoveEvent(document, "mouseup", this.MouseUp);
		};
		
		function GetButton(_e) {
			if (pu.ie)
				_e = window.event;
			
			var b = (_e.which) ? _e.which : _e.button, rb = 0;
			switch (b) {
				case 1: rb = pu.LEFT_BUTTON; break;
				case 2: (pu.ie) ? (rb = pu.RIGHT_BUTTON) : (rb = pu.MIDDLE_BUTTON); break;
				case 3: rb = pu.RIGHT_BUTTON; break;
				case 4: rb = pu.MIDDLE_BUTTON; break;
			}
			return rb;
		};
		
		//if (pu.Mouse.fi) {
			pu.AddEvent(document, "mousemove", this.MouseMove);
			pu.AddEvent(document, "mousedown", this.MouseDown);
			pu.AddEvent(document, "mouseup", this.MouseUp);
		//	pu.Mouse.fi = false;
		//}
	},  // END Mouse
	
	SendXmlHttpRequest: function(_func, _method, _url, _funcParams, _params, _headers) {
		var xmlhttp = (window.XMLHttpRequest ? new XMLHttpRequest : (window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : false));
		var headers = _headers;
	
		if (!xmlhttp)
			return false;
		
		if ((_method.toLowerCase() == "post") && (_headers == undefined) && (_params != undefined)) {
			headers = new Array();
			headers["Content-type"] = "application/x-www-form-urlencoded";
			headers["Content-length"] = _params.length;
			headers["Connection"] = "close";
	 	}
	
		xmlhttp.open(_method, _url);
	
		if (_func != null)
			xmlhttp.onreadystatechange = function() {
				_func(xmlhttp, _funcParams);
			};
	
		if (headers) {
			for (var key in headers)
				xmlhttp.setRequestHeader(key, headers[key]);
		}
	
		xmlhttp.send(_params);
		return true;
	},
	
	NewXMLDocument: function(rootTagName, namespaceURL) {
		if (!rootTagName)
			rootTagName = "";
		
		if (!namespaceURL)
			namespaceURL = "";
		
		if (document.implementation && document.implementation.createDocument)
			return document.implementation.createDocument(namespaceURL, rootTagName, null);
		else {
			var doc = new ActiveXObject("MSXML2.DOMDocument");
			if (rootTagName) {
				var prefix = "";
				var tagname = rootTagName;
				var p = rootTagName.indexOf(':');
				if (p != -1) {
					prefix = rootTagName.substring(0, p);
					tagname = rootTagName.substring(p+1);
				}
				if (namespaceURL) {
					if (!prefix)
						prefix = "a0";
				} else
					prefix = "";

				var text = "<" + (prefix?(prefix+":"):"") +  tagname +(namespaceURL ?(" xmlns:" + prefix + '="' + namespaceURL +'"') :"") + "/>";

				doc.loadXML(text);
			}
			
			return doc;
		}
	},
	
	XMLToString: function(_xml) {
		if (!SJEL.ie)
			return (new XMLSerializer()).serializeToString(_xml);
		else
			return _xml.xml;
	}
};  // public

return pu;
}();  // SJEL

SJEL.Init();