/*
 * Описание:	Асинхронная передача информации (формы, клики ...)
 * Автор:		Мылтасов Андрей
 * Источник:	b99.ru 
 * Версия:		2.1.1
 */
/************************* Диспечер ********************************************************/
function CDispatcher()
{
	this.TimeTick	= 50;			//Интервал проверок
	this.Jobs		= new Array();	//Список текущих запросов
	//Обработчик
	this.Handler = function(obj, status, result)
	{
		this.delJob(obj.IDpack);
		obj.Status = status;
		obj.Result = result;
		obj.Handler();
	}
	//Добавление закачки
	this.Add = function(obj)
	{
		this.Jobs[obj.IDpack] = obj;
		setTimeout( 'Dispatcher.TickTimeOut("' + obj.IDpack + '")', obj.TimeOut);
		this.Tick();
	}
	//Проверка состояния запроса
	this.Tick = function()
	{
		var flag = false;
		for( num in this.Jobs)
			if( this.isJob(num) ) 
			{
				var result = eval(num);
				if( result != null && typeof(result) == 'object' )
					this.Handler(this.Jobs[num], 'ok', result)
				else
					flag = true;
			}
		if( flag )
			setTimeout('Dispatcher.Tick()', this.TimeTick);
	}
	//Истекло время...
	this.TickTimeOut = function(num)
	{
		if( this.isJob(num) )
			this.Handler(this.Jobs[num], 'timeout', null)
	}
	//Удаляем задание
	this.delJob = function(num)
	{
		if( this.isJob(num) )
			delete this.Jobs[num];
	}
	//Проверка на существование задания
	this.isJob = function(num)
	{
		if( this.Jobs[num] != undefined )
			return true;
		return false;
	}
}
Dispatcher = new CDispatcher();

/************************* Базовый асинхронные запросы *********************************************/
function CAsyn()
{
	this.isDebug	= false;			//Отладка скрипта?
	this.Handler	= null;				//Обработчик результата
	this.Result		= null;				//Ответ
	this.Status		= 'create';			//Статус: create, wait, ok, error, timeout
	this.TimeOut	= 3000;				//Timeout на обмен
	this.IDpack		= 0;				//Номер пакета
	this._Container	= null;				//Контейнер
	//Получить номер пакета
	this.setDebug = function(type)
	{
		if( !type )
			this.isDebug = true;
		else
			this.isDebug = type;
	}
	//Получить номер пакета
	this.getPack = function()
	{
		this.IDpack = '_' + Math.floor(Math.random()*100000000000000);
		eval(this.IDpack + ' = null;');
	}
	//Закачка
	this._Go = function()
	{
		this.createPack();
		this.Status = 'wait';
		Dispatcher.Add(this); //Добавляем задание в диспечер
	}
	//Очищаем
	this.Del = function()
	{
		delete this._Container;
		delete this.Result;
		delete this.IDpack;
		delete this.Handler;
	}
}
/************************* Асинхронные запросы *********************************************/
function CAsynClick(url, handler)
{
	this.Handler	= handler;			//Обработчик результата
	this.Url		= url;				//URL
	this.Params		= new Array();		//Параметры запроса
	this._Container	= document.createElement('SCRIPT'); //Контейнер
	//Добавление параметров запроса
	this.setParam	= function(name, value)
	{
		this.Params.push( [name, value] );
	}
	//Создаем пакет
	this.createPack = function()
	{
		this.getPack();
		this._Container.setAttribute('type', 'text/javascript');
		this._Container.setAttribute('src', this.getUrl());
	}
	//Получение URL запроса
	this.getUrl		= function()
	{
		var url = this.Url + '?pack=' + this.IDpack;
		for( i = 0; i < this.Params.length; i++ )
			url += '&' + encodeURIComponent(this.Params[i][0]) + '=' + encodeURIComponent(this.Params[i][1]);
		return url;
	}
	//Закачка
	this.Go	= function()
	{
		this._Go();
		if( this.isDebug ) alert(this.getUrl());
		document.getElementsByTagName('head')[0].appendChild(this._Container); //Отправляем запрос
	}
}
CAsynClick.prototype = new CAsyn();

/************************* Асинхронные формы *********************************************/
function CAsynForm(form, handler)
{
	this.Handler	= handler;			//Обработчик результата
	this.Form		= form;				//Форма
	this.idPackForm	= form.id+'-pack';	//id элемента pack в Форме
	this.TimeOut	= 7000;				//Timeout на обмен
	this._Container	= document.createElement('DIV'); //Контейнер
	//Создаем пакет
	this.createPack = function()
	{
		this.getPack();
		var pPack = document.getElementById(this.idPackForm);
		if(	pPack == null )
		{
			pPack = document.createElement('INPUT');
			pPack.type = 'hidden';
			pPack.name = 'pack';
			pPack.id = this.idPackForm;
			this.Form.appendChild(pPack);
		}
		pPack.value = this.IDpack;
		this._Container.style.position = 'absolute';
		this._Container.style.visibility = 'hidden';
		document.body.appendChild(this._Container);
		this._Container.innerHTML = '<iframe frameborder="0" width="0" height="0" name="' + this.IDpack + '" style="visibility: hidden;"></iframe>';
	}
	//Закачка
	this.Go	= function()
	{
		this._Go();
		if( this.isDebug ) alert(this.Form.action);
		this.Form.setAttribute('target', this._Container.getElementsByTagName('IFRAME')[0].name);
	}
	/*
	 * Универсальный обработчик ошибок в форме
	 *   class="error-box" - оформление выделения ошибки
	 *   class="error-msg" - оформление сообщения об ошибке
	 *   form_id|elem_id   - id контейнера для вывода сообщения об ошибке
	 */
	this.ErrorHandler = function(pError /*ссылка на объект ошибка*/)
	{
		var mName = '';
		var sElem = null;
		//Снимаем выделяние ошибки у каждого поля формы; выделяем и подписываем, где есть ошибка
		for( i = 0; i < this.Form.length; i++)
			if( (mName = this.Form.id+'|'+this.Form[i].name) && document.getElementById(mName) != null )
			{
				//Инициализация
				if( document.getElementById(mName+'|msg') == null )
				{
					var pDiv = document.createElement('DIV');
					pDiv.id = mName+'|msg';
					pDiv.className = 'error-msg';
					document.getElementById(mName).appendChild(pDiv);
				}
				//Очищаем
				document.getElementById(mName).className = '';
				document.getElementById(mName+'|msg').style.display = 'none';
				//Выделяем и подписываем
				if( pError != undefined && pError[this.Form[i].name] != undefined )
				{
					if( sElem == null ) //Сохраняем первую ошибку
						sElem = this.Form[i];
					document.getElementById(mName).className = 'error-box';
					document.getElementById(mName+'|msg').style.display = 'block';
					document.getElementById(mName+'|msg').innerHTML = pError[this.Form[i].name];
				}
			}
		//Переводим фокус на ошибку
		if(sElem != null)
			sElem.focus();
	}
}
CAsynForm.prototype = new CAsyn();
/************************* Tools **********************************************************/
// Копирует строку в таблице и заполняет значениями
function copyRow(pTable /*ссылка на таблицу*/, mIndex /*номер строки*/, mCells /*массив значений ячеек*/)
{
	var pNewRow = pTable.rows[mIndex].cloneNode(true);
	pTable.rows[mIndex].parentNode.insertBefore(pNewRow, pTable.rows[mIndex]);
	if( mCells != undefined )
		for(var i = 0; i < pNewRow.cells.length; i++)
			if( mCells[i] != undefined )
				pNewRow.cells[i].innerHTML = mCells[i];
	return pNewRow;
}
