	function ajaxLink(ref_form)
	{
		if(typeof ref_form == 'string') this.parseRef(ref_form);
		if(typeof ref_form == 'object') this.assignForm(ref_form);
	}
	
	ajaxLink.prototype.protocol;
	ajaxLink.prototype.host;
	ajaxLink.prototype.path;
	ajaxLink.prototype.parameters;
	ajaxLink.prototype.anchor;
	
	ajaxLink.prototype.a;
	ajaxLink.prototype.form;
	ajaxLink.prototype.submit;

	ajaxLink.prototype.parseRef = function(ref)
	{
		this.protocol = window.location.protocol;
		this.host = window.location.host;
		this.path = window.location.pathname
		this.parameters = {};
		
		var pos;

		if((pos = ref.search(/\:/)) >= 0)
		{
			this.protocol = ref.substring(0, pos + 1);
			ref = ref.substring(pos + 1);
		}

		if((pos = ref.search(/\#/)) >= 0)
		{
			this.anchor = ref.substring(pos + 1);
			ref = ref.substring(0, pos);
		}

		if((pos = ref.search(/\?/)) >= 0)
		{
			var paramsStr = ref.substring(pos + 1) + '&';
			ref = ref.substring(0, pos);
			while((pos = paramsStr.search(/\&/)) >= 0)
			{
				var paramStr = paramsStr.substring(0, pos);
				paramsStr = paramsStr.substring(pos + 1);

				if(paramStr.length)
				{
					var equPos = paramStr.search(/\=/);
					if(equPos < 0) this.parameters[paramStr] = '';
					else this.parameters[paramStr.substring(0, equPos)] = decodeURIComponent(paramStr.substring(equPos + 1));
				}
			}
		}

		if(ref.search(/\/\//) == 0)
		{
			ref = ref.substring(2);
			if((pos = ref.search(/\//)) >= 0)
			{
				this.host = ref.substring(0, pos);
				this.path = ref.substring(pos);
			}
			else
			{
				this.host = ref
				this.path = '/';
			}
		}
		else if(ref.search(/\//) == 0)
		{
			this.path = ref;
		}
		else this.path = this.path + (this.path.substring(this.path.length - 1) == '/' ? '' : '/') + ref;

		return this;
	}

	ajaxLink.prototype.assignA = function(a)
	{
		this.parseRef(a.href);
		this.a = a;
	}

	ajaxLink.prototype.assignForm = function(form, submit)
	{
		this.parseRef(form.action);
		this.form = form;
		this.submit = submit;
	}

	ajaxLink.prototype.assembleRef = function()
	{
		var ref = this.protocol + '//' + this.host + this.path;
		var div = '?';
		for(var key in this.parameters)
		{
			ref += div + key + '=' + encodeURIComponent(this.parameters[key]);
			div = '&';
		}
		return ref;
	}
	
	ajaxLink.prototype.setParameter = function(name, value, overwrite)
	{
		if(overwrite == undefined) overwrite = true;
		
		if(overwrite || !this.hasParameter(name))
			this.parameters[name] = value;
	}

	ajaxLink.prototype.getParameter = function(name)
	{
		if(this.form)
		{
			if(this.parameters[name]) return this.parameters[name];
			var field = $(this.form).find(":input[name='"+ name +"']").get(0);
			if(field) return this.getFormFieldValue(field);
		}
		return this.parameters[name];
	}

	ajaxLink.prototype.hasParameter = function(name)
	{
		if(this.form) return $(this.form).find(":input[name='"+ name +"']").length > 0;
		return this.parameters[name];
	}
	
	ajaxLink.prototype.getFormFieldValue = function(field)
	{		
		switch(field.type)
		{
			case 'radio': return field.checked ? encodeURIComponent(field.value) : null;
			case 'checkbox': return field.checked ? encodeURIComponent(field.value) : null;
			case 'select-one': return field.selectedIndex >= 0 ? field.options[field.selectedIndex].value : '';
			case 'select-multiple': return $(field).val() || []; 
			case 'textarea': return encodeURIComponent(field.value);
			default: return encodeURIComponent(field.value);
		}
	}

	ajaxLink.prototype.getFormData = function()
	{
		var formData = '';
		var fields = $(this.form).find(":input:not(:submit,:image)").get();
		for(var i = 0; i < fields.length; i++)
		{
			var fieldValue = this.getFormFieldValue(fields[i]);
			if(fieldValue != null) 
				if(fieldValue instanceof Array)
					for(var j = 0; j < fieldValue.length; j++)
						formData += fields[i].name + '=' + fieldValue[j] + '&';
				else formData += fields[i].name + '=' + fieldValue + '&';
		}

		if(this.submit) formData += this.submit.name + '=' + encodeURIComponent(this.submit.value);

		return formData;
	}

	ajaxLink.prototype.getFreeLoader = function()
	{
		var loaders = $("iframe.loader");
		var freeLoaders = loaders.filter(".free");
		if(freeLoaders.length) return freeLoaders.get(0);

		var name = 'loader'+ loaders.length;
		$(document.documentElement).append('<iframe class="loader" name="'+ name +'" style="display:none" />')
		loader = $("iframe.loader[name='"+ name +"']").get(0);
		
		loader.free = function() { $(this).addClass('free'); }
		loader.getDocument = function()
		{
			var result;
			do{result = getFrameDocument(loader)} while(!result);
			result = cloneDocument(result);
			return result;
		}

		return loader;
	}

	ajaxLink.prototype.loadXml = function(options)
	{
		if(options == undefined) options = {};
		if(this.form != undefined) {
		    options.method = $(this.form).attr("method");	
			if(this.form.enctype == 'multipart/form-data') {
			    options.method = $(this.form).attr("method");
				var loader = this.getFreeLoader();
				this.form.target = $(loader).attr('name');
				if(loader.contentWindow) loader.contentWindow.name = this.form.target;
				for(var name in this.parameters)
				{
					$(this.form).append('<input name="'+ name +'" type="hidden" class="_loader" />');
					$(this.form).find("input._loader[name='"+ name +"']").attr('value', this.parameters[name]);
				}

				if(this.submit)
				{
					$(this.form).append('<input name="'+ this.submit.name +'" type="hidden" class="_loader" />');
					$(this.form).find("input._loader[name='"+ this.submit.name +"']").attr('value', this.submit.value);
				}
				
				this.form.submit();
				
				this.form.target = '';
				$(this.form).find("input._loader").remove();
				
				if(options.success == undefined)
				{
					var result = loader.getDocument();
					loader.free();
					return result;
				}
				else loader.onload = function() {var result = loader.getDocument(); loader.free(); options.success(result)};
			}
			else
			{
				var postData = this.getFormData();
				for(var name in this.parameters)
					postData += '&' + name + '=' + encodeURIComponent(this.parameters[name]);
				
				if(options.success == undefined) return loadXml(this.assembleRef(), postData);
				else loadXml(this.assembleRef(), postData, options);
			}
		}
		else
		{
			if(options.success == undefined) return loadXml(this.assembleRef());
			else loadXml(this.assembleRef(), undefined, options);
		}
	}

