// JavaScript Document

function asMessage(type)
{
	this.type = 0;
	this.remoteFunc = "";
	this.resCB = undefined;
	this.data = undefined;
	this.userdate = undefined;
	this.sendType = 0;
	
	if(type != undefined) this.type = type;
	
}

asMessage.prototype.IDLE 			= 0;
//asMessage.prototype.JS_CHECK 		= 1;
asMessage.prototype.AS_FUNC_CALL 	= 2;
asMessage.prototype.AS_FUNC_RESULT 	= 3;
asMessage.prototype.JS_FUNC_CALL 	= 4;
asMessage.prototype.JS_FUNC_RESULT 	= 5;

asMessage.prototype.AS_FUNC_CALL_NO_RESULT 	= 6; //Msg is a function call coming from JS calling an AS function JS doesn't wait for a result
asMessage.prototype.JS_FUNC_CALL_NO_RESULT 	= 7;

asMessage.prototype.SEND_TYPE_NONE	= 0; //nothing to send
asMessage.prototype.SEND_TYPE_ONEWAY	= 1; //Message has to be sent but no response will come back
asMessage.prototype.SEND_TYPE_REQUEST	= 2; //Message has to be sent and we have to wait for a response
	

asMessage.prototype.setCallData = function(remoteF,params,callback,userd)
{
  if(callback == undefined)
	{
		this.type = this.AS_FUNC_CALL_NO_RESULT;
	}
	else
	{
		this.type = this.AS_FUNC_CALL;
	}
	this.remoteFunc = remoteF;
	this.data = params;
	this.userdata = userd;
	this.resCB = callback;
}

asMessage.prototype.getSendType = function()
{
	switch(this.type)
	{
		case this.AS_FUNC_CALL_NO_RESULT:
		case this.JS_FUNC_RESULT:
			return this.SEND_TYPE_ONEWAY;
			
		case this.AS_FUNC_CALL:
			return this.SEND_TYPE_REQUEST;
	}
	return this.SEND_TYPE_NONE;
}

/* This function should be called to get the encoded data of the message.
	It will expect that the data is sent afterwards and adapt ist internal state */
asMessage.prototype.getSendData = function()
{
	var postType = this.type;
	var out = new Object();
	var strOut = "";
	out.type = this.type;
	var outStr;
	switch(this.type)
	{
		case this.AS_FUNC_CALL:
			out.func = this.remoteFunc;
			out.data = this.data;
			break;
		case this.AS_FUNC_CALL_NO_RESULT:
			out.func = this.remoteFunc;
			out.data = this.data;
			postType = this.IDLE;
			break;
		case this.JS_FUNC_RESULT:
			out.data = this.data;
			postType = this.IDLE;
			break;
		default:
			alert("Unexpected msgType: "+this.type);
			return;
	}
	outStr = this.serializeData(out,"data");
	this.type = postType;
	return outStr;
}
	
asMessage.prototype.onData = function(src)
{
	var msg = new Object();
	/*if(src.search(/hallo/) && fc++ < 8)
	{
		alert("Found "+src);
	}*/
	this.unserializeData(src,msg);
	msg = msg.data;
	this.type = msg.type;
	switch(msg.type)
	{
		case this.IDLE:
			alert("IDLE arrived");
			return;
		case this.JS_CHECK:
			alert("ERROR CHECK arrived");
			return;
		case this.JS_FUNC_CALL:
			//We have to call the function and return the result
			var func = eval(msg.func);
			this.data = undefined;
			if(func != undefined)
			{
				this.data = func.apply(null,msg.data);
			}
			this.type = this.JS_FUNC_RESULT;
			break;
		case this.JS_FUNC_CALL_NO_RESULT:
			//We have to call the function and return the result
			var func = eval(msg.func);
			this.data = undefined;
			if(func != undefined)
			{
				func.apply(null,msg.data);
			}
			this.type = this.IDLE;
			break;
		case this.AS_FUNC_RESULT:
			if(typeof(this.resCB) == "function")
			{
				this.resCB.call(null,msg.data,this.userdata);
			}
			this.type = this.IDLE;
			break;
		default:
			alert("unexpected receiveType: "+this.type);
	}
}
//asMessage.prototype.onData = asMessage_onData;
				
	
	/* serializes Any Datatype into a string */
asMessage.prototype.serializeData = function(item,name)
{
	var itype = typeof(item);
	var res = "";
	var i;
	switch(itype)
	{
		case "number":
			res = "<N"+name+":"+item+">";
			break;
		case "boolean":
			res = "<B"+name+":"+((item==true)?"1":"0")+">";
			break;
		case "string":
			var tmp = item;
			tmp = tmp.replace(/&/g,"&amp;");
			tmp = tmp.replace(/</g,"&lt;");
			tmp = tmp.replace(/>/g,"&gt;");
			res = "<S"+name+":>"+tmp+"</S>";
			break;
		case "undefined":
			res = "<U"+name+":>";
			break;
		case "object":
		  var isArr = true;
  		for (var n in item)
  		{
  		  res+=this.serializeData(item[n],n);
  			if(n == 'length') isArr = false;
  		}
		  if(isArr && typeof(item.length) == 'number')
		  {
		    res = "<A"+name+":>"+res+"</A>";
      }
      else
      {
        res = "<O"+name+":>"+res+"</O>";
      }
		  
			/*if(item instanceof Array)
			{
				res = "<A"+name+":>";
				for(i=0;i<item.length;i++)
				{
					res+=this.serializeData(item[i],i.toString());
				}
				res+= "</A>";
			}
			else if(item instanceof Object)
			{
				var n;
				res = "<O"+name+":>";
				for(n in item)
				{
					res+=this.serializeData(item[n],n);
				}
				res+="</O>";
			}
			else
			{
				alert("Unsupported Object "+itype + (item instanceof Object));
			}*/
			break;
		case "function":
			res = "";
			break;
			
		default:
			alert("Unsupported Type: "+itype+" "+name);
	}
	return res;
}
	
asMessage.prototype.unserializeData = function(src,res,startPos)
{
	if(startPos == undefined) startPos = 0;
	var endPos = src.indexOf(">",startPos)+1;
	// getting the type
	var itype = src.charAt(startPos+1);
	//var closed:Boolean = (src.charAt(endPos-1) == "/");
	
	var tp1;
	var tp2;
	
	res.name = "";
	tp1 = src.indexOf(":",startPos)+1;
	res.name = src.substr(startPos+2,tp1-startPos-3);
		
	var t;
	switch(itype)
	{
		case "N": //Number
			//t= src.substr(tp1,endPos-tp1-1);
			res.data = Number(src.substr(tp1,endPos-tp1-1));
			break;
		case "B": //Boolean
			res.data = Boolean(src.substr(tp1,endPos-tp1-1));
			break;
		case "U": //Boolean
			res.data = undefined;
			break;
		case "S": //String
			tp1 = endPos;
			endPos = src.indexOf("</S>",tp1)+4;
			res.data = src.substr(tp1,endPos-tp1-4);
			res.data.replace("&lt;","<");
			res.data.replace("&gt;",">");
			res.data.replace("&amp;","&");
			break;
		case "A": //Array
			var tmp = new Object();
			res.data = new Array();
			tp1 = endPos;
			while(src.substr(tp1,4) != "</A>")
			{
				tp1=this.unserializeData(src,tmp,tp1);
				res.data.push(tmp.data);
			}
			endPos = tp1 + 4;
			break;
		case "O": //Object
			var tmp = new Object();
			res.data = new Object();
			tp1 = endPos;
			while(src.substr(tp1,4) != "</O>")
			{
				tp1=this.unserializeData(src,tmp,tp1);
				res.data[tmp.name] = tmp.data;
			}
			endPos = tp1 + 4;
			break;
		default:
			alert("Unsupported type: "+itype);
	}
		
	return endPos;
}
