function extraActionsThruXmlHttp(targets)
{
	addEventToTargets(targets, 'click', _extraActionsThruXmlHttp, 'div.extra-actions ul.links li[class] a');
};

function _extraActionsThruXmlHttp(e)
{
	/*var e = e || fixEvent(e);*/

	var container = new DOMQuery("div.extra-actions").get(0);

	var item = this;

	var li = getSiblingNode(item, 'up', 'li');
	if(!li)
		return;

	var topicid = item.href.replace(/.+(insert_topicreport|insert_bookmark|add_keywords|delete_keywords|insert_notification|rate|set_topic_posthistory|rate)(\/\D+)?\/(\d+)(.+)?/, '$3');
	if(!topicid)
		return;

	var classNames = jscss('get', li), request, formName;
	for(var i = 0; i < classNames.length;i++)
	{
		switch(classNames[i])
		{
			case 'topic-add-keyword':
				request = 'action=add_keywords&data%5Btype%5D=topic&data%5Bid%5D='+topicid;
				formName = 'form-add-keywords';
				var onsubmitcallback = function ()
				{
					var keywords = new DOMQuery('dl.topic-keywords dd').get(0);

					if(!keywords)
						return;

					var newKeywords = new DOMQuery('form#form-add-keywords input#keywords').get(0).value;
					var listTopicsUrl = new DOMQuery('a', keywords).get(0).href;

					newKeywords = newKeywords.split(' ');

					for(var j = 0; j < newKeywords.length; j++)
						keywords.appendChild(createDOMNode('a', { 'href' : listTopicsUrl.replace(/=.+/i, '=' + newKeywords[j]) }, [ ' ' + newKeywords[j] ]));
				};
			break;
			case 'topic-delete-keyword':
				request = 'action=delete_keywords&data%5Btype%5D=topic&data%5Bid%5D='+topicid;
				formName = 'form-delete-keywords';
				var onsubmitcallback = function ()
				{
					var keywords = new DOMQuery('dl.topic-keywords dd').get(0);

					if(!keywords)
						return;

					var newKeywords = new DOMQuery('form#form-delete-keywords input#keywords').get(0).value;
					var listTopicsUrl = new DOMQuery('a', keywords).get(0).href;

					newKeywords = newKeywords.split(' ');

					for(var j = 0; j < newKeywords.length; j++)
						keywords.appendChild(createDOMNode('a', { 'href' : listTopicsUrl.replace(/=.+/i, '=' + newKeywords[j]) }, [ ' ' + newKeywords[j] ]));
				};
			break;
			case 'topic-report':
				request = 'action=insert_topicreport&data%5Btopicid%5D='+topicid;
				formName = 'form-insert-topicreport';
			break;
			case 'topic-bookmark':
				request = 'action=insert_bookmark&data%5Btopicid%5D='+topicid;
				formName = 'form-insert-bookmark';
			break;
			case 'topic-notification':
				request = 'action=insert_notification&data%5Btype%5D=topic&data%5Bid%5D='+topicid;
				formName = 'form-insert-notification';
			break;
			case 'topic-posthistory':
				request = 'action=set_topic_posthistory&data%5Btopicid%5D='+topicid;
				formName = 'form-posthistory-set';
			break;
			case 'topic-rate':
				request = 'action=rate&data%5Btype%5D=topic&data%5Bid%5D='+topicid;
				formName = 'form-rate';
			break;
		}

		if(request)
			break;
	}

	if(!request)
		return;

	var result = xmlHttpForm( this, request, container, formName, onsubmitcallback );

	if(result)
		e.preventDefault();
};

function updateMessagesThruXmlHttp(targets)
{
	var items = getTargets(targets, "ol.messages li.message ul.message-links li.message-edit a");
	for(var i = 0, item;(item=items.get(i));i++)
	{
		addEvent(item, 'click',
			function(e)
			{
				var messageid = this.href.replace(/.+update_message\/(\d+)(.+)?/, '$1');
				if(!messageid)
					return true;

				var container = new DOMQuery("ol.messages li#message-" + messageid +" div.message-content").get(0);

				var result = xmlHttpForm(
						this,
						'action=update_message&data%5Bmessageid%5D='+messageid,
						container,
						'form-update-message',
						function()
						{
							var request = 'action=view_message&data%5Bmessageid%5D='+messageid;
							var resultreq = httpreq_string(request, null, null, false);

							var target = new DOMQuery('div.message-content-content', container).get(0);
							while(target.childNodes.length > 0)
							{
								target.removeChild(target.firstChild);
							}

							var source = new DOMQuery('div#core form.primary-input dl.property-list dt:first-child + dd', resultreq.responseXML).get(0);
							while(source.childNodes.length > 0)
							{
								target.appendChild( source.removeChild(source.firstChild) );
							}
						}
				);

				if(result)
					e.preventDefault();
			}
		);
	}
};



function xmlHttpForm(invoker, request, container, formIdentifier, onsubmitcallback)
{
	if(formIdentifier)
	{
		var oldForm = new DOMQuery('form#'+formIdentifier, container).get(0);
		if(oldForm)
		{
			oldForm.parentNode.removeChild(oldForm);
			jscss('remove', invoker, 'request-active');
			return true;
		}
	}

	if(!container)
		return false;

	var items = new DOMQuery('form.primary-input, a[class^="request"]', container);
	for(var i = 0, item;(item = items.get(i));i++)
	{
		switch(item.tagName.toLowerCase())
		{
			case 'form':
				item.parentNode.removeChild(item);
			break;
			case 'a':
				jscss('remove', item, 'request-active');
			break;
		}
	}

	jscss('add', invoker, 'request-active');

	var onsubmit = function(e)
	{
		if(e.defaultPrevented)
			return false;

		jscss('add', invoker, 'request-running');

		/* find out wether preview or submit has been hit */
		if(e && e.type == "submit" && typeof e.explicitOriginalTarget != 'undefined' && e.explicitOriginalTarget.name == "data[preview]")
			return true;

		var request = gatherHttpForm(this);
		updatereq = httpreq_string(request, null, null, false);
		if(updatereq.getResponseHeader('X-Errormessage'))
		{
			alert( updatereq.getResponseHeader('X-Errormessage') );
			jscss('remove', invoker, 'request-running');
		}
		else
		{
			if(onsubmitcallback)
			{
				onsubmitcallback();
			}

			this.parentNode.removeChild(this);

			jscss('remove', invoker, 'request-running');
			jscss('add', invoker, 'request-completed');
			setTimeout(function() { jscss('remove', invoker, 'request-completed'); jscss('remove', invoker, 'request-active'); }, 5000);
		}

		e.preventDefault();
	};

	return requestForm(request, container, onsubmit, invoker);
};

function requestForm(requestURL, container, onsubmit, invoker)
{
	jscss('add', invoker, 'request-running');
	var formreq = httpreq_string(requestURL, null, null, false, 'GET');

	if( formreq.readyState == 4 )
	{
		if(formreq.getResponseHeader('X-Errormessage'))
		{
			alert( formreq.getResponseHeader('X-Errormessage') );
			jscss('remove', invoker, 'request-running');
			return true;
		}
		else
		{
			var form = getElementFromXHR(formreq, 'form.primary-input', container);

			if(!form)
			{
				return false;
			}

			jscss('add', form, 'extrequest');

			container.appendChild( form );

			/*
				To prevent the onsubmit() function to submit the form using a XHR,
				we have to store wether any previous action has stopped the default action
				(submitting of the form).
				So, we attach a special event at the propagation-phase (before all events[]
				do their work) at the parentNode, and modify the event-object to store
				wether preventDefault() has been called.
				Then, the second event-listener is called during the bubble-phase - and it
				checks wether the event has determined preventDefault() has been called.

				However... IE must die!
				It doesn't support propagation for submit-events, so we use the addEvent's behaviour
				of calling the functions in sequence of assignment to emulate the behaviour.
			*/

			var eventTarget = form;
			if(form.addEventListener)
			{
				var eventTarget = eventTarget.parentNode;
			}

			/* only attach the handler on the container once */
			if(eventTarget.tagName == 'form' || typeof eventTarget.__preventDefaultHandler == 'undefined')
			{
				addEvent.eventListenerUseCapture = true;
				addEvent(eventTarget, 'submit', function(e)
				{
					e.__preventDefault = e.preventDefault;
					e.preventDefault = function()
					{
						e.defaultPrevented = true;
						e.__preventDefault();
					};
				});
				addEvent.eventListenerUseCapture = false;
				eventTarget.__preventDefaultHandler = true;
			}

			_init(events, form.parentNode);

			addEvent(form, 'submit', onsubmit);

			jscss('remove', invoker, 'request-running');

			return true;
		}
	}
};

function gatherHttpForm(form)
{
	var items = form.elements;
	var str = [ ];

	for(var i = 0, item;(item=items[i]);i++)
	{
		switch( item.tagName.toLowerCase() )
		{
			case 'input':
				switch(item.type)
				{
					case 'text':
					case 'hidden':
					case 'password':
						str.push(item.name+'='+ escape( item.value ) );
					break;
					case 'radio':
					case 'checkbox':
						if(item.checked)
						{
							str.push(item.name+'='+ encodeURI( item.value ) );
						}
					break;
					case 'file':
						if(item.value)
						{
							throw new Error("I can't handle file-uploads; I'll submit the form using a normal request.");
						}
					break;
				}
			break;
			case 'select':
				str.push(item.name+'='+ encodeURI( item.options[item.selectedIndex].value ) );
			break;
			case 'textarea':
				str.push(item.name+'='+ encodeURI( item.value ) );
			break;
		}
	}

	return str.join('&');
};

function httpreq_xml(request, callback, url, async)
{
	var xmlurl = url || board_script_url + '/../xml_input.php';
  	var xmlParser, xmlDocument, req;

	if(window.XMLHttpRequest)
	{
		/* safari 1.3/2.0 doesn't support DOMParser */
		if(typeof DOMParser == "undefined")
			return false;

		req = new XMLHttpRequest();
		xmlParser = new DOMParser();
		xmlDocument = xmlParser.parseFromString(request, 'text/xml');
	}
	else if(window.ActiveXObject)
	{
		req = new ActiveXObject("MSXML2.XMLHTTP.3.0");

		xmlDocument = new ActiveXObject('Msxml2.DOMDocument.3.0');
		xmlDocument.async = false;
		xmlDocument.loadXML(request);
	}

	xmlDocument.insertBefore(xmlDocument.createProcessingInstruction("xml", "version='1.0'"), xmlDocument.firstChild);

	if(callback)
		req.onreadystatechange = callback;

	req.open("POST", xmlurl, (typeof async == "boolean" ? async : true) );

	if(window.XMLHttpRequest)
	{
		req.setRequestHeader('Content-Type', 'text/xml; utf-8');
	}

	req.send(request);

	return req;
};

function httpreq_string(request, callback, url, async, method)
{
  	var req;
	var xmlurl = url || board_script_url;
	method = method || "POST";
  	async = (typeof async == "boolean" ? async : true);

	if(window.XMLHttpRequest)
	{
		req = new XMLHttpRequest();
	}
	else if(window.ActiveXObject)
	{
		req = new ActiveXObject("MSXML2.XMLHTTP.3.0");
	}

	if(callback)
		req.onreadystatechange = callback;

	if(req.overrideMimeType)
		req.overrideMimeType('text/xml');

	request += '&dont_meta_refresh=1';

	if(method == "GET")
	{
		req.open(method, xmlurl + '?' + request, async );
		req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
		req.send(null);
	}
	else
	{
		req.open(method, xmlurl, async );
		req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
		req.send(request);
	}

	return req;
};

/* the container specifies the desired endpoint for the node */
function getElementFromXHR(transport, selector, container)
{
	var root;
	if(isWebKit || !transportHasValidResponseXML(transport))
	{
		root = document.createElement('div');
		root.innerHTML = transport.responseText;
	}
	else
	{
		root = transport.responseXML;
	}

	var element = new DOMQuery(selector, root).get(0);
	if(!element)
		return;

	if(isWebKit || !transportHasValidResponseXML(transport))
	{
		return element;
	}

	var _element;

	if(!container)
		container = document.body;

	try
	{
		_element = container.ownerDocument.adoptNode( element, true );
	}
	catch(e)
	{
		_element = container.ownerDocument.importNode( element, true );
	}

	return container.namespaceURI == _element.namespaceURI ? _element : importNodeCurrentNS( _element );
};

function transportHasValidResponseXML(transport)
{
	if ( typeof transport.responseXML != 'undefined' || transport.responseXML.firstChild.tagName == 'parsererror' || transport.responseXML.documentElement == null || transport.responseXML.documentElement == 'undefined')
		return false;

	return true;
};

function importNodeCurrentNS(node)
{
	var clone;

	switch(node.nodeType)
	{
		default:
		case 8: /* comment */
			return;
		case 3: /* text */
			return document.createTextNode( node.nodeValue );
		case 1: /* node */
			clone = document.createElement( node.tagName );
	}

	for(var i=0, attribute; (attribute=node.attributes[i]); i++)
	{
		clone.setAttribute(attribute.name, attribute.value);
	}

	for(var j=0, subNode, importedSubNode; (subNode=node.childNodes[j]); j++)
	{
		importedSubNode = arguments.callee( node.childNodes[j] );
		if(importedSubNode)
			clone.appendChild( importedSubNode );
	}

	return clone;
};
