function FmAjax(){}

FmAjax.gateway = '/fmajax/gateway.php';

FmAjax.buffer = new Array();

FmAjax.request = null;

FmAjax.request_timer = null;

FmAjax.getXml = function()
{
	var args = FmAjax._getArguments(arguments);
	if (args)
	{
		FmAjax._request('GET','XML', args.gateway_class, args.gateway_function, args.callback, args.params);
	}
}

FmAjax.postXml = function()
{
	var args = FmAjax._getArguments(arguments);
	if (args)
	{
		FmAjax._request('POST','XML', args.gateway_class, args.gateway_function, args.callback, args.params);
	}
}

FmAjax.getJosn = function(){}

FmAjax.postJosn = function(){}

// Функция выполняющая запрос к серверу
FmAjax._request = function(request_method, response_type, gateway_class, gateway_function, callback, params)
{
	// Если объект раньше не существоал, пытаемся его создать
	if (FmAjax.request == null) FmAjax.request = FmAjax._getRequestObject();

	// Если существует объект FmAjax.request
	if (FmAjax.request != null)
	{
		// Создаем массив параметров для данного запроса
		// и записываем их в буфер, если число параметров раввно 5
		if (arguments.length == 6)
		{
			var request_params = new Array(request_method, response_type, gateway_class, gateway_function, callback, params);
			FmAjax.buffer.push(request_params);
		}

		// Если аякс объект не занят и в очереди находится хотябы один запрос
		if ((FmAjax.request.readyState == 4 || FmAjax.request.readyState == 0) && (FmAjax.buffer.length > 0))
		{
			var request_params = FmAjax.buffer.shift();
			request_method = request_params[0];
			response_type = request_params[1];
			gateway_class = request_params[2];
			gateway_function = request_params[3];
			callback = request_params[4];
			params = request_params[5];

			try
			{
				var url = FmAjax.gateway;
				url += '?_cl=' + encodeURIComponent(gateway_class) + '&_fn=' + encodeURIComponent(gateway_function);
				switch (request_method)
				{
					case 'GET':
					get_params = FmAjax._getParamQuery(params);
					if (get_params != null) url += '&' + get_params;
					FmAjax.request.open(request_method, url, true);
					FmAjax.request.send(null);
					break;
					case 'POST':
					FmAjax.request.open(request_method, url, true);
					FmAjax.request.setRequestHeader("Method", "POST " + url + " HTTP/1.1");
					FmAjax.request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
					FmAjax.request.send(FmAjax._getParamQuery(params));
					break;
				}

				FmAjax.request.onreadystatechange = function()
				{
					try
					{
						if (FmAjax.request.readyState != 4) return;
						if (FmAjax.request.status == 200)
						{
							var result = null;
							switch (response_type)
							{
								case 'XML':
								var xml_obj = FmAjax.request.responseXML;
								FmAjax._reRequest(true);
								if (xml_obj && xml_obj.documentElement) result = FmAjax._parseXml(xml_obj);
								break;
								case 'JSON': break;
							}

							if (result != null)
							{
								if (typeof(callback) == 'string')
								{
									eval(callback + '(' + FmAjax._convertArrayToObjectCode(result) + ')');
								}
								else if (typeof(callback) == 'function')
								{
									var obj = FmAjax._convertArrayToObject(result);
									try {callback.call(null,obj);}
									catch (e) {FmAjax.error('Ошибка вызова функции');}
								}
								else
								{
									FmAjax.error('Неправильная функция обратного вызова');
								}
							}
							else FmAjax.error('Сервер вернул ошибку');
						}
						else
						{
							FmAjax.error('Ошибка доступа к серверу ' + FmAjax.request.status);
						}
					}
					catch (e)
					{
						FmAjax.error(e.toString());
						return false;
					}
				}

			}
			catch (e)
			{
				FmAjax.error(e.toString());
				return false;
			}
		}
		else
		{
			FmAjax._reRequest(false);
		}
	}
	else
	{
		FmAjax.error('Ваш браузер не поддерживает Ajax');
		return false;
	}
}

FmAjax._reRequest = function(now)
{
	if (FmAjax.request_timer) window.clearTimeout(FmAjax.request_timer);
	if (FmAjax.buffer.length > 0)
	{
		var timeout = 300;
		if (now == true) timeout = 100;
		FmAjax.request_timer = window.setTimeout('FmAjax._request()', 500);
	}
}

FmAjax._convertArrayToObjectCode = function(data)
{
	var error_code = '';
	var data_code = '';
	if (data['ok'])
	{
		var comma = '';
		var data_code = ",'data':{";
		for (key in data['data'])
		{
			$quote = (data['data'][key]['type'] == 'string')?"'":'';
			data_code += comma + key + ':' + $quote + data['data'][key]['value'] + $quote;
			comma = ',';
		}
		data_code += '}';
	}
	else
	{
		error_code = ",'error':{'code':"+data['error']['code']+",'message':'"+data['error']['message']+"'}";
	}

	var array_code = "{'ok':" + data['ok'] + data_code + error_code + "}";
	return array_code;
}

FmAjax._convertArrayToObject = function(data)
{
	var obj = new Object();
	obj.ok = data['ok'];
	obj.data = new Object();
	if (data['ok'])
	{
		for (key in data['data'])
		{
			eval("obj.data." + key + " = data['data']['" + key + "']['value'];");
		}
	}
	else
	{
		obj.error = new Object();
		obj.error.code = data['error']['code'];
		obj.error.message = data['error']['message'];
	}
	return obj;
}

FmAjax._parseXml = function(xml_document)
{
	var root_element = xml_document.documentElement;
	if (root_element.tagName == 'fmajax_response')
	{
		var result = new Array();
		result['ok'] = true;
		result['data'] = new Array();
		result['error'] = new Array();

		var response_errors = xml_document.getElementsByTagName('response_error');
		if (response_errors.length > 0)
		{
			var response_errors = response_errors.item(0).childNodes;
			var error_code = null, error_message = null;
			for (var i = 0; i < response_errors.length; i++)
			{
				if (error_code == null && response_errors.item(i).tagName == 'code') error_code = response_errors.item(i).firstChild.nodeValue;
				if (error_message == null && response_errors.item(i).tagName == 'message') error_message = response_errors.item(i).firstChild.nodeValue;
			}

			result['error']['code'] = error_code;
			result['error']['message'] = error_message;
			result['ok'] = false;
			return result;
		}
		else
		{
			var response_items = xml_document.getElementsByTagName('response_item');
			for (var i = 0; i < response_items.length; i++)
			{
				var response_item = response_items.item(i).childNodes;
				var var_name = null, var_type = null, var_value = null;
				for (var j = 0; j < response_item.length; j++)
				{
					if (var_name == null && response_item.item(j).tagName == 'name') var_name = response_item.item(j).firstChild.nodeValue;
					if (var_type == null && response_item.item(j).tagName == 'type') var_type = response_item.item(j).firstChild.nodeValue;
					if (var_value == null && response_item.item(j).tagName == 'value') var_value = response_item.item(j).firstChild.nodeValue;
				}

				switch (var_type)
				{
					case 'int': var_value = parseInt(var_value,10); break;
					case 'float': var_value = parseFloat(var_value,10); break;
				}

				result['data'][var_name] = new Array();
				result['data'][var_name]['value'] = var_value;
				result['data'][var_name]['type'] = var_type;
			}
		}

		return result;
	}
	else
	{
		return null;
	}
}

FmAjax.error = function(msg)
{
	alert(msg);
}

FmAjax.getFormValues = function(form_id)
{
	var obj_form = document.getElementById(form_id);
	var form_values = new Array();

	if (obj_form && obj_form.tagName.toUpperCase() == 'FORM')
	{
		var form_elements = obj_form.elements;
		for(var i=0; i < form_elements.length; i++)
		{
			if (!form_elements[i].name) continue;
			if (form_elements[i].type && (form_elements[i].type == 'radio' || form_elements[i].type == 'checkbox') && form_elements[i].checked == false) continue;
			if (form_elements[i].disabled && form_elements[i].disabled == true) continue;
			var name = form_elements[i].name;
			if (name)
			{
				if(form_elements[i].type=='select-multiple')
				{
					for (var j = 0; j < form_elements[i].length; j++)
					{
						if (form_elements[i].options[j].selected == true) form_values[name] =  form_elements[i].options[j].value;
					}
				}
				else form_values[name] =  form_elements[i].value;
			}
		}
		return form_values;
	}
}

FmAjax._getParamQuery = function(params)
{
	if (params)
	{
		var query_string = '';
		var comma = '';
		for (key in params)
		{
			query_string += comma + key + '=' + encodeURIComponent(params[key]);
			comma = '&';
		}
		return query_string;
	}
	else return null;
}

FmAjax._getArguments = function(args)
{
	if (args.length == 3 || args.length == 4)
	{
		var params = args[args.length - 4]
		if (params == undefined) params = false;
		var gateway_class = args[args.length - 3];
		var gateway_function = args[args.length - 2];
		var callback = args[args.length - 1];
		return {'gateway_class':gateway_class,'gateway_function':gateway_function,'callback':callback,'params':params};
	}
	else
	{
		return false;
	}
}

FmAjax._getRequestObject = function()
{
	var req = null;
	if (typeof XMLHttpRequest != "undefined") req = new XMLHttpRequest();
	if (!req && typeof ActiveXObject != "undefined")
	{
		try {req=new ActiveXObject("Msxml2.XMLHTTP"); }
		catch (e)
		{
			try{req=new ActiveXObject("Microsoft.XMLHTTP");}
			catch (e2)
			{
				try {req=new ActiveXObject("Msxml2.XMLHTTP.4.0");}
				catch (e3) {req=null; }
			}
		}
	}
	if(!req && window.createRequest) {req = window.createRequest(); }
	if (!req) return null;
	else return req;
}

