/**
 * Перенацеливает метод на другой объект
 *
 * @param object Object
 */
Function.prototype.bind = function(Object) {
	var method = this;
	return function() { return method.apply(Object, arguments); }
}

/**
 * Возвращает позицию элемента в массиве или false в случае отсутствия элемента в массиве
 *
 * @param array array массив
 * @param string value значение элемента
 * @return int
 */
function alzGetPosInArray(array, value) {
	for (var i=0; i<array.length; i++) if (array[i]==value) return i;
	return false;
}

/**
 * Преобразует данные формы в массив
 *
 * @param HtmlElement formId
 */
function alzDataFormToJs(formId) {
	var result = new Array();
	for (var i=0; i<formId.elements.length; i++) {
		with (formId.elements[i]) {
			if (name) {
				if (type == 'radio') {
					if (checked) result[name] = value;
				} else {
					var pos = name.indexOf('[');
					if (pos != -1) {
						var _name = name.substr(0, pos);
						if (typeof(result[_name]) == 'undefined') result[_name] = new Array();
						result[_name][name.substr(pos+1, name.indexOf(']')-pos-1)] = value;
					} else {
						result[name] = value;
					}
				}
			}
		}
	}
	return result;
}

/**
 * Возвращает ширину видимой части документа
 *
 * @return int|undefined
 */
function alzGetClientWidth() {
	return self.innerWidth ? self.innerWidth
			: ((document.documentElement && document.documentElement.clientWidth) ? document.documentElement.clientWidth
				: (document.body ? document.body.clientWidth : undefined));
}

/**
 * Возвращает высоту видимой части документа
 *
 * @return int|undefined
 */
function alzGetClientHeight() {
	return self.innerHeight ? self.innerHeight
			: (document.documentElement && document.documentElement.clientHeight ? document.documentElement.clientHeight
				:(document.body ? document.body.clientHeight : undefined));
}

/**
 * Возвращает ширину элемента
 *
 * @param HTMLElement element html-элемент
 * @return int|undefined
 */
function alzGetElementWidth(element) {
	if (element.style)
		with (element.style)
			if (typeof(width)!='undefined' && null!=width.match(/^[0-9]+px$/i)) return parseInt(width, 10);
	return element.offsetWidth;
}

/**
 * Возвращает высоту элемента
 *
 * @param HTMLElement element html-элемент
 * @return int|undefined
 */
function alzGetElementHeight(element) {
	if (element.style)
		with (element.style)
			if (typeof(height)!='undefined' && null!=height.match(/^[0-9]+px$/i)) return parseInt(height, 10);
	return element.offsetHeight;
}


/**
 * Объект предоставляющий интерфейс для взаимодействия с событием объекта
 * Использование:
 * new alzEventer(document.getElementById('...'), 'mouseover', function(event){ return true; }).add();
 *
 * @param HTMLElement Object
 * @param string onEvent наименование события (без приставки 'on')
 * @param functon userHandler обработчик события
 */
function alzEventer(element, onEvent, userHandler) {
	this.element = element;
	this.onEvent = onEvent;
	this.userHandler = userHandler;
	this.eventHandler = this._handler.bind(this);
}

/**
 * Устанавливает обработчик события объекта
 *
 *  @exception
 */
alzEventer.prototype.add = function () {
	if (typeof(this.element.addEventListener) != 'undefined') this.element.addEventListener(this.onEvent, this.eventHandler, false);
	else if (typeof(this.element.attachEvent) != 'undefined') this.element.attachEvent('on'+this.onEvent, this.eventHandler);
	else throw "Incompatible browser";
}

/**
 * Удаляет обработчик события объекта
 *
 *  @exception
 */
alzEventer.prototype.remove = function () {
	if (typeof(this.element.removeEventListener) != 'undefined') this.element.removeEventListener(this.onEvent, this.eventHandler, false);
	else if (typeof(this.element.detachEvent) != 'undefined') this.element.detachEvent('on'+this.onEvent, this.eventHandler);
	else throw "Incompatible browser";
}

/**
 * Обертка к пользовательскому обработчику события
 *
 * @private
 * @exception
 * @param Event event
 */
alzEventer.prototype._handler = function (event) {
	if (typeof(window.event) != 'undefined') event = window.event;
	if (this.onEvent == 'DOMMouseScroll' || this.onEvent == 'mousewheel') {
		if (this.userHandler(event, event.wheelDelta ? (window.opera?-1:1) * event.wheelDelta / 120 : (event.detail ? -event.detail / 3 : 0)))
			return true;
	} else {
		if (this.userHandler(event))
			return true;
	}
	if (typeof(event.preventDefault) != 'undefined') event.preventDefault();
	return false;
}

/** Возвращает объект элемента для которого произошло указанное событие
 *  @param Event event
 *  @return HTMLElement Object */
function alzGetEventElement(event) {
	return typeof(event.srcElement) != 'undefined' ? event.srcElement : event.target;
}

function alzGetEventTopElement(event, tagName) {
	var el = typeof(event.srcElement) != 'undefined' ? event.srcElement : event.target;
	while (true) {
		if (tagName != el.tagName) {
			if (typeof(el.parentNode) == 'undefined') return undefined;
			el = el.parentNode;
		} else
			return el;
	}
}

/** Возвращает элемент, располагающейся по определенному пути
 *  @param HTMLElement el контекстный узел
 *  @param string path выражение x-path
 *  @return HTMLElement */
function alzXPather(el, path) {
	var tag = '';
	var pos = '';
	var mode = 'tag';
	for (var i=0; i<path.length; i++) {
		if (path.charAt(i) == '/') { path = path.substr(i+1); break; }
		else if (path.charAt(i) == '.') {
			if (mode == 'dot') return alzXPather(el.parentNode, path.substr(i+2));
			else mode = 'dot';
		}
		else if (path.charAt(i) == '[') mode = 'pos';
		else if (path.charAt(i) == ']') mode = 'tag';
		else if (mode == 'pos') pos += path.charAt(i);
		else if (mode == 'tag') tag += path.charAt(i);
		if ((i+1) == path.length) path = path.substr(i+1);
	}
	if (!tag.length) return el;
	pos = parseInt('0'+pos, 10); if (!pos) pos = 1;
	for (var i=0; i<el.childNodes.length; i++)
		if (el.childNodes[i].tagName == tag && (pos-- == 1))
			return path ? alzXPather(el.childNodes[i], path) : el.childNodes[i];
	return null;
}
