/**
* Provides an SoapClient
*
* @package Ceasy_Core
* @author Ralf Glaser
*
*
*/

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

	this._paramters = {};

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

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

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

	}

	// -------------------------------------------------------------------
	this.toXml = function()	{
//alert(this._arrayToXml(this._paramters));
		return this._arrayToXml(this._paramters);

	}



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

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

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

		parentTagName=parentTagName || 'noParentTagName';

		for(var n in value) {

			var tagName=n
			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[n];

					}

					if (furtherSubTagNames.length==2) {

						if (!valueArray[thisTagName][firstSubTagName][furtherSubTagNames[0]]) {

							valueArray[thisTagName][firstSubTagName][furtherSubTagNames[0]]={};

						}

						valueArray[thisTagName][firstSubTagName][furtherSubTagNames[0]][furtherSubTagNames[1]]=value[n];

					}

					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[n];

					}

				} else {

					valueArray[thisTagName][firstSubTagName]=value[n];

				}

			} else {

				valueArray[tagName]=value[n];

			}

		}


		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();


}
