/**
 * Function.prototype.call and other IE 5.0 nonsense copy from base2.Legacy file or include one :)
 * http://base2.googlecode.com/svn/trunk/src/legacy.js
 */

function log() {
	if (window.console) {
		window.console.log.apply(window.console, arguments);
	} else {
		log.output.push(array(arguments).join(', '));
		clearTimeout(log.time);
		log.time = setTimeout(function() {
			var t = log.output.join('\n');
			log.output = [];
			alert(t);
		}, 100);
	};
	return arguments[0];
}
log.output = [];

/**
 * labai plachiai naudojamas praplesti objekto duomenims
 * target = extend(target, objectas, [ objectas, ... ]);
 * kinta tik target objektas
 * pvz: extend(Array.prototype, { method: function(){} });
 */
function extend(target) {
	for (var a = arguments, i, k = 0; ++k < a.length;) {
		for (i in a[k]) {
			target[i] = a[k][i];
		};
	};
	return target;
}

/**
 * greitas objekto kopijavimas
 * newObjectCopy = copy(object);
 * pvz:
extend(function classConstructor(settings){
	this.settings = extend(copy(this.settings), settings);
}, {prototype:{
	settings: { default: 0 }
}});
 */
function copy(object) {
	var fn = new Function;
	fn.prototype = object;
	return new fn;
};

/**
 * "masyviniu" objectu konvertavimas y masyva arba masyvo kopijavimas
 * dazhnai naudingas reikalas ir tikrai dazhnai naudojamas
 */
function array(a) {
	var r = [], i = 0, l = a.length;
	try {
		r = array.a.slice.call(a, 0);
		// safari kazhkodel nenukopijuoja kaikuriu objektu duomenu
		if (r[0] == undefined) {
			throw "";
		};
	} catch (e) {
		for (; i < l; i++) {
			r[i] = a[i];
		};
	};
	return r;
}
array.a = [];

/**
 * unikalaus id objektui priskirimo ir nuskaitymo metodas
 * galima butu shiektiek patobulinti norit naudoti crosswindow
 */
function assignID(object) {
	// assign a unique id
	if (!object.__guid) {
		object.__guid = assignID.$id++;
	};
	return object.__guid;
}
assignID.$id = 1;

/**
 * priskiria funkcijai kokionors objekto skoupa
 * dazhnai naudojamas eventu priskirimui
 * pvz:
extend(window.classConstructor = function(settings){
	document.onclick = bind(this.documentClick, this);
}, {prototype:{
	state: 0,
	documentClick: function(){
		alert("document clicked then state is "+ this.state);
	}
}});
 */
function bind(method, context) {
	var bound = function() {
		return method.apply(context, arguments);
	};
	bound.__cloneID = assignID(method);
	return bound;
}

/**
 * ishrenka dom elementus
 * dom() grazhina document, dom(element) grazhina element, dom("string") grazhina element.id == "string", dom("string" || element, "string") grazhina [ elment, element, ... ]
 * pvz:
dom(dom(), "html");
 */
function dom(elem, name) {
	return !elem ? document : name
		? array(dom(elem).getElementsByTagName(name))
		: elem.constructor == String
			? dom().getElementById(elem)
			: elem;
}
extend(dom, {
	/**
	 * suranda elemento teva
	 * pvz:
	var table = dom.parent(td, null, "table");
	 */
	parent: function(elem, klass, name) {
		klass = klass && new RegExp("(^|\\s)" + klass + "(\\s|$)");
		name = name && name.toUpperCase();
		while ((elem = elem.parentNode) && (klass && !klass.test(elem.className) || name && name != elem.nodeName));
		return elem;
	},

	/**
	 * suranda elemento vyresnijy broly
	 * reiks prideti klass
	 */
	prev: function(elem, klass, name) {
		klass = klass && new RegExp("(^|\\s)" + klass + "(\\s|$)");
		name = name && name.toUpperCase();
		while ((elem = elem.previousSibling) && (elem.nodeType != 1 || klass && !klass.test(elem.className) || name && name != elem.nodeName));
		return elem;
	},

	/**
	 * suranda elemento jaunesnijy broly
	 * reiks prideti klass
	 */
	next: function(elem, klass, name) {
		klass = klass && new RegExp("(^|\\s)" + klass + "(\\s|$)");
		name = name && name.toUpperCase();
		while ((elem = elem.nextSibling) && (elem.nodeType != 1 || klass && !klass.test(elem.className) || name && name != elem.nodeName));
		return elem;
	},

	last: function(elem, name) {
		var elems = dom(name ? elem : null).getElementsByTagName(name || elem);
		return elems[elems.length - 1];
	},

	/**
	 * suranda elementus su tam tikra klase
	 */
	getByClass:
	(dom().getElementsByClassName // FF 3, ... ?
	? function(klass, parent, tag) {
		var res = this(parent).getElementsByClassName(klass);
		return tag && (tag = tag.toUpperCase())
			? Array.filter(res, function(elem) { return elem.nodeName == tag; })
			: array(res);
	}
	: dom().evaluate // FF <= 2, Opera, Safari
	? function(klass, parent, tag) {
		var xpath = this().evaluate("descendant::"+ (tag || '*') +"[contains(concat(' ',@class,' '),'"+ klass +"')]", this(parent), null, 7, null);
		for (var i = 0, res = []; (e = xpath.snapshotItem(i)); i++) {
			res[res.length] = e;
		};
		return res;
	}
	: function(klass, parent, tag) { // IE
		var regxp = new RegExp('(^|\\s)' + klass + '(\\s|$)'), elems = this(this(parent), tag || '*');
		for (var i = 0, res = [], e; (e = elems[i]); i++) {
			if (regxp.test(e.className)) {
				res[res.length] = e;
			};
		};
		e = elems = null;
		return res;
	}),

	/**
	 * greitasis elementu kurimo metodas innerHTML :)
	sukuriamas tik vienas elementas
	neveikia su <caption>, <thead>, <tbody>, <tr>, <th>, <td> kadangi jie reikalauja <table> lemento
	 */
	create: function(html) {
		var d = this().createElement('div'), res;
		d.innerHTML = html;
		res = d.firstChild; d = null;
		return this.remove(res);
	},

	remove: function(elem) {
		var p = this.parent(elem);
		return p && p.removeChild(elem);
	},

	before: function(elem, before) {
		var p = this.parent(before);
		return p && p.insertBefore(elem, before);
	},

	after: function(elem, after) {
		var p = this.parent(after);
		return p && p.insertBefore(elem, after.nextSibling);
	},

	hasClass: function(elem, klass) {
		return new RegExp("(^|\\s)" + klass + "(\\s|$)").test(elem.className);
	},

	addClass: function(elem, klass) {
		if (!this.hasClass(elem, klass)) {
			elem.className += (elem.className ? " " : "") + klass;
		};
		return elem;
	},

	removeClass: function(elem, klass) {
		elem.className = elem.className.replace(new RegExp("(^|\\s)" + klass + "(\\s|$)"), "$2");
		return elem;
	},

	toggleClass: function(elem, klass) {
		return this[(this.hasClass(elem, klass) ? 'remove' : 'add') + 'Class'](elem, klass);
	}
});

/**
 * eventu modulis
 */

/**
 * priskiria eventus objectams
 * panaudojimo budai:
 * events(object || "id", type, handler),
 * events([object || "id", object || "id", ...], type, handler),
 * events(object || "id", { "type": handler, "type": handler, ... }),
 * events([object || "id", object || "id", ...], { "type": handler, "type": handler, ... })
 */
// shio metodo gali ir nebuti, bo jis mano sugalvotas grichiau testukams rashyti... :)
function events(elem, type, handl) {
	if (elem instanceof Array) {
		for (var i=0; i < elem.length; i++) {
			events(elem[i], type, handl);
		};
	} else if (!handl) {
		for (var i in type) {
			events(elem, i, type[i]);
		};
	} else {
		events.add(dom(elem), type, handl);
	};
}
extend(events, {
	add: function(elem, type, handl) {
		if (!elem.__events) {
			elem.__events = {};
		};

		var handlers = elem.__events[type];

		if (!handlers) {
			handlers = elem.__events[type] = {};
			if (elem["on"+ type]) {
				var on = elem["on"+ type];
				elem["on"+ type] = null;
				this.add(elem, type, on);
			};
		};

		handlers[assignID(handl)] = handl;
		elem["on"+ type] = this.handle;
	},

	remove: function(elem, type, handl) {
		if (!type) {
			for (type in elem.__events) {
				this.remove(elem, type);
			};
		};

		if (elem.__events && elem.__events[type]) {
			if (!handl) {
				for (handl in elem.__events[type]) {
					delete elem.__events[type][handl];
				};
			} else {
				delete elem.__events[type][handl.__guid];
			};
		};
	},

	handle: function(e) {
		e = e || window.event;

		if (!e.target && e.srcElement) {
			e.target = e.srcElement;
		};

		if (!e.relatedTarget && e.toElement) {
			e.relatedTarget = e.toElement == e.target ? e.fromElement : e.toElement;
		};

		if (!e.preventDefault) {
			e.preventDefault = function() {
				this.returnValue = false;
			};
		};

		if (!e.stopPropagation) {
			e.stopPropagation = function() {
				this.cancelBubble = true;
			};
		};

		var handlers = this.__events[e.type];
		var result = true;
		for (var i in handlers) {
			if (handlers[i].call(this, e) === false) {
				e.preventDefault();
				e.stopPropagation();
				result = false;
			};
		};

		if (e.srcElement) {
			e = e.target = e.relatedTarget = e.preventDefault = e.stopPropagation = null;
		};
		return result;
	},

	dispatch: function(e) {
		var elem = e.target, type = e.type;
		while (elem) {
			if (elem['on'+ type]) {
				elem['on'+ type](e);
			};
			elem = !e.cancelBubble && dom.parent(elem);
		};
		return !(e.returnValue === false);
	},

	/**
	 * grazhina surinktus ish evento duomenis apie mouso koordinates
	 * koordinaciu nuo target elmento skaichiavimas perdaug skiriasi visuose browseriuose kad galima butu jy lengvai implementuoti
	 * todel paliktos kordinates nuo relative elemento
	 */
	mouse: function(e) {
		/**
		 * opera e.x, e.y atiduoda gerai tik tada jei kursorius yra ant teksto,
		 * kitu atveju gaunasi kazhkox bullshitas
		 * idealus variantas operai tokiu atveju: <div style="position: relative; padding: 0; border: 0"><div onclick="...">...</div></div>
		 */
		var o = {
			relativeX: e.layerX != undefined ? e.layerX : e.x != undefined ? e.x : 0,
			relativeY: e.layerY != undefined ? e.layerY : e.y != undefined ? e.y : 0
		};

		if (e.pageX == null && e.clientX != null) {
			var d = dom().documentElement, b = dom().body;
			o.pageX = e.clientX + (d && d.scrollLeft || b.scrollLeft || 0);
			o.pageY = e.clientY + (d && d.scrollTop || b.scrollTop || 0);
		} else {
			o.pageX = e.pageX;
			o.pageY = e.pageY;
		};

		return o;
	},

	// events.hover(div, function(e){ ... mouse over element code ... }, function{ ... mouse out element code .... });
	hover: function(elem, over, out) {
		this.add(elem, 'mouseover', function(e){
			if (!this.__hovered) {
				this.__hovered = true;
				return over.call(this, e);
			};
		});

		this.add(elem, 'mouseout', function(e){
			var p = e.relatedTarget;
			while (p && p != this) {
				p = dom.parent(p);
			};
			if (p != this) {
				this.__hovered = false;
				return out.call(this, e);
			};
		});
	}
});

new function(){
	var drag;

	extend(drag = events.dragdrop = function(e) {
		if (e.target) {
			drag.mousedown(e);
		} else {
			events.add(e, "mousedown", drag.mousedown);
		};
		return drag.draggable;
	}, {
		draggable: {},
		mousedown: function(e) {
			var m = events.mouse(e);
			extend(drag.draggable, {
				target: e.target,
				relatedTarget: e.target,
				relativeX: m.relativeX,
				relativeY: m.relativeY
			});
			events.add(dom(), "mousemove",	drag.mousemove);
			events.add(dom(), "mouseup",	drag.cancel);
		},
		mousemove: function(e){
			events.remove(dom(), "mousemove",	drag.mousemove);
			events.remove(dom(), "mouseup",		drag.cancel);

			if (events.dispatch(extend(events.mouse(e), drag.draggable, {
				type: "mousedrag"
			}))) {
				events.add(dom(), "mouseup", drag.mouseup);
				e.preventDefault();
			} else {
				drag.cancel();
			};
		},
		mouseup: function(e){
			events.dispatch(extend(events.mouse(e), drag.draggable, {
				type: "mousedrop",
				target: e.target
			}));
			drag.cancel();
		},
		cancel: function(){
			events.remove(dom(), "mousemove",	drag.mousemove);
			events.remove(dom(), "mouseup",		drag.cancel);
			events.remove(dom(), "mouseup",		drag.mouseup);
			for (var i in drag.draggable) {
				delete drag.draggable[i];
			};
		}
	});

/**
 * dragdrop example
 *
var draggableObject = events.dragdrop(dom());
events.add(dom().body, "mousedrag", function(e){
	log("start drag bomb "+ e.target);
});
events.add(dom().body, "mousedrop", function(e){
	log("drop bomb on "+ e.target +" from base "+ e.relatedTarget);
});
 */

	// Additional string methods
	extend(String.prototype, {
		stripTags: function(){
			return this.replace(/\s+|\&nbsp;/g, ' ').replace(/ *<br[^\/>]*\/?> */ig, '\n').replace(/<!--[\s\S]*?-->|<[^>]+>/g, '').trim();
		},

		rescape: function() {
			return this.replace(re, "\\$1");
		},

		trim: function() {
			return this.replace(/^\s+|\s+$/g, '');
		},

		format: function() {
			// replace %n with arguments[n]
			// e.g. format("%1 %2%3 %2a %1%3", "she", "se", "lls");
			// ==> "she sells sea shells"
			// only %1 - %9 supported
			var args = arguments;
			return this.replace(FORMAT, function(match, index) { return index <= args.length ? args[index - 1] : match; });
		},

		toNumber: function(){
			return parseFloat(this.replace(/\s+/g, '').replace(/[\,\.](?=.*[\,\.])/g, '').replace(/[\,\.]/, '.').replace(/^(?=-?)0*(?=\d)\.?/, ''), 10);
		},

		// format: ymd, dmy, mdy
		toDate: function(format) {
			format = format || 'ymd';
			var s = this.replace(/\D+/g, ' '),
				a = format.split(''),
				m = s.match(dateFormat[format]),
				d = {}, i = 0;

			for (; m && s && i < a.length; i++) {
				d[a[i]] = m[i + 1] || m[i + 4];
			};

			d = Date.parse(d.y +'/'+ d.m +'/'+ d.d);

			return isNaN(d) ? null : new Date(d);
		},

		htmlencode: function() {
			var div = dom().createElement('div');
			div.appendChild(dom().createTextNode(this));
			return div.innerHTML;
		}

	});

	extend(Number.prototype, {
		format: function(fix, dec, tou) {
			var parts = this.toFixed(arguments.length ? fix : 2).split('.');
			if (tou) {
				parts[0] = parts[0].replace(/\B(?=(...)*$)/g, tou);
			};
			return parts.join(dec || '.');
		}
	});

	var re = /([\/()[\]{}|*+-.,^$?\\])/g;
	var FORMAT = /%([1-9])/g;
	var dateFormat = {
		dmy: /(\d{1,2}) (\d{1,2}) (\d{4})|(\d{2})(\d{2})(\d{4})/,
		ymd: /(\d{4}) (\d{1,2}) (\d{1,2})|(\d{4})(\d{2})(\d{2})/
	};
	dateFormat.mdy = dateFormat.dmy;

};


new function(){
	// switches;
	var date = {
		a:'this.getHours() > 11 ? "pm" : "am"',
		A:'this.a().toUpperCase()',
		// B:'var beat = (Math.floor(((this.G() + 1) * 3600 + this.getMinutes() * 60 + this.getSeconds() - this.Z()) / 86.4) + 1000) % 1000 +""; return "000".substring(beat.length) + beat',
		// c:'this.format("Y-m-dTh:i:sP")',
		d:'var j = ""+ this.j(); return j.length == 1 ? "0"+ j : j',
		D:'this.daysShort[this.w()]',
		F:'this.monthsLong[this.n() - 1]',
		g:'this.G() % 12 || 12',
		G:'this.getHours()',
		h:'var g = this.g() +""; return g.length == 1 ? "0"+ g : g',
		H:'var G = this.G() +""; return G.length == 1 ? "0"+ G : G',
		i:'var m = this.getMinutes() +""; return m.length == 1 ? "0"+ m : m',
		// I:'var noDST = new Date(this.Y(), 0); return noDST.getTimezoneOffset() == this.getTimezoneOffset() ? 0 : 1',
		j:'this.getDate()',
		l:'this.daysLong[this.w()]',
		L:'new Date(this.Y(), 1, 29).j() == 29 ? 1 : 0',
		m:'var n = this.n() +""; return n.length == 1 ? "0"+ n : n',
		M:'this.monthsShort[this.n() - 1]',
		n:'this.getMonth() + 1',
		N:'7 + (this.w() - 7) % 7',
		// O:'var o = this.getTimezoneOffset(), os = Math.abs(o), h = Math.floor(os / 60) +"", m = os % 60 +"", r = (h.length == 1 ? "0"+ h : h) + (m.length == 1 ? "0"+ m : m); return (o < 0 ? "+" : "-") + r',
		// P:'var O = this.O(); return O.substr(0, 3) +":"+ O.substr(3, 2)',
		// r:'this.format("D, d M Y H:i:s O")',
		s:'var s = this.getSeconds() +""; return s.length == 1 ? "0"+ s : s',
		S:'[0, "st", "nd", "rd"][((this.j() + 20) % 30 - 10) % 10] || "th"',
		t:'[0, 31, this.L() ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][this.n()]',
		// U:'Math.round(this.getTime()/1000)',
		w:'this.getDay()',
		W:'Math.floor((this.z() + 3 + (new Date(this.Y(), 0).w() - 11) % 7) / 7) + 1',
		y:'(""+ this.Y()).substring(2)',        
		Y:'this.getFullYear()',
		z:'Math.floor((this.getTime() - new Date(this.Y(), 0).getTime()) / 86400000)'//,
		// Z:'- this.getTimezoneOffset() * 60'
	};

	var names = "";
	for (var i in date) {
		names += i;
		date[i] = new Function((!eval('/return/').test(date[i]) ? 'return ' : '') + date[i]);
	};

	var reg = new RegExp("(\\\\?)(["+ names +"])", "g");
	var fn = function(m, s, c){ return s ? c : '", this.'+ c +'(), "'; };
	var cache = {};

	extend(Date.prototype, date, {
		daysLong:		["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
		daysShort:		["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
		monthsShort:	["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
		monthsLong:		["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
		format: function(pattern) {
			if (!cache[pattern]) {
				cache[pattern] = new Function('return ["'+ pattern.replace(reg, fn) +'"].join("")');
			};
			return cache[pattern].call(this);
		},
		tomorrow: function() {
			this.setDate(this.getDate() + 1);
			return this;
		},
		yesterday: function() {
			this.setDate(this.getDate() - 1);
			return this;
		},
		scrollByMonths: function(count) {
			count = this.getMonth() + count;
			this.setFullYear(this.getFullYear() + Math.floor(count / 12));
			this.setMonth((12 + count % 12) % 12);
			return this;
		},
		scrollByDays: function(count) {
		    var dE=new Date(this.valueOf()+count*86400000);
		    this.setFullYear(dE.getFullYear());
		    this.setMonth(dE.getMonth());
		    this.setDate(dE.getDate());
            
			return this;
		}
	});

	var frm = {
		dmy: /(\d{1,2}) (\d{1,2}) (\d{4})|(\d{2})(\d{2})(\d{4})/,
		ymd: /(\d{4}) (\d{1,2}) (\d{1,2})|(\d{4})(\d{2})(\d{2})/
	};
	frm.mdy = frm.dmy;

};

var browser = {
	init: function () {
		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
		this.version = this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || "an unknown version";
		this.OS = this.searchString(this.dataOS) || "an unknown OS";
	},
	searchString: function (data) {
		for (var i=0;i<data.length;i++)	{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1)  {
					return data[i].identity;
				};
			} else if (dataProp) {
				return data[i].identity;
			};
		};
	},
	searchVersion: function (dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) {
			return;
		};
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	},
	dataBrowser: [
		{ String: navigator.userAgent,
			subString: "OmniWeb",
			versionSearch: "OmniWeb/",
			identity: "OmniWeb"
		},
		{
			string: navigator.vendor,
			subString: "Apple",
			versionSearch: "Version",
			identity: "Safari"
		},
		{
			prop: window.opera,
			identity: "Opera"
		},
		{
			string: navigator.vendor,
			subString: "iCab",
			identity: "iCab"
		},
		{
			string: navigator.vendor,
			subString: "KDE",
			identity: "Konqueror"
		},
		{
			string: navigator.userAgent,
			subString: "Firefox",
			identity: "Firefox"
		},
		{
			string: navigator.vendor,
			subString: "Camino",
			identity: "Camino"
		},
		{		// for newer Netscapes (6+)
			string: navigator.userAgent,
			subString: "Netscape",
			identity: "Netscape"
		},
		{
			string: navigator.userAgent,
			subString: "MSIE",
			identity: "Explorer",
			versionSearch: "MSIE"
		},
		{
			string: navigator.userAgent,
			subString: "Gecko",
			identity: "Mozilla",
			versionSearch: "rv"
		},
		{ 		// for older Netscapes (4-)
			string: navigator.userAgent,
			subString: "Mozilla",
			identity: "Netscape",
			versionSearch: "Mozilla"
		}
	],
	dataOS : [
		{
			string: navigator.platform,
			subString: "Win",
			identity: "Windows"
		},
		{
			string: navigator.platform,
			subString: "Mac",
			identity: "Mac"
		},
		{
			string: navigator.platform,
			subString: "Linux",
			identity: "Linux"
		}
	]

};
browser.init();

var cookie = {
	set: function(name, value, options) {
		var a = [encodeURIComponent(name) +'='+ encodeURIComponent(value)];

		for (name in options) {
			value = options[name];
			a.push(name + '=' + ( name == 'expires' ? new Date((new Date).getTime() + value * 86400000).toUTCString() : name == 'secure' ? name : value ));
		};
		document.cookie = a.join('; ');
	},
	get: function(name) {
		var res = String(document.cookie).match(new RegExp('\\b'+ encodeURIComponent(name).rescape() +'=([^;]*)'));
		return res && decodeURIComponent(res[1]) || null;
	},
	rem: function(name, options) {
		this.set(name, '', extend({ expires: -1 }, options));
	}
};
