// Requires: aserializer.js
// Requires: axmlserializer.js
// Requires: ajax-request.js

function PacketType(v) { this.value_ = v; }
PacketType.prototype.Value = function() { return this.value_; }
PacketType.ConvertFromInt = function(t) {
	switch (t) {
		case 0: return PacketType.UNDEFINED;
		case 1: return PacketType.REQUEST;
		case 2: return PacketType.RESPONSE;
		case 3: return PacketType.EVENT;
		case 4: return PacketType.ERROR;
		case 5: return PacketType.COMMIT;
		case 6: return PacketType.ROLLBACK;
	}
	ThrowError("GetPacketType: Invalid packet type passed ("+t+"). ");
	return null;
}

PacketType.UNDEFINED = new PacketType(0);
PacketType.REQUEST   = new PacketType(1);
PacketType.RESPONSE  = new PacketType(2);
PacketType.EVENT     = new PacketType(3);
PacketType.ERROR     = new PacketType(4);
PacketType.COMMIT    = new PacketType(5);
PacketType.ROLLBACK  = new PacketType(6);


// Call method (POST or GET)
function CallType(v) { this.value_ = v; }
CallType.prototype.Value = function() { return this.value_; }
CallType.UNDEFINED = new CallType("UNKNOWN");
CallType.GET = new CallType("GET");
CallType.POST = new CallType("POST");

var APacket = Class.create({
initialize: function(oOptions) {
	if (!oOptions) oOptions = {};
	this.type_ = PacketType.REQUEST;
	this.sReceiverContainer_ = (oOptions.Cont) ? oOptions.Cont : "INVALID_CONT_NAME";
	this.sReceiverObject_ = (oOptions.Obj) ? oOptions.Obj : "INVALID_OBJ_NAME";
	this.sReceiverMethod_ = (oOptions.Method) ? oOptions.Method : "INVALID_METHOD_NAME";
	this.sSenderContainer_ = (oOptions.SenderCont) ? oOptions.SenderCont : "JavaX";
	this.sSenderObject_ = (oOptions.SenderObj) ? oOptions.SenderObj : "JavaXObject";
	this.oEnvelope_ = (oOptions.Envelope) ? oOptions.Envelope : new Object();
	this.oData_ = (oOptions.Data) ? oOptions.Data : new Object();
},

// getters
Type: function() { return this.type_; },
Data: function() { return this.oData_; },
Envelope: function() { return this.oEnvelope_; },
SenderContainer: function() { return this.sSenderContainer_; },
SenderObject: function() { return this.sSenderObject_; },
ReceiverContainer: function() { return this.sReceiverContainer_; },
ReceiverObject: function() { return this.sReceiverObject_; },
ReceiverMethod: function() { return this.sReceiverMethod_; },
Messages: function() { return this.oMessages_; },

// setters
SetType: function(type) { this.type_ = type; },
SetData: function(oData) { this.oData_ = oData; },
SetEnvelope: function(oEnvelope) { this.oEnvelope_ = oEnvelope; },
SetSenderContainer: function(sSenderContainer) { this.sSenderContainer_ = sSenderContainer; },
SetSenderObject: function(sSenderObject) { this.sSenderObject_ = sSenderObject; },
SetReceiverContainer: function(sReceiverContainer) { this.sReceiverContainer_ = sReceiverContainer; },
SetReceiverObject: function(sReceiverObject) { this.sReceiverObject_ = sReceiverObject; },
SetReceiverMethod: function(sReceiverMethod) { this.sReceiverMethod_ = sReceiverMethod; },

// serialization
Serialize: function(oS) {
	oS.BeginType("APacket");
	oS.Serialize(this.type_.Value()); // int
	oS.Serialize(this.sReceiverContainer_);
	oS.Serialize(this.sReceiverObject_);
	oS.Serialize(this.sReceiverMethod_);
	oS.Serialize(this.sSenderContainer_);
	oS.Serialize(this.sSenderObject_);
	oS.Serialize(this.oEnvelope_); // Value
	oS.Serialize(this.oData_); // Value
	if (typeof (this.oMessages_) != "undefined") os.Serialize(this.oMessages_);
	oS.EndType("APacket");
},

Restore: function(oR) {
	oR.BeginType("APacket");
	this.type_ = PacketType.ConvertFromInt(oR.Restore().Value());
	this.sReceiverContainer_ = oR.Restore();
	this.sReceiverObject_ = oR.Restore();
	this.sReceiverMethod_ = oR.Restore();
	this.sSenderContainer_ = oR.Restore();
	this.sSenderObject_ = oR.Restore();
	this.oEnvelope_ = oR.Restore();
	this.oData_ = oR.Restore();
	this.oMessages_ = new MessageList();
	if (oR.GetType() == "list") this.oMessages_.Restore(oR);
	else if (oR.GetType() == "Message"){ // for backwards compatibility
		this.oMessages_.AddMessage(oR.Restore());
	}
	oR.EndType("APacket");
},

/**
  * Performs async server call (transmits APacket to SWS)
  * @param oSO - send options (HTTP method, exception handlers, etc)
  */
Send: function(oSO) {
	if (oSO.Type == CallType.POST) {
		var sURL = "/srv";
		if (oSO.bNoLogin) sURL = "/nologin"+sURL;
		var sPacket = XMLSerialize(this);
		var oHeaders = new Object();
		oHeaders["X-Content-Type"] = "APacket";
		new AjaxRequest("POST", sURL, sPacket, {
			onSuccess: oSO.onSuccess,
			thisObject: oSO.thisObject,
			headers: oHeaders
		});
	} else if (oSO.Type == CallType.GET) {
		alert("This method is unsupported for APacket calls. ");
		throw Error("This method is unsupported for APacket calls. ");
	} else {
		throw Error("APacket: Unknown call type. ");
	}
}

});

/**
  * Interface for server calls
  *
  **/
var ServerCall = Class.create({
initialize: function(sURL, sParams, oSO, bAsync) {
	if (typeof(sParams) == "object") sParams = URLSerializeVS(sParams);
	if (oSO.onSuccess) {
		this.onSuccess_ = (oSO.thisObject) ? oSO.onSuccess.bind(oSO.thisObject) : oSO.onSuccess;
	}
	if (oSO.onException) {
		this.onException_ = (oSO.thisObject) ? oSO.onException.bind(oSO.thisObject) : oSO.onException;
	}
	// For some reason, IE does not encode Unicode characters properly in URL,
	// so we will use POST instead of GET
	new AjaxRequest("POST", sURL, sParams, {
		onSuccess: this.OnSuccess,
		onException: this.OnException,
		thisObject: this
	}, bAsync);
},

OnSuccess: function(oAjaxRequest) {
	// first, check if we received APacket
	var oXML = oAjaxRequest.XML();
	if (!oXML.documentElement) {
		this.Throw("No XML data. ", null);
		return;
	}
	var xRoot = oXML.documentElement;
	if (xRoot.nodeName != "xmlstream" || !xRoot.firstChild || xRoot.firstChild.nodeName != "APacket") {
		this.Throw("Server reply does not contain valid APacket. ", null);
		return;
	}
	// we have APacket
	var oPacket;
	try {
		oPacket = XMLRestore(oXML);
	} catch (e) {
		this.Throw("APacket restoring problem: "+ e.message, null);
		return;
	}
	if (oPacket.Type() == PacketType.ERROR) {
		// Packet contains exception
		var oData = oPacket.Data();
		var sErrorText = oData["ExceptionText"];
		// unsigned int lies in ErrorCode
		var nErrorCode = (typeof(oData["ErrorCode"]) != 'undefined') ? oData["ErrorCode"].Value() : undefined;
		this.Throw(sErrorText, nErrorCode);
		return;
	}
	var messagelist = oPacket.Messages();
	if (messagelist instanceof MessageList) messagelist.GetMessages().each(GlobalMessageProcessor.ProcessMessage, GlobalMessageProcessor);
	// real success :)
	if (this.onSuccess_) this.onSuccess_(oPacket);
},

OnException: function(oAjaxReq) {
	if (this.onException_) this.onException_(oAjaxReq.Error(), oAjaxReq.ErrorCode());
},

Throw: function(sMessage, nErrorCode) {
	// nErrorCode can be null
	if (this.onException_) this.onException_(sMessage, nErrorCode);
}

});

