/*
	(c)copyright 2007, 2008 Gerald Wodni
	ajax update class

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
*/

/* constructors & access functions */
var xmlHttp;	/*!< current */
var xmlHttpBusy = false;
var tabPages = new Array();
var domain = "";
var hiddenElementStyles = new Array();
var forumTicker = null;

function Tabpage()
{
	/* properties */
	this.name = "unknown";
	this.element = null;
	this.currentState = -1;

	/* add this instance to tabPages */
	tabPages.push( this );

	/* members */
	this.getName = getName;
	this.updateState = updateState;
	this.loadUpdate = loadUpdate;
}

function getName()
{
	return this.name;
}

/* update this instance */
function updateState(state)
{
	if( state == null )
		return;

	/* debug output */
	var request = new XMLSerializer().serializeToString(state);
		//console.info( this.getName() + ".updateState:\n" + request);

	/* get increment steps for this element */
	var increments = state.getElementsByTagName('increment');

	for( var i = 0; i < increments.length; i++ )
		/* perform all increments from currentState on */
		if( increments[i].getAttribute && increments[i].getAttribute('step') > this.currentState )
		{
			var newContent = new XMLSerializer().serializeToString(increments[i]);
			var step = increments[i].getAttribute('step');

			this.element.innerHTML += "<h3>" + step + "</h3>" + newContent;
			this.currentState = step;
		}
}

/* apply last update to all tabpages */
function setUpdate()
{
	if ( xmlHttp.readyState == 4)
    	{
		/* search for update tag within the respone */
		var response = xmlHttp.responseXML;

		//var reply = new XMLSerializer().serializeToString(response);
		var kern = getChildByTagName( response, 'kern' );

		/* display Errors */
		var errorShower = getChildrenByClassname( document, 'errorShower', new Array() );
		var errors = getChildByTagName( kern, 'errors' );
		if( errors && errors.hasChildNodes() )
		{
			for( var i = 0; i < errorShower.length; i++ )
				deleteChildren( errorShower[i] );

			var error = errors.firstChild;
			while( error )
			{
				if( error.nodeName == 'error' )
				{
					for( var i = 0; i < errorShower.length; i++ )
					{
						var p = errorShower[i].appendChild( document.createElement('p') );
						var img = p.appendChild( document.createElement('img') );
						img.setAttribute('src', error.getAttribute('image') );
						img.setAttribute('style','vertical-align:middle;');
						p.appendChild( document.createTextNode( html_entity_decode(error.getAttribute('message')) ) );
					}
				}

				error = error.nextSibling;
			}
		}

		/* handle actions */
		var actions = getChildByTagName( kern, 'actions' );
		if( actions && actions.hasChildNodes() )
		{
			var action = actions.firstChild;

			while( action )
			{
				if( action.nodeName == 'action' )
					switch( action.getAttribute('type') )
					{
						case 'swapElements':
							var elementA = document.getElementById( action.getAttribute('targetA') );
							var elementB = document.getElementById( action.getAttribute('targetB') );

							swapElements( elementA, elementB );
						break;
						case 'appendAsFirstChild':
							var target = document.getElementById( action.getAttribute('target') );

							if( target.hasChildNodes )
							{
								target = target.firstChild;

								/* insert before (first child) */
								var constructionTarget = document.createElement('div');
								translateChildrenToDocument( action, constructionTarget );

								var node = constructionTarget.lastChild;
								while( node )
								{
									var nextNode = node.previousSibling;
									target.parentNode.insertBefore( node, target );
									target = node;
									node = nextNode;
								}
							}
							else
								/* normal append */
								translateChildrenToDocument( action, target );

						break;
						case 'append':
							var target = document.getElementById( action.getAttribute('target') );

							translateChildrenToDocument( action, target );
						break;
						case 'appendToParent':
							var target = document.getElementById( action.getAttribute('target') );

							translateChildrenToDocument( action, target.parentNode );
						break;
						case 'insertBefore':
							var target = document.getElementById( action.getAttribute('target') );
							
							var constructionTarget = document.createElement('div');
							translateChildrenToDocument( action, constructionTarget );
							
							var node = constructionTarget.lastChild;
							while( node )
							{
								var nextNode = node.previousSibling;
								target.parentNode.insertBefore( node, target );
								target = node;
								node = nextNode;
							}
						break;
						case 'removeParent':
							var target = document.getElementById( action.getAttribute('target') );

							target.parentNode.parentNode.removeChild( target.parentNode );
						break;
						case 'remove':
							var target = document.getElementById( action.getAttribute('target') );

							target.parentNode.removeChild( target );
						break;
						case 'removeChildren':
							var target = document.getElementById( action.getAttribute('target') );

							while( target.firstChild )
								target.removeChild( target.firstChild );
						break;
						case 'removeChildByAttributeValue':
							var target = document.getElementById( action.getAttribute('target') );

							var attributeName = action.getAttribute( 'attributeName' );
							var attributeValue = action.getAttribute( 'attributeValue' );
							
							var node = target.firstChild;
							while( node )
							{
								if( node.hasAttributes && node.getAttribute )
									if( node.getAttribute( attributeName ) == attributeValue )
										target.removeChild( node );

								node = node.nextSibling;
							}
						break;
						case 'setAttribute':
							var target = document.getElementById( action.getAttribute('target') );
							var attributeName = action.getAttribute( 'attributeName' );
							var attributeValue = action.getAttribute( 'attributeValue' );

							target.setAttribute( attributeName, attributeValue );
						break;
						case 'hideElement':
							var target = document.getElementById( action.getAttribute('target') );
							hiddenElementStyles[ target.id ] = target.getAttribute('style');
							target.setAttribute('style', 'display:none; visibility:hidden;');
						break;
						case 'debug':
							var target = action.getAttribute('target');
							var text = action.getAttribute('text');
							switch( target )
							{
								case '#console':
									if( console )
									{
										console.debug( text );
										break;
									}
								case '#alert':
									alert( text );
								break;
								default:
									console.error( "Unknown KERN-AJAX Debug-Target: " + target + ", text: " + text );
							}
						break;
						case 'logout-notification':
							alert( "Sitzungszeit &uuml;berschritten, bitte erneut einloggen" );
							if( forumTicker )
								window.clearInterval( forumTicker );
						break;
						default:
							console.error( "Unknown KERN-AJAX Action: " + action.getAttribute('type') );
					}

				action = action.nextSibling;
			}
		}
	}

	xmlHttpBusy = false;
}

function translateChildrenToDocument( xml, target )
{
	var node = xml.firstChild;

	while( node )
	{
		if( node.nodeName == '#text' )
		{
			target.appendChild( document.createTextNode( html_entity_decode( node.nodeValue ) ) );
		}
		else
		{
			var newNode = target.appendChild( document.createElement( node.nodeName ) );

			for( var i = 0; i < node.attributes.length; i++ )
			{
				var attributeNode = node.attributes[i];

				if( _SARISSA_IS_IE && attributeNode.nodeName == 'onclick' )	/* for any reason IE is to stupid to handle setAttribute with onclick >:( */
					newNode.onclick = ajaxEventCall;
				else
					newNode.setAttribute( attributeNode.nodeName, attributeNode.nodeValue );
			}

			translateChildrenToDocument( node, newNode );
		}

		node = node.nextSibling;
	}
}

/* load homepage with callback */
function loadUpdate( address )
{
	xmlHttp = new XMLHttpRequest();
	xmlHttp.open("GET", address, true);
	xmlHttp.onreadystatechange = setUpdate;

	xmlHttp.send();
}

function postUpdate( address, parameters )
{
	xmlHttpBusy = true;
	xmlHttp = new XMLHttpRequest();
	xmlHttp.open("POST", address, true);
	xmlHttp.onreadystatechange = setUpdate;

	xmlHttp.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
	//xmlHttp.send("id=asd&lol=hai wie gehts? 'albert'");
	xmlHttp.send( parameters );
}

function kernUpdate( address, elementId, formsName, formsKey )
{
	var element = document.getElementById( elementId );

	var errorShower = getChildrenByClassname( document, 'errorShower', new Array() );
	for( var i = 0; i < errorShower.length; i++ )
	{
		deleteChildren( errorShower[i] );
		var p = errorShower[i].appendChild( document.createElement('p') );
		var img = p.appendChild( document.createElement('img') );
		img.setAttribute('src','/pics/sys/a_loading.gif');
		img.setAttribute('style','vertical-align:middle;');
		p.appendChild( document.createTextNode('Lade...') );
	}

	var presetArray = new Array();
	if( formsName && formsKey )
		presetArray[ formsName ] = formsKey;

	postUpdate( address, urlEncode( getInputs(element, presetArray) ));
}

function ajaxEventCall( evt )
{
	var element = getTarget( evt );

	forumAction( element );
}

function removeArrayItemByIndex( arrayHandle, index )
{
	if( index == 0 )
		return arrayHandle.slice( 1 );
	else if( index == arrayHandle.length )
		return arrayHandle.slice( 0, -1 );
	else
		return Array.concat( arrayHandle.slice( 0, index ), arrayHandle.slice( index + 1 ) );
}

function removeArrayItemByValue( arrayHandle, value )
{
	var i;
	for( i = 0; i < arrayHandle.length; i++ )
		if( arrayHandle[i] == value )
			return removeArrayItemByIndex( arrayHandle, i );
	
	return arrayHandle;
}

function activateForumTicker( aliasUin )
{
	forumTicker = window.setInterval( "forumAction('forum-" + aliasUin + "-tick-1')", 60000 );
}

function forumAction( element )
{
	if( typeof forumAction.semaphore == 'undefined' )
		forumAction.semaphore = 0;
	
	while( forumAction.semaphore );
	forumAction.semaphore++;
	
	if( typeof forumAction.openForums == 'undefined' )
		forumAction.openForums = new Array();

	if( typeof forumAction.openThreads == 'undefined' )
		forumAction.openThreads = new Array();

	var idParts;
	if( element.id )
		idParts = element.id.split( '-' );
	else
		idParts = element.split( '-' );

	if( idParts.length != 4 )	/* non-valid id */
	{
		console.error( 'forumAction: wrong id format "' + element.id + "' count:" + idParts.length );
		return;
	}

	/* id-values */
	var moduleName = idParts[0];
	var aliasUin = idParts[1];
	var item = idParts[2];
	var itemUin = idParts[3];
	
	/* get address & forms information */
	var address = 'http://www.wodni.at/ajax/alias/' + aliasUin;
	var formsName = document.getElementById( moduleName + '-' + aliasUin + '-formsName' ).value;
	var formsCode = document.getElementById( moduleName + '-' + aliasUin + '-formsCode' ).value;
	var postValues = new Array();
	postValues[formsName] = formsCode;

	if( element.id )
		postValues['submitterElement'] = element.id;
	else
		postValues['submitterElement'] = element;

	switch( moduleName )
	{
		case 'forum':
			switch( item )
			{
				case 'tick':
					if( xmlHttpBusy )
						break;

					postValues['tick'] = 1;
					postValues['openForums'] = forumAction.openForums.join(',');
					postValues['openThreads'] = forumAction.openThreads.join(',');
					postUpdate( address, urlEncode( postValues ));
				break;
				case 'forumImage':

					var nextForumUl = getChildByTagName( element.parentNode, 'UL' );

					if( element.getAttribute('alt') == 'collapsed' )
					{
						element.setAttribute( 'src', '/pics/sys/a_loading.gif' );
						element.setAttribute( 'alt', 'loading' );

						//postValues['forumContent'] = nextForumUl.id.split( '-' )[1];
						postValues['forumContent'] = itemUin;
						postUpdate( address, urlEncode( postValues ));
						forumAction.openForums.push( itemUin );
					}
					else if( element.getAttribute('alt') == 'expanded' )
					{
						forumAction.openForums = removeArrayItemByValue( forumAction.openForums, itemUin );

						element.setAttribute( 'src', '/pics/sys/s_folderCollapsed.png' );
						element.setAttribute( 'alt', 'collapsed' );

						/* delete forum entries */
						while( nextForumUl.firstChild ) nextForumUl.removeChild( nextForumUl.firstChild );

						/* delete add fieldset / button */
						while( element.parentNode.lastChild != nextForumUl ) element.parentNode.removeChild( element.parentNode.lastChild );
					}
				break;
				case 'threadImage':
					var nextThreadUl = getChildByTagName( element.parentNode, 'UL' );

					if( element.getAttribute('alt') == 'collapsed' )
					{
						element.setAttribute( 'src', '/pics/sys/a_loading.gif' );
						element.setAttribute( 'alt', 'loading' );

						postValues['threadContent'] = itemUin;
						postUpdate( address, urlEncode( postValues ));
						forumAction.openThreads.push( itemUin );
					}
					else if( element.getAttribute('alt') == 'expanded' )
					{
						forumAction.openThreads = removeArrayItemByValue( forumAction.openThreads, itemUin );
						element.setAttribute( 'src', '/pics/sys/s_folderCollapsed.png' );
						element.setAttribute( 'alt', 'collapsed' );

						/* delete forum entries */
						while( nextThreadUl.firstChild ) nextThreadUl.removeChild( nextThreadUl.firstChild );

						/* delete add fieldset / button */
						while( element.parentNode.lastChild != nextThreadUl ) element.parentNode.removeChild( element.parentNode.lastChild );
					}
				break;
				case 'addNewThreadForm':
				case 'addNewThreadItemForm':

					var id = element.id;

					appendLoadingImage( element.parentNode ).setAttribute( 'id', id );
					element.parentNode.removeChild( element );

					postValues[ item ] = itemUin;
					postUpdate( address, urlEncode( postValues ) );
				break;
				case 'newThread':
				case 'newThreadItem':
					var fieldset = getParentByTagName( element, 'FIELDSET' );
					var id = element.id;
					
					appendLoadingImage( fieldset.parentNode ).setAttribute( 'id', id );
					postValues = getInputs( fieldset, postValues );

					fieldset.parentNode.removeChild( fieldset );

					postValues[ item ] = itemUin; 
					postUpdate( address, urlEncode( postValues ) );
				break;
				case 'threadItemDelete':
					if( ! confirm('Wirklich Löschen?' ) )
						break;

					postValues[ item ] = itemUin;
					postUpdate( address, urlEncode( postValues ) );
				break;
			}
		break;
	}
	forumAction.semaphore--;
}

/* general purpose functions ( belong to no class) */
function getChildByTagName( element, tagName )
{
	var node = element.firstChild;

	while( node )
	{
		if( node.nodeName == tagName )
			return node;

		node = node.nextSibling;
	}
	return null;
}

function getParentByTagName( element, tagName )
{
	var node = element.parentNode;

	while( node )
	{
		if( node.nodeName == tagName )
			return node;

		node = node.parentNode;
	}
	return null;
}

function getChildByAttributeValue( element, attributeName, attributeValue )
{
	var node = element.firstChild;

	while( node )
	{
		if( node.getAttribute && node.getAttribute( attributeName ) == attributeValue )
			return node;

		node = node.nextSibling;
	}
	return null;
}

function getChildrenByClassname( element, className, retter )
{
	var node = element.firstChild;

	while( node )
	{
		if( node.className && node.className == className )	
			retter.push( node );
		
		retter = getChildrenByClassname( node, className, retter );

		node = node.nextSibling;
	}

	return retter;
}

function debugMessage( type, message )
{
	if( window.console && window.console.firebug )
		switch( type )
		{
			case 'error':	console.error( message );	break;
			case 'info':	console.info( message );	break;
			case 'debug':
			default:	console.debug( message );	break;
		}
	else
	{
		var errorShowers = getChildrenByClassname( document, 'errorShower', new Array() );
		var errorShower = errorShowers[ errorShowers.length - 1 ];
		errorShower.style.color = 'white';
		errorShower.style.backgroundColor = 'black';

		errorShower.appendChild( document.createTextNode( type + ':' + message ) );
		errorShower.appendChild( document.createElement( 'br' ) );
	}
}

/* returns all element-children which are inputs in an array */
function getInputs( element, retter )
{
	var node = element.firstChild;

	while( node )
	{
		if( (node.nodeName == "INPUT" || node.nodeName == 'SELECT' || node.nodeName == 'TEXTAREA' ) && node.getAttribute && node.getAttribute("name") != "" )
			retter[node.getAttribute("name")] = node.value;
		else if( node.firstChild )
			retter = getInputs(node, retter);

		node = node.nextSibling;
	}

	return retter;
}

function appendLoadingImage( element )
{
	var img = element.appendChild( document.createElement('img') );
	img.setAttribute('src', "/pics/sys/a_loading.gif");
	img.setAttribute('alt', 'loading');

	return img;
}

function swapElements( a, b )
{
	var parentA, nextA;

	/* save a's rekations */
	parentA = a.parentNode; nextA = a.nextSibling;

	/* put a in front of b */
	parentA.removeChild( a );
	b.parentNode.insertBefore( a, b );
	b.parentNode.removeChild( b );

	/* move b to old a position */
	if( nextA )
		parentA.insertBefore( b, nextA );
	else
		parentA.appendChild( b );
}

function urlEncodeString( inp )
{
	/* prevent encoding of numbers */
	if( !inp.replace )
		return inp;

	inp = inp.replace(/&/g, "%26");
	inp = inp.replace(/=/g, "%3D");
	inp = inp.replace(/\?/g, "%3F");
	return inp;
}

function urlEncode( parameters )
{
	var retter = "";
	var separator = "";
	for( key in parameters )
	{
		retter += separator + key + "=" + urlEncodeString( parameters[key] );
		separator = "&";
	}

	return retter;
}

function deleteChildren( element )
{
	while( element.firstChild )
		element.removeChild( element.firstChild );
}

function html_entity_decode( str )
{
	var textarea = document.createElement('textarea');
	textarea.innerHTML = str.replace(/</g, '&lt;').replace(/>/g, '&gt;');
	var retter = textarea.value;
	textarea = null;	/* "free" instance */
	return retter;
}

