

/******************************************************************************

	[clientlibrary] soap.js

	Simple implementation of a jScript SOAP broker. The broker is capable or 
	transmitting simple arguments (strings) and return compound and simple
	types from the server.

	The current version has no associated schema information, so there is 
	no way to query the server for the capabilities of the publice webservices or
	to verify the structure of the compound types returned from the server.

	[author]		Ulf Johansen
	[version]		3.0
	[package]		clientcore

******************************************************************************/

///////////////////////////////////////////////////////////////////////////
//
// Globals
//
///////////////////////////////////////////////////////////////////////////

var g_nErrorState 		= 0;	// Global state to prevent endless loop
var g_strDebugTemplate 	= null; // Template for holding debug messages

///////////////////////////////////////////////////////////////////////////
//
// Public Functions
//
///////////////////////////////////////////////////////////////////////////


function SOAPDecodeType( objInstance )
{
	// Check for null elements
	var objNullAttribute = objInstance.attributes.getNamedItem( "xsi:null" );
	if ( objNullAttribute )
	{
		return null;
	}

	var strType = objInstance.attributes.getNamedItem( "xsi:type" ).nodeValue;
	switch ( strType )
	{
		case "xsd:string":
			return objInstance.text;

		case "xsd:xml":
			return objInstance.childNodes( 0 ).xml;

		case "xsd:int":
			return parseInt( objInstance.text );

		case "xsd:float":
			return parseFloat( objInstance.text );
		
		case "xsd:boolean":
			return objInstance.text == "true";

		case "SOAP-ENC:Array":
			var objResult = new Array();
			for ( var i = 0; i < objInstance.childNodes.length; i++ )
			{
				objResult[ i ] = SOAPDecodeType( objInstance.childNodes( i ) );
			}
			return objResult;

		default:

			var objResult = new Array();
			for ( var i = 0; i < objInstance.childNodes.length; i++ )
			{
				var strName		= objInstance.childNodes( i ).nodeName;
				var objValue	= SOAPDecodeType( objInstance.childNodes( i ) );

				objResult[ strName ] = objValue;
			}
			return objResult;
	}
}


/**********************************************************

	[function]	SOAPEncodeArgument

	Create SOAP encoding of a jScript variable argument

	[in]		objInstance		The jScript variable
	[in]		nIndex			Argument number

	[return]	The SOAP encoding of the jScript variable

**********************************************************/
function SOAPEncodeArgument( objArgument, nIndex )
{
	if ( objArgument == null )
	{
		return '<arg-' + nIndex + ' xsi:null="1"/>\n';
	}

	var strType = typeof( objArgument );
	switch( strType )
	{
		case "string":
			if ( objArgument.indexOf( "<![CDATA[" ) == -1 )
			{
				return '<arg-' + nIndex + ' xsi:type="xsd:string"><![CDATA[' + objArgument + ']]></arg-' + nIndex + '>\n';
			}
			else
			{
				// Make sure it is XML
				var objXML = ParseXML( objArgument );
				return '<arg-' + nIndex + ' xsi:type="xsd:xml">' + objArgument + '</arg-' + nIndex + '>\n';
			}

		case "number":
			if ( Math.floor( objArgument ) == objArgument )
			{
				return '<arg-' + nIndex + ' xsi:type="xsd:int">' + objArgument + '</arg-' + nIndex + '>\n';
			}
			else
			{
				return '<arg-' + nIndex + ' xsi:type="xsd:float">' + objArgument + '</arg-' + nIndex + '>\n';
			}

		case "boolean":
			return '<arg-' + nIndex + ' xsi:type="xsd:boolean">' + ( objArgument ? "true" : "false" ) + '</arg-' + nIndex + '>\n';

		default:
			// NOTE: functions, objects and arrays are not marshalled			
	}
}

function CallServer( strURL, strMethod, strEncoding, arg1, arg2, arg3, arg4, arg5, arg6, arg6, arg7, arg8 )
{
	var strConstHTTP = 'http';//backwrds comp issue...need to detect abs urlks and leave them unchanged
	// Construct SOAP envelope	
	var strXML =	'<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">\n' + 
					'	<SOAP-ENV:Body>\n' +
					'		<cms:' + strMethod + ' xmlns:cms="http://www.software-innovation.com/growBusiness/cms/rpc1.0">\n';

	for ( var i = 3; i < arguments.length; i++ )
	{
		strXML +=	'			' + SOAPEncodeArgument( arguments[ i ], ( i- 2 ) ) + '\n';
	}


	strXML +=		'		</cms:' + strMethod + '>\n' +
					'	</SOAP-ENV:Body>\n' +
					'</SOAP-ENV:Envelope>';

	// Call server
	var objHTTP = new ActiveXObject( "MSXML2.XMLHTTP" );

	if ( strURL.indexOf(strConstHTTP) != 0 )
	{

//TODO REMOVE:	alert( 'INFO: strURL is:' + strURL + '.\n' + 'strURL.indexOf("/") :' + strURL.indexOf("/") + '.' );

		//add SiteRootPath to given strURL, before strURL is being used
		//if strURL first-char is not a "/", raise an error/message (we should support the url-encoded value "%2F", also)
		if ( strURL.indexOf("/") != 0 ) {
			var strErrMsg = 'CallServer(): Usage error by programmer:\n\tstrURL is: ' + strURL + ', ' + 'strMethod is: ' + strMethod + '.';
			alert(strErrMsg);
			//should not throw exception when the callee does not catch: only brings up more system errors.
			//throw strErrMsg;
			return null;//needed
		}
//TODO REMOVE: else	alert( 'INFO: Input strURL relative and ok.' );

	//fails from QL Bar management...
	try
	{
		strURL = GetSiteRootPath() + strURL;
	}
	catch(e)
	{
		alert('Warning: contact a site administrator with this message:\n\tCallServer(): js-file not loaded.');
		//assume intranet-site configured as WebApp...
		strURL = "/_intranet" + strURL;
	}

//TODO REMOVE:	alert( 'INFO:\nstrURL is:' + strURL + '.\n' + 'strMethod :' + strMethod + '.' );

	}
	//else do nothing
//TODO REMOVE:	else {		alert('INFO: strURL is absolute: ' + strURL + '.');	}

	if ( strEncoding == "GET" )
	{
		objHTTP.open( "GET", strURL + "?" + strXML, false, null, null );
		objHTTP.setRequestHeader( "SOAPAction", strURL + "#" + strMethod );

		objHTTP.send();
	}
	else 
	{
		// Default for posting data to the server.
		objHTTP.open( "POST", strURL, false, null, null );
		objHTTP.setRequestHeader( "Content-Type", 'text/xml; charset="utf-8"' );
		objHTTP.setRequestHeader( "SOAPAction", strURL + "#" + strMethod );
		objHTTP.send( strXML );
	}

	var strErrMsg = "SOAP internal error: ";
	// Check the result
	if ( objHTTP.responseXML.parseError.errorCode == 0 )
	{
		var objBody = objHTTP.responseXML.selectSingleNode( "/SOAP-ENV:Envelope/SOAP-ENV:Body" );
		if ( objBody )
		{
			var objChild = objBody.childNodes( 0 );
			var strNodeName = objChild.nodeName;

			switch ( objChild.nodeName )
			{
				case  strMethod + "-Response":
					return SOAPDecodeType( objChild );
				
				case "SOAP-ENV:Fault":
					alert( strErrMsg + objChild.selectSingleNode( "detail" ).text );
					return null;
	
				default:
					alert( strErrMsg + "Unknown SOAP child name! Excepted: '" + strMethod + "-Response' but got '" + objChild.nodeName + "'" );
					return null;
			}
		}
		else
		{
			alert( strErrMsg + 'No SOAP-ENV:Body in response.\n' + 'Method :' + strMethod + ' failed.');
		}
	}
	else
	{
		alert( strErrMsg + objHTTP.responseXML.parseError.reason );
	}

	// If we get here, we got an error
	//the responseText may be a string containing complete html-markup "<html>..."
	//var strMarkupMsg =  objHTTP.responseText.replace( /</g, "&lt;" ).replace( />/g, "&gt;" );
	var strMarkupMsg =  objHTTP.responseText;
	//var elemBody = document.body;
	var elemCol = document.getElementsByTagName( "body" );
	var elemBody = elemCol[0];
	if ( elemBody )
	{
		elemBody.innerHTML = strMarkupMsg;
	}
	else
	{
		//this gives a empty white browser on most installations..:
		window.open( "", "" ).document.write( strMarkupMsg );
	}

	throw objHTTP.responseText;
	return null;
}

