/**
 * LAjEDA - Lightweight AJAX Event-Driven Architecture
 *
 * LaMessage class
 * LaPage template class
 **/
 
function LaMessage()
{
	this.url = "";
	this.method = "POST";
	this.data = null;
	this.contentType = "application/x-www-form-urlencoded";
	this.nextMessage = null;
	this.onCompletion = null;
	this.state = null;
}

LaMessage.prototype.getNextMessage = function()
{
	return this.nextMessage;
}

LaMessage.prototype.newMessage = function()
{
	if( this.nextMessage != null ) {
		return this.nextMessage.newMessage();
	}
	
	this.nextMessage = new LaMessage();
	return this.nextMessage;
}

LaMessage.prototype.setUrl = function(url)
{
	this.url = url;
}

LaMessage.prototype.setOnCompletion = function(func)
{
	this.onCompletion = func;
}

LaMessage.prototype.setState = function(state)
{
	this.state = state;
}

LaMessage.prototype.initInvocationMessage = function(method, params)
{
	var objMessageBody = {
		events : new Array(),
		state : this.state
	};
	
	if( !params )
		params = new Array();

	objMessageBody.events[0] = {
		type : 101,
		arguments : {
			id : 0,
			rootArg : method,
			otherArgs : params
		}
	};

	this.method = "POST";
	this.data = objMessageBody.toJSONString( null );
	this.contentType = "application/x-www-form-urlencoded";
}

LaMessage.prototype.initCompInvocationMessage = function(compId, method, params)
{
	var objMessageBody = {
		events : new Array(),
		state : this.state
	};
	
	if( !params )
		params = new Array();
	
	objMessageBody.events[0] = {
		type : 102,
		arguments : {
			id : compId,
			rootArg : method,
			otherArgs : params
		}
	};

	this.method = "POST";
	this.data = objMessageBody.toJSONString( null );
	this.contentType = "application/x-www-form-urlencoded";
}

LaMessage.prototype.initEventMessage = function(eventType, eventArg)
{
	var objMessageBody = {
		events : new Array(),
		state : this.state		
	};
	
	objMessageBody.events[0] = {
		type : eventType,
		arguments : {
			id : 0,
			rootArg : eventArg,
			otherArgs : null
		}
	};
	
	this.method = "POST";
	this.data = objMessageBody.toJSONString( null );
	this.contentType = "application/x-www-form-urlencoded";
}

function LaPage()
{
	this.request = null;
	this.firstMessage = null;
	this.invocationTable = new Array();
	this.url = document.location;
	this.state = new Object();
	this.requestWatcher = null;
	this.defaultWatchTimeout = 60;
}

LaPage.prototype.newMessage = function()
{
	var msg;

	if( this.firstMessage == null ) {
		msg = new LaMessage();
		this.firstMessage = msg;
	} else {
		msg = this.firstMessage.newMessage();
	}

	return msg;
}

LaPage.prototype.onLoad = function()
{
	var msg = this.newMessage();
	
	msg.setUrl( this.url );
	msg.setState( this.state );
	msg.initEventMessage( 1, null );
	
	this.sendNextMessage();
}

LaPage.prototype.invoke = function(method, params, resultFunc)
{
	var msg = this.newMessage();
	
	msg.setUrl( this.url );
	msg.setState( this.state );
	msg.initInvocationMessage( method, params );
	msg.setOnCompletion( resultFunc );
	
	this.sendNextMessage();
}

LaPage.prototype.invokeComp = function(id, method, params, resultFunc)
{
	var msg = this.newMessage();
	
	msg.setUrl( this.url );
	msg.setState( this.state );
	msg.initCompInvocationMessage( id, method, params );
	msg.setOnCompletion( resultFunc );
	
	this.sendNextMessage();
}

LaPage.prototype.sendNextMessage = function()
{
	if( this.request != null ) return;
	
	var msg = this.firstMessage;
	if( msg == null ) return;

    if (window.XMLHttpRequest)
        this.request = new XMLHttpRequest();

    else if (window.ActiveXObject)
    {
        try {
			this.request = new ActiveXObject("Msxml2.XMLHTTP")
        } catch (e) {
			try{
				this.request = new ActiveXObject("Microsoft.XMLHTTP")
			} catch (e) {
				return false;
			}
        }
    }
    else {
        return false
    }

    this.request.onreadystatechange = function() {
		thePage.onResponse();
	}
    	
	this.request.open( msg.method, msg.url );
	
	if( msg.contentType != "" )
		this.request.setRequestHeader( "Content-type", msg.contentType );

	if( this.onWait )
		this.onWait( msg, true ); // start a "waiting for" sequence if defined

    this.request.send( msg.data );
	
	// start a timer to detect a timeout...
	this.requestWatcher = window.setTimeout( function () { thePage.onRequestTimeout(); }, (this.defaultWatchTimeout * 1000) );
}

LaPage.prototype.onRequestTimeout = function()
// this method is called when transaction timeout elapses without a result...
{
	// no more waiting
	if( this.onWait )
		this.onWait( this.firstMessage, false );

	if( this.onRequestTimedOut ) {
		// if defined, call the method that notifies the user about the matter
		this.onRequestTimedOut( this.request );
	}	
}

LaPage.prototype.applyStyle = function(element, styleName, styleValue)
{
	if( !element.style )
		return;

	if( element.style.setAttribute !== undefined ) {
		element.style.setAttribute( styleName, styleValue );
	} else {
		element.style[ styleName ] = styleValue;
	}
}

LaPage.prototype.setAttribute = function(element, attribute, value)
{
	if( !element ) return;
	
	switch( attribute.toLowerCase() ) {
		case	"innerhtml"		:
			if( element.innerHTML !== undefined )
				element.innerHTML = value;
			break;
			
		case	"innertext"		:
			if( element.innerText !== undefined )
				element.innerText = value;
			break;
			
		case	"selectedindex"	:
			if( element.options !== undefined ) {
				for( var j = 0; j < element.options.length; j ++ ) {
					if( (j != value) && ((value == -1) && (!element.options[j].defaultSelected)) )
						element.options[j].selected = false;
					else if( (j == value) || ((value == -1) && (element.options[j].defaultSelected)) )
						element.options[j].selected = true;
				}
			}
			break;
			
		case	"selectedvalue"	:
			if( element.options !== undefined ) {
				if( typeof( value ) === "object" ) {
					for( var v = 0; v < value.length; v ++ ) {
						for( var j = 0; j < element.options.length; j ++ ) {
							if( element.options[ j ].value == value[ v ] ) {
								element.options[ j ].selected = true;
								break;
							}
						}
					}
				} else {
					for( var j = 0; j < element.options.length; j ++ ) {
						if( element.options[ j ].value == value ) {
							element.options[ j ].selected = true;
							break;
						}
					}
				}
			}
			break;
			
		case	"options"		:
			if( (element.options !== undefined) && (value.length !== undefined) ) {
				element.options.length = 0;
				for( var j = 0; j < value.length; j ++ ) {
					element.options[ element.options.length ] = new Option( value[j].text, value[j].value );
					
					if( value[j].selected !== undefined ) {
						if( value[j].selected == true ) {
							element.options[ element.options.length - 1 ].selected = true;
						}
					}
				}
			}
			break;
			
		case	"checked"		:
			if( value == 1 )
				element.checked = true;
			else
				element.checked = false;
			break;
			
		case	"class"			:
			if( element.className !== undefined ) {
				element.className = value;
			} else {
				element.setAttribute( "class", value );
			}
			break;
			
		case	"value"			:
			var cls;
			
			if( element.className !== undefined )
				cls = element.className;
			else
				cls = element.getAttribute( "class" );
				
			if( (cls == "wysiwyg") && (tinyMCE !== undefined) ) {
				var editor = tinyMCE.get( element.id );
				
				if( editor ) {
					editor.setContent( value );
					return;
				}
			} 
						
			if( element.value !== undefined )
				element.value = value;
			else
				element.setAttribute( "value", value );
			break;
			
		case	"enabled"		:
			if( element.disabled !== undefined ) {
				element.disabled = ((value == true) ? false : true);
			} else {
				element.setAttribute( "disabled", (value == true) ? "" : "disabled" );
			}
			break;
			
		default:
			element.setAttribute( attribute, value );
			break;
	}
}

LaPage.prototype.parseTransaction = function(jsonString)
{
	var objResponse = null;
	
	try {
		objResponse = jsonString.parseJSON(null);
	} catch( exception ) {
		alert( "Invalid response from server: " + jsonString );
		return;
	}
	
	if( !objResponse ) return;
	
	// renew state
	this.state = objResponse.state;
	
	// attributes
	for( var j = 0; j < objResponse.dme.attributes.length; j ++ ) {
		var element = document.getElementById( objResponse.dme.attributes[ j ].id );
		
		if( element ) {
			if( objResponse.dme.attributes[ j ].attr == "style" ) {
				this.applyStyle( element, objResponse.dme.attributes[ j ].key, objResponse.dme.attributes[ j ].val ); 
				continue;
			}
			
			this.setAttribute( element, objResponse.dme.attributes[ j ].attr, objResponse.dme.attributes[ j ].val );
		}
	}
	
	if( (objResponse.invoke.result != null) && (this.firstMessage.onCompletion != null) )
		this.firstMessage.onCompletion( objResponse.invoke.result );
	
	// invokations
	for( var j = 0; j < objResponse.invoke.call.length; j ++ ) {
		var method = this.invocationTable[ objResponse.invoke.call[ j ].method ];
		
		if( method != null ) {
			if( this.invokeWithParams ) {
				this.invokeWithParams( method, objResponse.invoke.call[ j ].params );
			} else {
				method( objResponse.invoke.call[ j ].params );
			}
		} else {
			switch( objResponse.invoke.call[ j ].method ) {
				case	"openPopup"		:
					window.open( objResponse.invoke.call[ j ].params[0],
								 objResponse.invoke.call[ j ].params[1],
								 objResponse.invoke.call[ j ].params[2] );
					break;
					
				case	"redirect"		:
					document.location.href = objResponse.invoke.call[ j ].params[0];
					break;
			}
		}
	}
	
	if( objResponse.exception ) {
		alert( "Exception: " + objResponse.exception );
	}
	
	// return generically the result
	return objResponse.invoke.result;
}

LaPage.prototype.onResponse = function()
{
    if( (this.request.readyState == 4) &&
		(this.request.status==200 || window.location.href.indexOf("http")==-1))
    {
		if( this.onWait )
			this.onWait( this.firstMessage, false ); // and the "waiting for"

		// cancel timeout
		if( this.requestWatcher != null ) {
			window.clearTimeout( this.requestWatcher );
			this.requestWatcher = null;
		}

		var result = this.parseTransaction( this.request.responseText );
		
		if( this.firstMessage != null ) {
			this.firstMessage = this.firstMessage.getNextMessage();
		}
			
		this.request = null;
		
		if( this.firstMessage != null ) {
			this.sendNextMessage();
		}    
	}
}

LaPage.prototype.addValueToFormArray = function(arr, idx, value)
{
	if( arr[ idx ] ) {
		if( typeof arr[ idx ] === "object" ) {
			arr[ idx ][ arr[ idx ].length ] = value;
		} else {
			var first = arr[ idx ];
			arr[ idx ] = new Array( first, value );
		}
	} else {
		arr[ idx ] = value;
	}
}

LaPage.prototype.addValToArray = function(element, result)
{
	switch( element.type ) {
		case	"radio"				:
		case	"checkbox"			:
			if( element.checked == true )
				this.addValueToFormArray( result, element.name, element.value );
			break;

		case	"select-one"		:
			if( element.selectedIndex !== undefined ) {
				if( element.selectedIndex > -1 ) {
					if( element.options.length > element.selectedIndex ) {
						this.addValueToFormArray( result, element.name, element.options[ element.selectedIndex ].value );
					}
				}
			}
			break;

		case	"select-multiple"	:
			if( element.options ) {
				for( var o = 0; o < element.options.length; o ++ ) {
					if( element.options[ o ].selected ) {
						this.addValueToFormArray( result, element.name, element.options[ o ].value );
					}
				}
			}
			break;
			
		default						:
			var cls;
			
			if( element.className !== undefined )
				cls = element.className;
			else
				cls = element.getAttribute( "class" );
				
			if( (cls == "wysiwyg") && (tinyMCE !== undefined) ) {
				var editor = tinyMCE.get( element.id );
				
				if( editor ) {
					this.addValueToFormArray( result, element.name, editor.getContent() );
					return;
				}
			}

			if( element.value !== undefined )
				this.addValueToFormArray( result, element.name, element.value );
			break;
	}				
}

LaPage.prototype.formToArray = function(form)
{
	var result = new Object();

	for( var j = 0; j < form.length; j ++ ) {
		if( form[ j ].name !== undefined ) {
			if( form[ j ].name != "" ) {
				this.addValToArray( form[ j ], result );
			}
		}
	}
	
	return result;
}

LaPage.prototype.valuesToArray = function(arels)
{
	var result = new Object();
	
	for( var j = 0; j < arels.length; j ++ ) {
		var element = document.getElementById( arels[ j ] );
		if( !element ) continue;
		if( element.name != "" ) {
			this.addValToArray( element, result );
		}
	}
	
	return result;
}

LaPage.prototype.getDocMetrics = function()
{
	var metrics = {
		offX : 0,
		offY : 0,
		width : 0,
		height: 0
	};
	
	if( window.pageXOffset !== undefined ) {
		metrics.offX = window.pageXOffset;
	} else if( document.documentElement.scrollLeft !== undefined ) {
		metrics.offX = document.documentElement.scrollLeft;
	} else if( document.body.scrollLeft !== undefined ) {
		metrics.offX = document.body.scrollLeft;
	}

	if( window.pageYOffset !== undefined ) {
		metrics.offY = window.pageYOffset;
	} else if( document.documentElement.scrollTop !== undefined ) {
		metrics.offY = document.documentElement.scrollTop;
	} else if( document.body.scrollTop !== undefined ) {
		metrics.offY = document.body.scrollTop;
	}

	if( window.innerWidth ) {
		metrics.width = window.innerWidth ;
		metrics.height = window.innerHeight;
	} else if( document.documentElement.clientWidth ) {
		metrics.width = document.documentElement.clientWidth;
		metrics.height = document.documentElement.clientHeight;
	}
	
	return metrics;
}

