/**
 * Extend JS capabilities
 * ======================
 *
 * @version 1.0
 */

if (typeof Function.prototype.apply == 'undefined')
{
	Function.prototype.apply = function(target, args) {
		if (typeof(target) == undefined) return false;
		if (typeof(args) == undefined) args = [];

		target.__apply_func__ = this;
		var ret = eval('target.__apply_func__(' + args.join(', ')+ ')');
		delete target.__apply_func__;
		return ret;
	}
}
/**
 * Simple Event Handler
 * ====================
 *
 * @version 1.0
 */

var wm_Event = {

	ev_owners : [],

	add : function(el, ev_type, func) {
		if (typeof el.wm_events == 'undefined')
		{
			this.ev_owners.push(el);
			el.wm_events = [];
		}

		if (typeof el[ev_type] == 'undefined' || ! el[ev_type])
		{
			el.wm_events[ev_type] = [];
			el[ev_type] = function(event) {
				var ev_type = 'on' + (window.event ? window.event.type : event.type);
				for (var i = 0; i < this.wm_events[ev_type].length; ++ i)
				{
					var ev = this.wm_events[ev_type][i];
					ev.func.apply(this, ev.args);
				}
			};
		}

		var args = [];
		for (var i = 3; i < arguments.length; ++ i)
			args.push(arguments[i]);

		el.wm_events[ev_type].push({func : func, args : args});
	},

	remove : function(el, ev_type, func) {
		if (typeof el.wm_events == 'undefined'
		    || typeof el.wm_events[ev_type] == 'undefined') return false;

		if (typeof func == 'undefined')
		{
			el.wm_events[ev_type] = [];
		}
		else if (typeof func == 'function')
		{
			var ev = el.wm_events[ev_type];
			for (var l = false, i = 0; ! l && i < ev.length; ++ i)
			{
				l = ev[i].func == func;
			}
			if (l) ev.splice(-- i, 1);
		}
		else if (typeof func == 'number' && typeof el.wm_events[ev_type][func] == 'object')
		{
			el.wm_events[ev_type].splice(func, 1);
		}
		else return false;

		if (el.wm_events[ev_type].length == 0) el[ev_type] = null;

		var ev = el.wm_events;
		var l = true;
		for (var ev_type in ev)
		{
			if (ev[ev_type] != null) l = false;
		}

		if (l)
		{
			for (var l = false, i = 0; ! l && i < this.ev_owners.length; ++ i)
			{
				l = el == this.ev_owners[i];
			}
			if (l) this.ev_owners.splice(-- i, 1);
		}

		return l;
	},

	free : function() {
		while (el = this.ev_owners.shift())
		{
			var ev = el.wm_events;
			for (var ev_type in el.wm_events)
			{
				el.wm_events[ev_type] = [];
				el[ev_type] = null;
			}
		}
	},

	dump : function() {
		var dump = [];
		for (var i = 0; i < this.ev_owners.length; ++ i)
		{
			var el = this.ev_owners[i];
			var s = (el == window) ? 'Window:' : el.id + ' (' + el.tagName +'): ';
			for (var ev_type in el.wm_events)
			{
				s += ' ' + ev_type + '=' + el.wm_events[ev_type].length;
			}
			dump.push(s);
		}
		return dump.join('\n');
	}
}

/**
 * DOM functions
 * =============
 *
 * @version 1.0
 */

var wm_Dom = {
	ELEMENT_NODE : 1,
	ATTRIBUTE_NODE : 2,
	TEXT_NODE : 3,
	DOCUMENT_NODE : 9,

	get : function() {
		var arg_len = arguments.length;
		if (arg_len == 0) return null;

		var elements = [];
		for (i = 0; i < arg_len; ++ i)
		{
			el = arguments[i];
			if (typeof el == 'string') elements.push(
				document.getElementById(el) || null);
				else if (typeof el == 'object') elements.push(el);
					else elements.push(null);
		}
		return (elements.length == 1) ? elements.shift() : elements;
	},

	next : function(el) {
		el = (el) ? el : null;
		while(el && this.get_type(el) != this.ELEMENT_NODE)
			el = el.nextSibling;
		return el;
	},

	create : function() {
		var el = null, arg_len = arguments.length;
		if (arg_len == 1)
		{
			el = document.createTextNode(arguments[0]);
		}
		else if (arg_len == 2)
		{
			el = document.createElement(arguments[0]);
			for (prop in arguments[1])
				el.setAttribute(prop, arguments[1][prop]);
		}
		return el;
	},

	append : function() {
		var arg_len = arguments.length;
		if (arg_len < 2) return null;

		var el = this.get(arguments[0]);
		for (var i = 1; i < arg_len; ++ i)
		{
			el.appendChild(arguments[i]);
		}
		return el;
	},

	append_before : function() {
		var arg_len = arguments.length;
		if (arg_len < 2) return null;

		var el = this.get(arguments[0]);
		for (var i = 1; i < arg_len; ++ i)
		{
			el.parentNode.insertBefore(arguments[i], el);
		}
		return el;
	},

	append_after : function() {
		var arg_len = arguments.length;
		if (arg_len < 2) return null;

		var func, args = [];
		var el = this.get(arguments[0]);
		if (el.nextSibling)
		{
			func = this.append_before;
			args.push(el.nextSibling);
		}
		else
		{
			func = this.append;
			args.push(el.parentNode);
		}

		for (var i = 1; i < arg_len; ++ i) args.push(arguments[i]);
		func.apply(this, args);
	},

	remove_children : function(el) {
		el = this.get(el);
		while(el.firstChild)
		{
			el.removeChild(el.firstChild);
		}
	},

	get_type : function(el) {
		el = this.get(el);
		return typeof el.nodeType == 'undefined' ?
			el.getAttribute('nodeType') : el.nodeType;
	},

	get_position : function(el) {
		el = this.get(el);
		var pos = new Point(el.offsetLeft, el.offsetTop);
		while (el.offsetParent)
		{
			el = el.offsetParent;
			pos.x += el.offsetLeft;
			pos.y += el.offsetTop;
		}
		return pos;
	},

	clean : function(el) {
		el = this.get(el);
		for (var i = 0; i < el.childNodes.length; i++) {
			var child = el.childNodes[i];
			if (child.nodeType == this.TEXT_NODE
			    && !/\S/.test(child.nodeValue)) el.removeChild(child);
			    else if (child.nodeType == this.ELEMENT_NODE) this.clean(el);
		}
	}
};
/**
 * Class name
 * ==========
 *
 * @version 1.0
 */

var wm_ClassName = {

	add : function(el, class_name) {
		if (! el.className) el.className = class_name;
		else if (! this.has(el, class_name)) el.className += ' ' + class_name;
	},

	swap : function(el, class_name_from, class_name_to) {
		if (this.has(el, class_name_from))
		{
			el.className = el.className.replace(class_name_from, class_name_to);
		}
		else
		{
			this.add(el, class_name_to);
		}
	},

	remove : function(el, class_name) {
		if (this.has(el, class_name))
		{
			el.className = el.className.replace(eval('/ *' + class_name + '/gi'), '');
		}
	},

	has : function(el, class_name) {
		return el.className.match(eval('/ *' + class_name + ' */gi'));
	}
};
/**
 * Ajax Class
 * ==========
 *
 * @version 1.0
 */

var wm_Ajax = {
	request : function(el, properties) {
		var async = properties.async || true;
		var content = properties.content || null;
		var headers = properties.headers || [];
		var method = properties.method || 'GET';
		var oncomplete = properties.oncomplete || function(xmlhttp) {};
		var onfailure = properties.onfailure || function(status) {};
		var onreadystatechange = properties.onreadystatechange || function(readyState) {};
		var url = properties.url || '';

		var xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest()
			: (window.ActiveXObject ? new ActiveXObject("Msxml2.XMLHTTP")
				|| new ActiveXObject("Microsoft.XMLHTTP") : null);
		if (! xmlhttp) return false;

		xmlhttp.open(method, url, async);

		if (xmlhttp.overrideMimeType)
		{
			headers.push({
				name : 'Connection',
				content : 'close'
				} );
		}
		if (method == 'POST')
		{
			headers.push( {
				name : 'Content-type',
				content : 'application/x-www-form-urlencoded'
			} );
		}
		for (var i = 0; i < headers.length; ++ i)
		{
			xmlhttp.setRequestHeader(headers[i].name, headers[i].content);
		}

		xmlhttp.onreadystatechange = function() {
			onreadystatechange.apply(el, [xmlhttp.readyState]);
			if (xmlhttp.readyState == 4)
			{
				if (xmlhttp.status == 200)
				{
					oncomplete.apply(el, [xmlhttp]);
				}
				else
				{
					onfailure.apply(el, [xmlhttp.status]);
				}
			}
		};
		xmlhttp.send(content);
		return true;
	}
}
/**
 * Miscellaneous capabilities
 * ==========================
 *
 * @version 1.0
 */

Point = function(x, y) {
	this.x = x;
	this.y = y;

	this.dump = function() {
		return 'x = ' + this.x + ', y = ' + this.y;
	}
}

function extend(dst, src)
{
	for (var prop in src) dst[prop] = src[prop];
	return dst;
}/**
 * Shortcuts for api objects
 * =========================
 *
 * @version 1.0
 */

$A = extend({}, wm_Ajax);
$C = extend({}, wm_ClassName);
$D = extend({}, wm_Dom);
$E = extend({}, wm_Event);
