/************************* CommandDataUnit *********************/
/*
 * collection for javascript-php-communication
 * needed for sending attributes of simple type to php
 * key and value will base64 encode
 */

function CommandDataUnit(pKey, pValue){
	var supportedTypes = new Array("string", "number", "boolean");
	if(pValue == null){
		pValue = "null";
	}
	var vtype = typeof(pValue);
    if(typeof(pKey) != "string" || !supportedTypes.inArray(typeof(pValue))){
        throw "key or value has wrong type for constructor of CommandDataUnit";
    }
	this.key = Base64.encode(pKey);
	if(vtype == "boolean"){
		switch (pValue) {
			case true:
				this.value = "true";
				break;
			case false:
				this.value = "false";
				break;
		}
	}else{
		this.value = pValue;
	}
	this.value = Base64.encode(this.value);
}

CommandDataUnit.prototype.get_key = function(){
	return this.key;
}

CommandDataUnit.prototype.get_value = function(){
	return this.value;
}

CommandDataUnit.prototype.toXML = function(){
	var xml = "<re4:CommandDataUnit><re4:key>"+this.key+"</re4:key><re4:value>";
	if(this.value != undefined){
		xml += this.value;
	}
	xml += "</re4:value></re4:CommandDataUnit>";
    return xml;
}

/************************* Commander *********************/

/*
 * class for javascript-php-communication
 * needed for sending xml data to RE4-Command-API
 * @param mode send mode GET or POST
 * @param callbackObj
 */
function Commander(){
	if(!Commander.privateCall){
		throw "Commander is a Singleton class, please call Commander.getInstance()";
	}
	Commander.sendMode = "POST";
	Commander.commands = new Array();
}

Commander.getInstance = function(){
	Commander.privateCall = true;
	if(Commander.instance == undefined){
		Commander.instance = new Commander();
	}
	Commander.privateCall = false;
	return Commander.instance;
}

Commander.prototype.set_sendMode = function(mode){
	if(mode.toUpperCase() == "POST" || mode.toUpperCase() == "GET"){
		Commander.sendMode = mode.toUpperCase();
	}else{
		Commander.sendMode = "POST";
	}
}

Commander.prototype.get_sendMode = function(){
	return Commander.sendMode;
}

Commander.prototype.registerCommand = function(com, http){
	if(typeof(com.handleCommanderEvents) != "function"){
		var type = getExactType(com);
		throw "callback object \""+type+"\" has no handleCommanderEvents method";
	}
	var comSet = new Array(com, http);
	Commander.commands.push( comSet );
}

Commander.prototype.getCommand = function(http){
	var com = null;
	for(var i = 0; i < Commander.commands.length; i++){
		var storedHttp = Commander.commands[i][1];
		if (storedHttp === http) {
			com = Commander.commands[i][0];
			break;
		}
	}
	return com;
}

Commander.prototype.getServiceBySAP = function(sap, flags, data, command){
	var http = this.getHTTPObject();
	if(http) {
		if(typeof(sap) != "string" || sap == null){
			throw "string required for first argument in Commander.getServiceBySAP()";
		}
		var params = 'com='+sap;
		if(flags != null){
			if(typeof(flags) == "string"){
				params += '&comFlags='+flags;
			}
		}
		if(data != null){
			if(typeof(data.toXML) == "function"){
				params += '&comData='+data.toXML();
			}else if(typeof(data.toXML) == "string"){
				params += '&comData='+data;
			}else{
				throw "string or Collection (with toXML method) required for third argument \"data\" in Commander.getServiceBySAP()";
			}
		}
		if(sid != undefined){
			params += '&sid='+sid;
		}
		if(pid != undefined){
			params += '&pid='+pid;
		}
		if(typeof re4SAP != "undefined"){
			var sap_url = re4SAP;
		}else{
			throw "Commander can�t communicate with re4 backend, because re4SAP is unknown";
		}
		if(Commander.sendMode == "POST"){
			http.open(Commander.sendMode, sap_url, true);
		}else{
			http.open(Commander.sendMode, sap_url+'?'+params, true);
		}
		http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');

		if(command != null){
			var com = Commander.getInstance();
			com.registerCommand(command, http);
			http.onreadystatechange = function () {
				var com = Commander.getInstance();
				var command = com.getCommand(http);
				try{
					if(o.conn.status !== undefined && o.conn.status != 0){
						var httpStatus = http.status;
					}else{
						var httpStatus = 13030;
					}
				}catch(e){
					// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
					// when the http object's status and statusText properties are
					// unavailable, and a query attempt throws an exception.
					var httpStatus = 13030;
				}				
				var readyState = http.readyState;
    			var responseText = '';
    			if(readyState == 4){
     				responseText = http.responseText;
    			}
    			command.handleCommanderEvents(readyState, responseText, httpStatus);
		    }
		}
		
		/*
		// Test communication
		http.onreadystatechange = function () {
       		alert(http.readyState);
       		if (http.readyState == 4) {
	          //document.getElementById("DG_content").innerHTML = http.responseText;
	          document.getElementById("DG_content").innerHTML = "Hello World!";
	        }
	    }
	    */
	    
		if(Commander.sendMode == "POST"){
			http.send(params);
		}else{
			http.send('');
		}
     }
}

Commander.prototype.getHTTPObject = function(){
	var xhttp = null;
	if (window.ActiveXObject){
         try{
            //Internet Explorer 6.x and 7.x
             xhttp = new ActiveXObject("Msxml2.XMLHTTP");
         }catch(e){
             //IE 5.x
             try{
                 xhttp = new ActiveXObject("Microsoft.XMLHTTP");
             }catch(e){
                 xhttp = false;
             }
         }
     } else if(window.XMLHttpRequest) {
         // Fuer Mozilla, Opera und Safari
         try{
             xhttp = new XMLHttpRequest();
         }catch(e){
             xhttp = false;
         }
     }
     return xhttp;
}

/************************* Commands (Callback Classes) *********************/

/*
 * replace a html layer with the response of server
 */
function CommanderCallbackObj(){
}

/*
 * abstract method listen for commander events (http request state and response)
 */
CommanderCallbackObj.prototype.handleCommanderEvents = function(state, response, httpStatusCode){
	// abstract
}

/*
 * load RE4Components from server
 * and insert the source code in a specified layer
 */

function RE4ComponentLoader(){
	this.eventContext = null;
	this.data = null;
	this.state = null;
	this.httpStatusCode = null;
	this.observers = new HashSet();
}

// inherit all methodes from CommanderCallbackObj
RE4ComponentLoader.prototype = new CommanderCallbackObj(null);

RE4ComponentLoader.prototype.load = function(component){
	var os = new ObjectSet();
	var cdu = new CommandDataUnit('component', component);
	os.add(cdu);
	var com = Commander.getInstance();
	com.getServiceBySAP("GetRE4Component", 'b', os, this);
}

RE4ComponentLoader.prototype.handleCommanderEvents = function(state, response, httpStatusCode){
	this.data = response;
	this.state = state;
	this.httpStatusCode = httpStatusCode;
	this.notifyObservers();
}

RE4ComponentLoader.prototype.notifyObservers = function(){
	var it = this.observers.iterator();
	while(it.hasNext()){
		var obs = it.getNext();
		obs.update(this);
	}
}

RE4ComponentLoader.prototype.registerObserver = function(obs){
	if(typeof(obs.update) != "function"){
		var type = getExactType(cbObj);
		throw "\""+type+"\" can´t register observer, because it has no update method";
	}else{
		this.observers.add(obs);
	}
}

RE4ComponentLoader.prototype.removeObserver = function(obs){
	this.observers.remove(obs);
}

RE4ComponentLoader.prototype.get_data = function(){
	return this.data;
}

RE4ComponentLoader.prototype.get_state = function(){
	return this.state;
}
