/**
* Provides a client for SOAP-communication
*
* @package Ceasy_Core
* @author Ralf Glaser
*
*
*/

// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
function MadChickSoapClientParameters(parameters) {

	this._parameters = {};

	// -------------------------------------------------------------------
	this.addData = function(name, value) {

		this._parameters[name] = value;
		return this;

	};

	// -------------------------------------------------------------------
	this.toXml = function()	{

		return this._arrayToXml(this._parameters);

	};

	// *****************************************************************
	// ******************** for internal use only **********************
	// *****************************************************************

	// -------------------------------------------------------------------
	this._arrayToXml = function(value, parentTagName)	{

		var xml='';
		var valueArray={};

		parentTagName=parentTagName || 'noParentTagName';

		for(var index in value) {

			var tagName=index;
			var sPos=tagName.indexOf('[');

			if (sPos>-1) {

				var ePos=tagName.indexOf(']');
				var thisTagName=tagName.substring(0, sPos);
				var firstSubTagName=tagName.substring(sPos+1, ePos);
				var nameRest=tagName.substring(ePos+1, 10000);

				if (!valueArray[thisTagName]) {
					valueArray[thisTagName]={};
				}

				var furtherSubTagNames=[];

				while (nameRest && nameRest.indexOf('[')==0) {
					ePos=nameRest.indexOf(']');
					furtherSubTagNames.push(nameRest.substring(1, ePos));
					nameRest=nameRest.substring(ePos+1, 10000);
				}

				if (furtherSubTagNames.length>0) {

					if (!valueArray[thisTagName][firstSubTagName]) {
						valueArray[thisTagName][firstSubTagName]={};
					}

					if (furtherSubTagNames.length==1) {
						valueArray[thisTagName][firstSubTagName][furtherSubTagNames[0]]=value[index];
					}

					if (furtherSubTagNames.length==2) {
						if (!valueArray[thisTagName][firstSubTagName][furtherSubTagNames[0]]) {
							valueArray[thisTagName][firstSubTagName][furtherSubTagNames[0]]={};
						}
						valueArray[thisTagName][firstSubTagName][furtherSubTagNames[0]][furtherSubTagNames[1]]=value[index];
					}

					if (furtherSubTagNames.length==3) {
						if (!valueArray[thisTagName][firstSubTagName][furtherSubTagNames[0]]) {
							valueArray[thisTagName][firstSubTagName][furtherSubTagNames[0]]={};
						}
						if (!valueArray[thisTagName][firstSubTagName][furtherSubTagNames[0]][furtherSubTagNames[1]]) {
							valueArray[thisTagName][firstSubTagName][furtherSubTagNames[0]][furtherSubTagNames[1]]={};
						}
						valueArray[thisTagName][firstSubTagName][furtherSubTagNames[0]][furtherSubTagNames[1]][furtherSubTagNames[2]]=value[index];
					}

				} else {
					valueArray[thisTagName][firstSubTagName]=value[index];
				}

			} else {
				valueArray[tagName]=value[index];
			}

		}

		for(var valueName in valueArray) {

			var tagName=valueName;
			tagName=tagName.replace(/[^a-zA-Z0-9_]/g, '');

			if (!isNaN(parseInt(tagName))) {
				tagName=parentTagName.substring(0, parentTagName.length-1);
			}

			xml+='<'+tagName+'>';
			var vType=typeof(valueArray[valueName]);

			if (vType=='string') {
				xml+=valueArray[valueName].replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
			} else if (vType=='object') {
				xml+=this._arrayToXml(valueArray[valueName], valueName);
			} else if (vType=='number') {
				xml+=valueArray[valueName];
			}

			xml+='</'+tagName+'>';

		}

		return xml;

	};

	//--- Constructor ---------------------------------------------------------------
	this._init=function()  {

	};

	// call constructor
	this._init();

}

// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
function MadChickSoapClient(wsdlUrl, masterYodaObj)  {

	var self=this;

	this._wsdlUrl=wsdlUrl;
	this._webserviceNs=false;
	this._webserviceUrl=false;
	this._webserviceCookie=false;
	this._masterYoda=(masterYodaObj || madChickMasterYoda);

	/*********************/
	/*    public         */
	/*********************/

	// -------------------------------------------------------------------
	this.request= function(method, parameters, async, callback)  {

		if (!parameters) {
			parameters=new MadChickSoapClientParameters();
		}

		if (async) {
			this._sendRequest(method, parameters, async, callback);
		} else {

			var result=this._sendRequest(method, parameters);

			if (typeof(result)!='string') {

				var infoNode=MadChickDomDoc.selectSingleNode(result, '/info');

				if (infoNode) {

					var infoData=XMLArrayizer.xmlToArray(infoNode);
					alert(infoData['message']+(infoData['data'] ? '\n\nWeitere Informationen finden Sie im Log.' : ''));

					if (infoData['data']) {
						if (this._masterYoda) {
							this._masterYoda.getProtocol().protocolMsg('MadChickSoapClient::request(\''+method+'\'): Server returned info-message:\n'+infoData['message']+(infoData['data'] ? '\ndata:\n'+infoData['data'] : ''));
						} else {
							alert('MadChickSoapClient::request(\''+method+'\'): Server returned info-message:\n'+infoData['message']+(infoData['data'] ? '\ndata:\n'+infoData['data'] : ''));
						}
					}

					result=false;

				}

			}

			return result;

		}

	};

	// -------------------------------------------------------------------
	this.setCookie= function(cookie) {

		this._webserviceCookie=cookie;

	};


	// *****************************************************************
	// ******************** for internal use only **********************
	// *****************************************************************

	// --------------------------------------------------------------------------------
	this._sendRequest= function(method, parameters, async, callback)  {

		// build SOAP request
		var soapRequestXml=
			'<'+'?'+'xml version="1.0" encoding="utf-8" ?'+'>'+
			'<soap:Envelope '+
			'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '+
			'xmlns:xsd="http://www.w3.org/2001/XMLSchema" '+
			'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">'+
			'<soap:Body>'+
			'<'+method+' xmlns="'+this._webserviceNs+'">'+
			parameters.toXml()+
			'</'+method+'></soap:Body></soap:Envelope>';

		// send request
		var httpRequest = this._getHttpRequest();
		httpRequest.open('POST', this._webserviceUrl, (async ? true : false));

		var soapaction = this._webserviceNs+(this._webserviceNs.substr(this._webserviceNs.length-1, 1)!='/' ? '/' : '')+method;
		httpRequest.setRequestHeader('SOAPAction', soapaction);
		httpRequest.setRequestHeader('Content-Type', '"text/xml; charset=utf-8');

		if (this._webserviceCookie) {
			httpRequest.setRequestHeader('Cookie', this._webserviceCookie);
		}

		if (async) {
			httpRequest.onreadystatechange = function() {
				if(httpRequest.readyState == 4) {
					callback(self._evalResponse(method, httpRequest, soapRequestXml));
				}
			};
		}

		httpRequest.send(soapRequestXml);

		if (!async) {
			return this._evalResponse(method, httpRequest, soapRequestXml);
		}

	};

	// --------------------------------------------------------------------------------
	this._evalResponse = function(method, httpRequest, soapRequestXml) {

		var response=false;
		var faultMsg='MadChickSoapClient::_evalResponse(\''+method+'\'):\n';
		faultMsg+='POST-request to "'+this._webserviceUrl+'"\n';
		faultMsg+=(this._webserviceCookie ? 'Cookie: '+this._webserviceCookie+'\n' : '');
		faultMsg+='with payload:\n';
		faultMsg+=soapRequestXml+'\n';
		faultMsg+='failed:\n';

		var responseDoc=httpRequest.responseXML;

		if (httpRequest.status==200) {

			if (httpRequest.responseXML && (!responseDoc.parseError || responseDoc.parseError==0)) {

				var responseNode=MadChickDomDoc.selectSingleNode(responseDoc.documentElement, '//return');

				if(responseNode==null)	{

					this._logFault(faultMsg+'no return-node found: responseText:\n'+httpRequest.responseText);

				} else {

					if (responseNode.childNodes.length==1 && responseNode.childNodes[0].nodeType==3) { // only response-data is a text-node

						response= responseNode.childNodes[0].nodeValue;

					} else { // resonses is an element-node

						for (var i=0; i<responseNode.childNodes.length; i++) {

							// hack for gecko an it's stupid DOM with textNodes between the elementNodes
							if (responseNode.childNodes[i].nodeType==1) {
								response= MadChickDomDoc.factory(responseNode.childNodes[i].xml);
								break;
							}

						}

						if (!response) {
							this._logFault(faultMsg+'return-node has no childNodes: responseText:\n'+httpRequest.responseText);
						}

					}

				}

			} else {

				if (httpRequest.responseXML) {
					this._logFault(faultMsg+responseDoc.parseError.reason);
				} else {
					this._logFault(faultMsg+'returned no valid responseXml:\n'+httpRequest.responseText);
				}

			}

		} else {

			var faultStringNode=false;

			if (responseDoc && responseDoc.parseError==0) {
				faultStringNode=MadChickDomDoc.selectSingleNode(responseDoc.documentElement, '//faultstring');
			}

			if(faultStringNode) {
				this._logFault(faultMsg+'faultstring: '+faultStringNode.childNodes[0].nodeValue);
			} else {
				this._logFault(faultMsg+'HTTP-Status '+httpRequest.status+' - '+httpRequest.statusText);
			}

		}

		return response;

	};

	// --------------------------------------------------------------------------------
	this._getHttpRequest= function()  {

		if(typeof(XMLHttpRequest)!='undefined') {

			var httpRequest = new XMLHttpRequest();

			// some versions of Moz do not support the readyState property and the onreadystate event so we patch it!
			if(httpRequest.readyState == null) {

				httpRequest.readyState = 1;
				httpRequest.addEventListener('load',
					function() {
						httpRequest.readyState = 4;
						if(typeof httpRequest.onreadystatechange == 'function') {
							httpRequest.onreadystatechange();
						}
					}, false);

			}

			return httpRequest;

		} else if(window.ActiveXObject) {
			return new ActiveXObject(this._getHttpRequestProgID());
		}

		this._logFault('Your browser does not support XmlHttp objects');

	};

	// --------------------------------------------------------------------------------
	this._getHttpRequestProgID = function() {

		var progids = ['Msxml2.XMLHTTP.5.0', 'Msxml2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'];
		var o;

		for(var i = 0; i < progids.length; i++) {

			try	{
				o = new ActiveXObject(progids[i]);
				return progids[i];
			} catch (ex) {};

		}

		this._logFault('Could not find an installed XML parser');

	};

	// --------------------------------------------------------------------------------
	this._loadWsdl= function()  {

		if (this._masterYoda) {
			this._masterYoda.getCurtain().show('WSDL wird geladen', this._loadWsdl);
		}

		httpRequest = this._getHttpRequest();
		httpRequest.open('GET', this._wsdlUrl, false);
		httpRequest.send(null);
		this._onloadWsdl(httpRequest);

		if (this._masterYoda) {
			this._masterYoda.getCurtain().hide(this._loadWsdl);
		}

	};


	// --------------------------------------------------------------------------------
	this._onloadWsdl= function(httpRequest)  {

		var wsdlDoc=httpRequest.responseXML;

		if (wsdlDoc && wsdlDoc.documentElement && (!wsdlDoc.parseError || wsdlDoc.parseError==0)) {

			var soapBodyNode=MadChickDomDoc.selectSingleNode(wsdlDoc.documentElement, '//soap-env:address', {'soap-env':'http://schemas.xmlsoap.org/wsdl/soap/'});

			if (soapBodyNode) {
				this._webserviceUrl=soapBodyNode.getAttributeNode('location').nodeValue;
			} else {
				this._logFault('Could not extract service-url from wsdl-file');
			}

			this._webserviceNs=httpRequest.responseXML.documentElement.getAttribute('targetNamespace');

		} else {

			if (httpRequest.responseXML && httpRequest.responseXML.xml) {
				this._logFault='MadChickSoapClient::_onloadWsdl(): '+wsdlDoc.parseError.reason;
			} else {
				this._logFault='MadChickSoapClient::_onloadWsdl(): no valid responseXml '+httpRequest.responseText;
			}

		}

	};

	// --------------------------------------------------------------------------------
	this._logFault = function(faultString) {

		if (this._masterYoda) {
			alert('Bei der SOAP-Kommunikation ist ein Fehler aufgetreten.\n\nWeitere Informationen finden Sie im Log.');
			this._masterYoda.getProtocol().protocolError(faultString);
		} else {
			alert('Bei der SOAP-Kommunikation ist ein Fehler aufgetreten:n\n'+faultString);
		}

	};

	//--- Constructor ---------------------------------------------------------------
	this._init=function()  {
		this._loadWsdl();
	};

	// call constructor
	this._init();

}

