/**
 * Created by Aloyzas Rimeika on 2007-06-07.
 */

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 = [];

function extend(target) {
	var obj, a = 1, i;
	while (obj = arguments[a++])
		for (i in obj) target[i] = obj[i];
	return target;
}

// Copy object
function copy(object) {
	var fn = new Function;
	fn.prototype = object;
	return new fn;
};

// Object to Array
function array(a) {
	var r = [], i = 0, l = a.length;
	try {
		r = array.a.slice.call(a, 0);
		if (r[0] == undefined) throw "";
	} catch (e) {
		for (; i < l; i++) r[i] = a[i];
	}
	return r;
}
array.a = [];

function assignID(object) {
	// assign a unique id
	if (!object.__guid) object.__guid = assignID.$id++;
	return object.__guid;
}
assignID.$id = 1;

// bind object to method
function bind(method, context) {
	var bound = function() {
		return method.apply(context, arguments);
	};
	bound.cloneID = assignID(method);
	return bound;
}

// DOM select: dom(<element id:String>), dom(<element:HtmlNode>, <child node name:String>)
function dom(elem, name) {
	return !elem ? document : name
		? array(dom(elem).getElementsByTagName(name))
		: elem.constructor == String
			? dom().getElementById(elem)
			: elem;
}
extend(dom, {
	// DOM selection methods
	// select parent of element
	parent: function(elem, name, klass) {
		if (!name && !klass)
			return elem != document && elem.parentNode || null;

		if (name) name = name.toUpperCase();
		if (klass) klass = new RegExp("(^|\\s)" + klass + "(\\s|$)");

		while (elem
			&& !(name && elem.nodeName == name)
			&& !(klass && klass.test(elem.className)))
				elem = this.parent(elem);

		return elem;
	},

	// get last of nodes with name
	last: function(elem, name) {
		var elems = dom(name ? elem : null).getElementsByTagName(name || elem);
		return elems[elems.length - 1];
	},

	// get elements by className
	getByClass: function(klass, parent, tag) {
		var i = 0, parent = parent || document, tag = (tag || '*').toUpperCase(), result = [];
		if ((parent.getElementsByClassName) && (result = parent.getElementsByClassName(klass)) && tag != '*') { // FF 3, ... ?
			result = Array.filter(result, function(elem) { return elem.nodeName == tag });
		} else if (document.evaluate) { // FF <= 2, Opera, Safari
			var xpath = document.evaluate(".//" + tag + "[contains(concat(' ', @class, ' '), ' " + klass + " ')]", parent, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
			for (; (e = xpath.snapshotItem(i)); i++) result[result.length] = e;
		} else { // IE
			var regxp = new RegExp('(^|\\s)' + klass + '(\\s|$)');
			var elems = tag == '*' && parent.all || dom(parent, tag);
			for (; (e = elems[i]); ++i) if (regxp.test(e.className)) result[result.length] = e;
		}
		return result;
	},

	// DOM manipulation methods
	// create elements from html
	create: function(html) {
		var d = dom().createElement('div'), res;
		d.innerHTML = html;
		res = d.firstChild;
		d = null;
		return res;
	},

	remove: function(elem) {
		var p = this.parent(elem);
		if (p) p.removeChild(elem);
	},

	// insert before element
	before: function(elem, before) {
		before.parentNode.insertBefore(elem, before);
		return elem;
	},

	// insert before element
	after: function(elem, after) {
		after.parentNode.insertBefore(elem, after.nextSibling);
		return elem;
	},

	hasClass: function(elem, klass) {
		var r = new RegExp("(^|\\s)" + klass + "(\\s|$)");
		return r.test(elem.className);
	},

	addClass: function(elem, klass) {
		if (!this.hasClass(elem, klass))
			elem.className += (elem.className ? " " : "") + klass;
		return elem;
	},

	removeClass: function(elem, klass) {
		var r = new RegExp("(^|\\s)" + klass + "(\\s|$)");
		elem.className = elem.className.replace(r, "$2");
		return elem;
	},

	toggleClass: function(elem, klass) {
		dom[(dom.hasClass(elem, klass) ? 'remove' : 'add') +'Class'](elem, klass);
		return elem;
	},

	index: function(node) {
		var index = node.cellIndex, s = node;
		if (!index) while (node = node.previousSibling) if (node.nodeType == 1) index++;
		return index;
	},

	// event module
	event: {
		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 (elem.events && elem.events[type])
				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;
				};

			if (e.pageX == null && e.clientX != null) {
				var d = document.documentElement, b = document.body;
				e.pageX = e.clientX + (d && d.scrollLeft || b.scrollLeft || 0);
				e.pageY = e.clientY + (d && d.scrollTop || b.scrollTop || 0);
			}

			var handlers = this.events[e.type];
			var result = true;
			for (var i in handlers) {
				if (bind(handlers[i], 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);
		},

		// dom.event.hover(div, function(e){ ... mouse over element code ... }, function{ ... mouse out element code .... });
		hover: function(elem, over, out) {
			dom.event.add(elem, 'mouseover', function(e){
				if (!this.__hovered) {
					this.__hovered = true;
					return over.call(this, e);
				}
			});

			dom.event.add(elem, 'mouseout', function(e){
				var p = e.relatedTarget;
				while (p && p != document && p != this) p = p.parentNode;
				if (p != this) {
					this.__hovered = false;
					return out.call(this, e);
				}
			});
		}
	}
});

function form(elem) { return extend(dom(elem), form.methods); }
form.methods = {
	getValue: function(name) {
		var elem = this.getElement(name), result;
		for (var i = 0; i < (elem.length || (elem = [elem]).length); i++) {
			if (!elem[i].disabled && (!/ckeckbox|radio|select/.test(elem[i].type)
				|| (elem[i].checked || elem[i].selected))) {
				if (/\[\]$/.test(elem[i].name)) {
					if (!result || !result.push) result = [elem[i].value];
					else result.push(elem[i].value);
				} else result = elem[i].value;
			}
		}
		return result;
	},
	getElement: function(name, value) {
		var elem = this.elements[name],
			tmp = this.elements[name +'[]'];
		if (tmp) elem = array(elem || []).concat(tmp.length ? array(tmp) : [tmp]);

		if (value !== undefined) {
			for (var i = 0; i < (elem.length || (elem = [elem]).length); i++)
				if (elem[i].value == value) return elem[i];
			return null;
		}

		return elem;
	},
	// del shito nezinau ar labai naudinga...
	getElementsByType: function(name, type) {
		var elem = this.getElement(name), result = [];
		for (var i = 0; i < (elem.length || (elem = [elem]).length); i++)
			if (elem[i].type == type) result.push(elem[i]);
		return result;
	}
};

new function() {
	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;

	// Additional string methods
	extend(String.prototype, {
		stripTags: function(){
			return this
				.replace(/\s+/g, ' ')
				.replace(/ *<br[^\/>]*\/?> */g, '\n')
				.replace(/<[^>]+>/g, '');
		},

		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;
		}
	});

	var color = {
		reg: new RegExp('^\\s*(?:rgb\\s*\\(%1,%1,%1\\)|#%2%2%2)\\s*$'
			.format('\\s*([0-9]{1,3}|[0-9\\.]+\\%)\\s*', '([a-f0-9]|[a-f0-9]{2})'), 'i'),
		hex: function(s) { return parseInt('0x'+ (s.length > 1 ? s : s+s)); },
		num: function(s) { return parseInt(/\%/.test(s) ? parseFloat(s) * 255 / 100 : s); }
	};
	String.prototype.parseRGB = function(){
	  var m = color.reg.exec(this), h = color.hex, n = color.num;
	  return m && (m[1] && [n(m[1]), n(m[2]), n(m[3])] || m[4] && [h(m[4]), h(m[5]), h(m[6])]);
	};

	// Additional number methods
	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 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));
	}
};

