/**
 * @fileoverview
 * Juds Ajax Framework.
 * Copyright (C) 2007  Denis Panaskin (goliathdp@gmail.com)<br>
 * <br>
 * This library is free software; you can redistribute it and/or<br>
 * modify it under the terms of the GNU Lesser General Public<br>
 * License as published by the Free Software Foundation; either<br>
 * version 2.1 of the License, or (at your option) any later version.<br>
 * <br>
 * This library is distributed in the hope that it will be useful,<br>
 * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
 * Lesser General Public License for more details.<br>
 * <br>
 * You should have received a copy of the GNU Lesser General Public<br>
 * License along with this library; if not, write to the Free Software<br>
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA<br>
 * <br>
 * <br>
 * www.juds.com.ua<br>
 * Denis Panaskin<br>
 */

/**
 * @package Juds Ajax Framework
 * @copyright Copyright &copy; 2007, www.juds.com.ua
 * @author Denis Panaskin <goliathdp@gmail.com>
 */

/**
* @constructor
* @class AJAX
* @extends EventDispatcher
* @see #getInstance
* @version 1.2
* @return Экземпляр Ajax объекта
* @author Denis Panaskin <goliathdp@gmail.com>
*/
function AJAX()
{
	AJAX.instance = this;
	this.listener = new Array();
	if(this.isShowLoadingBar)
		this.initLoadingDiv();
}// end constructor 

AJAX.prototype = new EventDispatcher();

/**
 * Ссылка на последний экземпляр Ajax компонента.
 * @type AJAX
 * @private
 */
AJAX.instance = null;

/**
 * Флаг определяющий отображать ли панель загрузки
 * @type Boolean
 * @private
 */
AJAX.prototype.isShowLoadingBar = true;

/**
 * Последний запрос произведенные через Ajax компонент
 * @type String
 * @private
 */	
AJAX.prototype.last_request = "";

/** 
 * Идентификатор HTML объекта, в котором необходимо отображать ответ сервера 
 * @type String
 * @private
 */
AJAX.prototype.id_answer = "";
	
/** 
 * Буфер ссылок *.js файлов необходимых загрузить 
 * @type Array
 * @private
 */
AJAX.prototype.ajax_js_files = Array();
	
/** 
 * Буфер сриптов необходимых  интерпретировать 
 * @type Array
 * @private
 */
AJAX.prototype.ajax_scripts = Array();
	
/** 
 * Последний запрос произведенный через Ajax 
 * @type String
 * @private
 */
AJAX.prototype.last_ajax_request = null;
	
/**
 * Буфер хранения ответа полученного от сервера
 * @type String
 * @private
 */
AJAX.prototype.resultAjax;

/**
 * Константа состояния запроса
 * @final
 */
AJAX.READY_STATE_UNINITIALIZED=0;

/**
 * Константа состояния запроса
 * @final
 */
AJAX.READY_STATE_LOADING=1;

/**
 * Константа состояния запроса
 * @final
 */
AJAX.READY_STATE_LOADED=2;

/**
 * Константа состояния запроса
 * @final
 */
AJAX.READY_STATE_INTERACTIVE=3;

/**
 * Константа состояния запроса
 * @final
 */
AJAX.READY_STATE_COMPLETE=4;

/**
 * Инициализация экземпляр объекта XMLHttpRequest
 * @private
 * @return XMLHttpRequest объект
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.getXMLHttpRequest = function() 
{
	var xmlhttpreq;

	if (window.XMLHttpRequest) //Mozilla, Safari & IE 7
	{
		xmlhttpreq = new XMLHttpRequest();
	}
	else if(window.ActiveXObject) // IE 6 and later
	{
		try 
		{
			xmlhttpreq = new ActiveXObject('Msxml2.XMLHTTP');
		}
		catch(err) 
		{
			xmlhttpreq = new ActiveXObject('Microsoft.XMLHTTP');
		}
	}

	return xmlhttpreq;
}// end method getXMLHttpRequest

/**
 * Получаем экземпляр объекта (Singleton pattern)
 * @public
 * @return AJAX экземпляр
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.getInstance = function()
{
	if(AJAX.instance == null)
		AJAX.instance = new AJAX();
	return AJAX.instance;
}// end getInstance

/**
 * Устанавливаем строку последнего запроса
 * @private
 * @param String query запрос
 * @see #getLastRequest
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.setLastRequest = function(query)
{
	this.last_request = query;
}// end setLastRequest

/**
 * Возвращает последний запрос произведенный на сервер
 * @private
 * @see #setLastRequest
 * @return String последний запрос
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.getLastRequest = function()
{
	return this.last_request;
}// end getLastRequest

/**
 * Идентификатор HTML объекта, в котором необходимо отображать ответ сервера
 * @public
 * @see #getResponseID
 * @return String 
 * @author Denis Panaskin <goliathdp@gmail.com>
 */	
AJAX.prototype.getResponseID = function()
{
	return this.id_answer;
}// end getResponseID
	
/**
 * Устанавливает идентификатор HTML объекта, в котором необходимо отображать ответ сервера
 * @protected
 * @see #getResponseID
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.setResponseID = function(ids)
{
	this.id_answer = ids;
}// end 

/**
 * Отправляет запрос на сервер
 * @private
 * @param String method метод отправки GET или POST
 * @param String url ссылка
 * @see #handleAjaxResponse
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.sendRequest = function(method, url) 
{
	var requestParams = [];
	for(var i = 0; i < arguments.length; i++ ) 
		requestParams.push(arguments[i]);

	var request = this.getXMLHttpRequest();

	request.open( method, url, true);
	request.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded');

	var instance = this;
	request.onreadystatechange = function() 
	{
		AJAX.getInstance().handleAjaxResponse(request);
	};

	request.send(this.queryString(requestParams) );
}// end sendRequest

/**
 * Конвертирования массива параметров в строку параметров 
 * @param Array args
 * @return String
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.queryString = function(args) 
{
	var requestParams = [];
	for (var i = 0; i<requestParams.length; i++) 
		requestParams.push(requestParams[i]);

	for(var j = 0 ; j < args.length; j++) 
		requestParams.push(args[j]);

	var queryString = "";

	if(requestParams && requestParams.length > 0 ) 
	{
		for(var i = 0 ; i < requestParams.length ; i++ ) 
		{
			queryString += requestParams[i] + '&';
		}
		queryString = queryString.substring(0, queryString.length-1);
	}
	return queryString;
}// end queryString

/**
 * Отправляет запрос на сервер с переданными параметрами
 * @param String method метод отправки GET или POST
 * @param String url ссылка
 * @param String params строка параметров a=1&b=d&...&f=6
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.sendRequestParam = function(method, url, params) 
{
	var request = this.getXMLHttpRequest();
	request.open( method, url, true );
	request.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded');
	request.onreadystatechange = function() 
	{
		AJAX.getInstance().handleAjaxResponse(request) 
	};
	request.send( params );
}// end sendRequestParam

/**
 * Отправляем запрос серверу GET метод 
 * @param String params ссылка
 * @param String id Идентификатор объекта, в котором нужно отобразить ответ сервера
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.getContent = function(params, id)
{
	
	
	var url = params;
		
	if(url.search (/\?{1}/)==-1)
		url+="?ajax=1";
	else
		url+="&ajax=1";
		
	this.setLastRequest(url); 

	this.setResponseID(id);

	this.sendRequest("GET", url);
}// end getContent

/**
 * Отправляем запрос серверу POST метод 
 * @param String where ссылка
 * @param String id Идентификатор объекта, в котором нужно отобразить ответ сервера
 * @param String params строка параметров a=1&b=d&...&f=6
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.getContentPOST = function(where, id, params)
{
	var url = where;
		
	if(url.search (/\?{1}/)==-1)
		url+="?ajax=1";
	else
		url+="&ajax=1";
		
	this.setLastRequest(url);
		
	this.setResponseID(id);
	this.sendRequestParam("POST", url, params) 
}// end getContentPOST

/**
 * Обработчик ответа
 * @param XMLHttpRequest request
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.handleAjaxResponse = function(request) 
{
	if(request.readyState == AJAX.READY_STATE_COMPLETE ) 
	{
		if(this.isSuccess(request))
		{
			if(document.getElementById(this.getResponseID())==null)
			{
				throw "Object \""+this.getResponseID()+"\" not found.";
				return false;
			}

			this.setResponseData(request.responseText);
				
			this.getCssFiles();
			match = this.resultAjax.match(/<script.*?>((.|[\r\n])*?)<\/script>/ig);
			var stripTegReg = "(<script.*?>|</script>|<SCRIPT.*?>|</SCRIPT>)+";
			var regexpStripTeg = new RegExp(stripTegReg, "g");

			document.getElementById(this.getResponseID()).innerHTML = this.getResponseData();
					
			if(match!=null)// Если в ответе найден тег script
			{
				for(i=0; i<match.length; i++)
				{
					var tt = match[i];
					match2 = tt.match(/src=".*?"/ig);
					if(match2!=null)
					{
						js_url = match2[0].replace("src=", "").replace("\"", "").replace("\"", "");
						this.ajax_js_files.push(js_url);
					}
					else
					{
						var code_str = match[i].replace(regexpStripTeg, "");
						this.ajax_scripts.push(code_str);
					}
				}// end for i
					
				/** Подгружаем *.js файлы */
				this.getJSFiles();
			}// end if

			if(this.isShowLoadingBar)
				this.hideLoadingDiv();
			
			var event = new Object();
			event.url = this.getLastRequest();
			event.responseId = this.getResponseID();
			this.dispatchEvent(ResultEvent.RESULT, event);
			
			
		}
		else
		{
			throw "Ajax Error: Can't get response data from "+this.getLastRequest()+".";
			alert('Connection error: '+this.getLastRequest());
		}
	}
	else
	{
		if(this.isShowLoadingBar)
			this.showLoadingDiv();
	}// end if
}// end handleAjaxResponse
	
/**
 * Возвращает true если выполнен удачно запрос и получен ответ от сервера
 * @param  XMLHttpRequest request
 * @return Boolean 
 * @see #handleAjaxResponse
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.isSuccess = function(request)
{
	return request.status == 0 || (request.status >= 200 && request.status < 300);
}// end method isSuccess

/**
 * Сохраняем ответ полученный от сервера
 * @param data String
 * @see #getResponseData
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.setResponseData = function(data)
{
		this.resultAjax = data;
}// end setResponseData
	
/**
 * Возвращает ответ полученный от сервера
 * @see #setResponseData
 * @return String
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.getResponseData = function()
{
	return this.resultAjax;
}// end getResponseData

/**
 * @ignore
 */
AJAX.prototype.getCssFiles = function()
{
	//alert('asdasdasdasd');
}

/**
 * Загрузка *.js файлов помещенных в очередь загрузки
 * @see #getJsContent
 * @see #evalJS
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.getJSFiles = function()
{
	this.ajax_js_files.reverse();
	js_url = this.ajax_js_files.pop();
	if(js_url!=null) // Если в очереди есть файлы
		this.getJsContent("GET", js_url);
	else
	{
		this.ajax_js_files = Array();
		this.evalJS();
	}
}// end getJSFiles
	
/**
 * Интерпретирование скриптов извлеченных из ответа
 * @see #getJSFiles
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.evalJS = function()
{
	this.ajax_scripts.reverse();
	var js_scripts = "";
	for(i=0; i<this.ajax_scripts.length; i++)
	{
		var stripTegReg = "(<!--|-->)+";
		var regexpStripTeg = new RegExp(stripTegReg, "g");
		js_scripts +=this.ajax_scripts[i].replace(regexpStripTeg, ""); 
	}
		
	if(window.execScript!=null)
		window.execScript(js_scripts);
	else
		window.eval(js_scripts);
		
	this.ajax_scripts = Array();
}// end evalJS

/**
 * Загрузка *.js файлов
 * @see #getJSFiles
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.getJsContent = function(method, url) 
{
	var requestParams = [];

	for(var i = 0; i < arguments.length; i++) 
		requestParams.push(arguments[i]);

	var request = this.getXMLHttpRequest();

	this.setLastRequest(url); 
	request.open( method, url, true);

	request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

	request.onreadystatechange = function() 
	{
		AJAX.getInstance().handleAjaxJsResponse(request) 
	};

	request.send(this.queryString(requestParams));
}// end getJsContent

/**
 * Получаем содержимое *.js файла
 * @see #getJSFiles
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.handleAjaxJsResponse = function(request) 
{
	if(request.readyState == AJAX.READY_STATE_COMPLETE ) 
	{
		if (this.isSuccess(request))
		{
			var resultAjax = request.responseText;
			if(window.execScript!=null)
				window.execScript(resultAjax);
			else
				window.eval(resultAjax);
			/** Загружаем следующий *.js файл */
			this.getJSFiles();
		}
		else
			alert('Connection error: '+this.getLastRequest());
	}// end if
}// end handleAjaxJsResponse

/**
 * Преобразования массива checkboxов в строку
 * @param Array arr массив
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.arrayToString = function(arr)
{
	str = '';
	for(i=0; i<arr.length; i++)
	{
		if(arr[i].checked==true)
			str+=arr[i].value+',';
	}
	return str.substring(str.length-1, 0);
}// end arrayToString

/**
 * Преобразовуем елементы формы в список параметров.
 * @param Object form форма
 * @return String
 * @author Denis Panaskin <goliathdp@gmail.com>
 */
AJAX.prototype.getFormParam = function(form)
{
	var str = "";
		
	if(form.elements==null)
		return;
		
	for(i=0; i<form.elements.length; i++)
	{
		var type = form.elements[i].type;

		if(type != "radio" && type != "button" &&  type != "submit" && type!="checkbox")
		{
			if(form.elements[i].name==null)
				continue;
			str +=form.elements[i].name+"="+form.elements[i].value;
				
		}
		else if(type == "radio" || type == "checkbox")
		{
			if(form.elements[i].checked)
			{
				str +=form.elements[i].name+"="+form.elements[i].value;
			}
			else
				continue;
		}
		else 
			continue;

		if(i<form.elements.length-1)
			str +="&";
	}// end for i
		
	return str;
}// end FormToParam

/**
 * Инициализация панели загрузки. Панель отображается только при 
 * условии что  <code>isShowLoadingBar = true</code>
 * @see #showLoadingDiv
 * @see #hideLoadingDiv
 * @private
 */
AJAX.prototype.initLoadingDiv = function()
{
	var loadingDiv = document.createElement("div");
	loadingDiv.setAttribute("id", "loading_div");
	loadingDiv.className = "loading_div";
	loadingDiv.style.display = "none";
	document.getElementsByTagName("body")[0].appendChild(loadingDiv);
}// end initLoadingDiv

/**
 * Показать панель загрузки
 * @see #hideLoadingDiv
 * @private
 */
AJAX.prototype.showLoadingDiv = function()
{
	var client_width = Tools.getClientWidth();
	var client_height = Tools.getClientHeight();
	var scrollDeltaPos = document.documentElement.scrollTop;
		
	var loadingFormLeft = Math.ceil(client_width/2);
	var loadingFormTop = Math.ceil(client_height/2)+scrollDeltaPos;
		
	var loadingDiv = document.getElementById("loading_div");
		
	loadingDiv.style.left = (loadingFormLeft - 100)+"px";
	loadingDiv.style.top = (loadingFormTop - 50)+"px";
	loadingDiv.innerHTML = '<div align=center><img src = "./images/loading.gif" border=0></div><div align=center style="font-size:10px; font-family:Tahoma; color:#0074de; font-weight:bold; ">Loading! Please wait…</div>';
	loadingDiv.style.display = "inline";
}// end showLoadingDiv

/**
 * Скрыть панель загрузки
 * @see #showLoadingDiv
 * @private
 */	
AJAX.prototype.hideLoadingDiv = function()
{
	var div = document.getElementById("loading_div");
	div.style.display = "none";
}// end hideLoadingDiv

