/** Определение базовой функциональности
 *  @author Alexey A Zhukov <developer@alz.ru> */

/*****************************************************************************/
/** Действия над стандартными объектами */

/** Возвращает позицию элемента в массиве
 *  @param array array массив
 *  @param string value значение элемента
 *  @return int */
function getPosInArray(array, value) {
	for (var i=0; i<array.length; i++) if (array[i]==value) return i;
	return false;
}

/** Перенацеливает метод на другой объект
 *  @param object Object */
Function.prototype.bind = function(Object) {
	var method = this;
	return function() { return method.apply(Object, arguments); }
}

/** Преобразует данные формы в массив
 *  @param HtmlElement formId */
function dataFormToJs(formId) {
	var result = new Array();
	for (var i=0; i<formId.elements.length; i++) {
		with (formId.elements[i]) {
			if (name) {
				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;
}

/*****************************************************************************/
/** Интерфейс */

/** Открывает окно
 *  @param string path url загружаемого контента
 *  @param int width ширина окна
 *  @param int height высота окна
 *  @return WindowElement */
function windowOpen(path, width, height) {
	var wnd = window.open(path, '_blank', 'width='+width+', height='+height+',toolbar=no,menubar=no,scrollbars=yes,status=yes,resizable=yes');
	wnd.focus();
	return wnd;
}

/** Открывает окно с изображением
 *  @param string path путь до изображения
 *  @param int width ширина изображения
 *  @param int height высота изображения
 *  @return false */
function windowImageOpen(path, width, height) {
	var wnd = window.open('about:blank', '_blank', 'width='+width+', height='+height+',toolbar=no,menubar=no,scrollbars=no,status=yes,resizable=yes');
	wnd.document.write(
		 '<html><head><title>'+path+' ['+width+'X'+height+']</title></head>'
		+'<body style="margin:0; padding:0"><img src="'+path+'" width="'+width+'" height="'+height+'" title="'+path+' ['+width+'X'+height+']" onclick="window.close()" style="cursor:pointer"></body></html>');
	wnd.document.close();
	wnd.focus();
	return false;
}

/*****************************************************************************/
/** Взаимодействие с событиями */

/** Возвращает объект элемента для которого произошло указанное событие
 *  @param Event event
 *  @return HTMLElement Object */
function getEventElement(event) {
	return typeof(event.srcElement) != 'undefined' ? event.srcElement : event.target;
}

function getEventTopElement(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;
	}
}

/** Объект предоставляющий интерфейс для взаимодействия с событием объекта
 *  Использование:
 *  new Eventer(document.getElementById('...'), 'mouseover', function(event){ return true; }).add();
 *  @param HTMLElement Object
 *  @param string onEvent наименование события (без приставки 'on')
 *  @param functon userHandler обработчик события */
function Eventer(element, onEvent, userHandler) {
	this.element = element;
	this.onEvent = onEvent;
	this.userHandler = userHandler;
}

/** Устанавливает обработчик события объекта
 *  @exception */
Eventer.prototype.add = function () {
	if (typeof(this.element.addEventListener) != 'undefined') this.element.addEventListener(this.onEvent, this._handler.bind(this), false);
	else if (typeof(this.element.attachEvent) != 'undefined') this.element.attachEvent('on'+this.onEvent, this._handler.bind(this));
	else throw "Incompatible browser";
}

/** Удаляет обработчик события объекта
 *  @exception */
Eventer.prototype.remove = function () {
	if (typeof(this.element.removeEventListener) != 'undefined') this.element.removeEventListener(this.onEvent, this._handler.bind(this), false);
	else if (typeof(this.element.attachEvent) != 'undefined') this.element.detachEvent('on'+this.onEvent, this._handler.bind(this));
	else throw "Incompatible browser";
}

/** Обертка к пользовательскому обработчику события
 *  @param Event event
 *  @exception */
Eventer.prototype._handler = function (event) {
	if (typeof(window.event) != 'undefined') event = window.event;
	if (this.onEvent == 'DOMMouseScroll' || this.onEvent == 'mousewheel') {
		var wheelStep = event.wheelDelta ? (window.opera?-1:1) * event.wheelDelta / 120
			: (event.detail ? -event.detail / 3 : 0);
		if (this.userHandler(event, wheelStep)) return true;
	}
	else
		if (this.userHandler(event)) return true;
	if (typeof(event.preventDefault) != 'undefined') event.preventDefault();
	return false;
}

/*****************************************************************************/
/** Позиционирование и размеры элементов */

/** Возвращает элемент, располагающейся по определенному пути
 *  @param HTMLElement el контекстный узел
 *  @param string path выражение x-path
 *  @return HTMLElement */
function xpather(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 xpather(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 ? xpather(el.childNodes[i], path) : el.childNodes[i];
	return null;
}

/** Возвращает расстояние до элемента на странице
 *  @param HTMLElement element html-элемент
 *  @return Array(int|undefined, int|undefined) */
function getBounds(element) {
	var dim = new Array(element.offsetLeft, element.offsetTop);
	for (var parent = element.offsetParent; parent; parent = parent.offsetParent) {
		dim[0] += parent.offsetLeft; dim[1] += parent.offsetTop;
	}
	return dim;
}

/** Возвращает размеры видимой части документа
 *  @return Array(int|undefined, int|undefined) */
function getClientDim() {
	return new Array(
		self.innerHeight ? self.innerWidth
			: ((document.documentElement && document.documentElement.clientWidth) ? document.documentElement.clientWidth
				: (document.body ? document.body.clientWidth : undefined)),
		self.innerHeight ? self.innerHeight
			: (document.documentElement && document.documentElement.clientHeight ? document.documentElement.clientHeight
				:(document.body ? document.body.clientHeight : undefined)));
}

/** Возвращает размеры элемента
 *  @param HTMLElement element html-элемент
 *  @return Array(int|undefined, int|undefined) */
function getElementDim(element) {
	var dim = new Array(element.offsetWidth, element.offsetHeight);
	if (element.style)
		with (element.style) {
			if (typeof(width)!='undefined' && null!=width.match(/^[0-9]+px$/i)) dim[0] = parseInt(width, 10);
			if (typeof(height)!='undefined' && null!=height.match(/^[0-9]+px$/i)) dim[1] = parseInt(height, 10);
		}
	return dim;
}

/** Устанавливает размеры элемента
 *  @param HTMLElement element html-элемент
 *  @param Array(int, int) dim размеры */
function setElementDim(element, dim) {
	with (element.style) {
		if (dim[0] !== false && dim[0]>0) width = dim[0];
		if (dim[1] !== false && dim[1]>0) height = dim[1];
	}
}
