// WMSOAPWSDLClient.cpp: implementation of the WMSOAPWSDLClient class.
//
//////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003 Robert Cunnings. All rights reserved.
//
// You may copy, modify, distribute or publish this code free of charge.
//
// NO WARRANTY: This software is provided AS IS, without warranty of any kind.
//
//////////////////////////////////////////////////////////////////////
//
// WMSOAPWSDLClient class - implementation of WSDL client class
//  
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "WMSOAPWSDLClient.h"
#include "charencode.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

WMSOAPWSDLClient::WMSOAPWSDLClient()
{
	m_strUserAgent = "White Mesa WSDL Client/2.1 (C++ WSDL client library)";
	// 30 second socket timeout
	m_nHTTPTimeout = 30000;
}

WMSOAPWSDLClient::~WMSOAPWSDLClient()
{
}

bool WMSOAPWSDLClient::ReadServiceDesc(const wstring& wstrServiceName,
									   const wstring& wstrPortName,
									   const string& strWSDLFileURL)
{
	// be nice, convert any backslashes
	string strURL = strWSDLFileURL;
	string::size_type pos;
	for (pos = 0; pos < strURL.length(); pos++)
	{
		if (strURL[pos] == '\\')
		{
			strURL[pos] = '/';
		}
	}
	// store service and port names
	m_wstrServiceName = wstrServiceName;
	m_wstrPortName = wstrPortName;
	// set current doc base
	pos = strURL.rfind('/');
	m_strDocBase = strURL.substr(0, pos + 1);
	// http:// or file:// ?
	if ((pos = strURL.find("http://")) != string::npos)
	{
		string strWSDLHost;
		int nWSDLPort = 80;
		string strTemp = strURL.substr(pos + 7);
		pos = strTemp.find('/');
		string strWSDLFilename = strTemp.substr(pos);
        // accomodate proxied requests
        string::size_type pos2;
	    if ((pos2 = strWSDLFilename.find("http://")) != string::npos)
	    {
            strWSDLFilename = strWSDLFilename.substr(pos2);
        }
		strTemp = strTemp.substr(0, pos);
		if ((pos = strTemp.find(':')) != string::npos)
		{
			// port specified explicitly
			nWSDLPort = atoi(strTemp.substr(pos + 1).c_str());
			strWSDLHost = strTemp.substr(0, pos);
		}
		else
		{
			strWSDLHost = strTemp;
		}
		if (GetAndParseWSDLFile(strWSDLHost,
								strWSDLFilename,
								m_strUserAgent,
								m_strHTTPHeaders,
								nWSDLPort,
								m_nHTTPTimeout) == false)
		{
			return false;
		}
	}
	else if ((pos = strURL.find("file://")) != string::npos)
	{
		string strWSDLFilename = strURL.substr(pos + 7);
		if (LoadAndParseWSDLFile(strWSDLFilename) == false)
		{
			return false;
		}
	}
	else
	{
		return false;
	}
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the SOAP address
	if (pWSDLDesc->GetSOAPDefinitions().GetSOAPAddress(	m_wstrServiceName,
													m_wstrPortName,
													pWSDLDesc->GetDefinitionsTNS(),
													m_wstrSOAPAddress) == false ||
													m_wstrSOAPAddress.length() == 0)
	{
		// service and port not found
		return false;
	}
	// found it
	m_nSOAPHTTPPort = 80;
	wstring wstrTemp = m_wstrSOAPAddress;
	wstring::size_type wpos;
	wpos = wstrTemp.find(L"://");
	wstrTemp = wstrTemp.substr(wpos + 3);
	wpos = wstrTemp.find(wchar_t('/'));
	m_wstrSOAPSvcURI = wstrTemp.substr(wpos);
	wstrTemp = wstrTemp.substr(0, wpos);
	if ((wpos = wstrTemp.find(wchar_t(':'))) != wstring::npos)
	{
		// port specified explicitly
		m_nSOAPHTTPPort = _wtoi(wstrTemp.substr(wpos + 1).c_str());
		m_wstrSOAPHost = wstrTemp.substr(0, wpos);
	}
	else
	{
		m_wstrSOAPHost = wstrTemp;
	}
	return true;
}

WMSOAPBindingHandler *WMSOAPWSDLClient::GetSOAPBinding()
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the binding object
	return pWSDLDesc->GetSOAPDefinitions().GetSOAPBinding(
											m_wstrServiceName,
											m_wstrPortName,
											pWSDLDesc->GetDefinitionsTNS());
}

bool WMSOAPWSDLClient::GetMethodSOAPAction(const wstring& wstrMethod,
										   wstring& wstrSOAPAction)
{
	WMSOAPBindingHandler *pBinding = GetSOAPBinding();
	if (pBinding == NULL)
	{
		return false;
	}
	// find the operation using method name as key
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetSOAPOperation(wstrMethod);
	if (pOperation == NULL)
	{
		return false;
	}
	// get expected SOAPAction
	wstrSOAPAction = pOperation->GetSOAPAction();
	return true;
}

bool WMSOAPWSDLClient::SOAPActionRequired(const wstring& wstrOpName, bool& bIsRequired)
{
	WMSOAPBindingHandler *pBinding = GetSOAPBinding();
	if (pBinding == NULL)
	{
		return false;
	}
	// find the operation using method name as key
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetSOAPOperation(wstrOpName);
	if (pOperation == NULL)
	{
		return false;
	}
	// get expected method namespace
	bIsRequired = pOperation->SOAPActionRequired();
	return true;
}

bool WMSOAPWSDLClient::GetMethodNamespaceURI(const wstring& wstrMethod,
										  wstring& wstrSOAPMethodNS)
{
	WMSOAPBindingHandler *pBinding = GetSOAPBinding();
	if (pBinding == NULL)
	{
		return false;
	}
	// find the operation using method name as key
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetSOAPOperation(wstrMethod);
	if (pOperation == NULL)
	{
		return false;
	}
	// get expected method namespace
	wstrSOAPMethodNS = pOperation->GetSOAPInputBodyNS();
    if (wstrSOAPMethodNS.empty() == true)
    {
	    wstrSOAPMethodNS = pOperation->GetSOAPOutputBodyNS();
    }
	return true;
}

WMMessageHandler *WMSOAPWSDLClient::GetInputMessage(const wstring& wstrMethod)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the binding object
	WMSOAPBindingHandler *pBinding = pWSDLDesc->GetSOAPDefinitions().GetSOAPBinding(
											m_wstrServiceName,
											m_wstrPortName,
											pWSDLDesc->GetDefinitionsTNS());
	if (pBinding == NULL)
	{
		return NULL;
	}
	// get portType
	wstring wstrPortTypeName, wstrPortTypeNS;
	pBinding->GetPortTypeNames(wstrPortTypeName, wstrPortTypeNS);
	WMPortTypeHandler *pPortType =
		pWSDLDesc->GetSOAPDefinitions().GetPortType(wstrPortTypeName, wstrPortTypeNS);
	if (pPortType == NULL)
	{
		return NULL;
	}
	WMOperationHandler *pOp = pPortType->GetOperation(wstrMethod);
	if (pOp == NULL)
	{
		return NULL;
	}
	wstring wstrMessageName, wstrMsgNamespace;
	pOp->GetInputMessageNames(wstrMessageName, wstrMsgNamespace);
	return pWSDLDesc->GetSOAPDefinitions().GetMessage(wstrMessageName, wstrMsgNamespace);
}

WMMessageHandler *WMSOAPWSDLClient::GetOutputMessage(const wstring& wstrMethod)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the binding object
	WMSOAPBindingHandler *pBinding = pWSDLDesc->GetSOAPDefinitions().GetSOAPBinding(
											m_wstrServiceName,
											m_wstrPortName,
											pWSDLDesc->GetDefinitionsTNS());
	if (pBinding == NULL)
	{
		return false;
	}
	// get portType
	wstring wstrPortTypeName, wstrPortTypeNS;
	pBinding->GetPortTypeNames(wstrPortTypeName, wstrPortTypeNS);
	WMPortTypeHandler *pPortType =
		pWSDLDesc->GetSOAPDefinitions().GetPortType(wstrPortTypeName, wstrPortTypeNS);
	if (pPortType == NULL)
	{
		return false;
	}
	WMOperationHandler *pOp = pPortType->GetOperation(wstrMethod);
	if (pOp == NULL)
	{
		return false;
	}
	wstring wstrMessageName, wstrMsgNamespace;
	pOp->GetOutputMessageNames(wstrMessageName, wstrMsgNamespace);
	return pWSDLDesc->GetSOAPDefinitions().GetMessage(wstrMessageName, wstrMsgNamespace);
}

bool WMSOAPWSDLClient::GetHeaderElemType(   const wstring& wstrElemName,
											const wstring& wstrElemNS,
											wstring& wstrType,
											wstring& wstrTypeNS)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	return pWSDLDesc->GetSOAPDefinitions().GetSchemaElemType(wstrElemName,
															wstrElemNS,
															wstrType,
															wstrTypeNS);
}

bool WMSOAPWSDLClient::GetInputHeaderPartType(  const wstring& wstrOpName,
												const wstring& wstrPartName,
												const wstring& wstrPartNS,
												wstring& wstrType,
												wstring& wstrTypeNS)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the binding object
	WMSOAPBindingHandler *pBinding =
		pWSDLDesc->GetSOAPDefinitions().GetSOAPBinding(
											m_wstrServiceName,
											m_wstrPortName,
											pWSDLDesc->GetDefinitionsTNS());
	if (pBinding == NULL)
	{
		return false;
	}
	// find the operation using method name as key
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetSOAPOperation(wstrOpName);
	if (pOperation == NULL)
	{
		return false;
	}
	// get the message name
	wstring wstrMsgName, wstrMsgNS;
	if (pOperation->GetInput().GetHeaderPartMsg(wstrPartName,
												wstrPartNS,
												wstrMsgName,
												wstrMsgNS) == false)
	{
		// corresponding soap:header ext element not found
		return false;
	}
	// get the message object ptr
	WMMessageHandler *pMsg;
	pMsg = pWSDLDesc->GetSOAPDefinitions().GetMessage(wstrMsgName, wstrMsgNS);
	if (pMsg == NULL)
	{
		// no such message declared
		return false;
	}
	// get the message part type
	return pMsg->GetMessagePartType(wstrPartName, wstrType, wstrTypeNS);
}

bool WMSOAPWSDLClient::GetOutputHeaderPartType( const wstring& wstrOpName,
												const wstring& wstrPartName,
												const wstring& wstrPartNS,
												wstring& wstrType,
												wstring& wstrTypeNS)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the binding object
	WMSOAPBindingHandler *pBinding =
		pWSDLDesc->GetSOAPDefinitions().GetSOAPBinding(
											m_wstrServiceName,
											m_wstrPortName,
											pWSDLDesc->GetDefinitionsTNS());
	if (pBinding == NULL)
	{
		return false;
	}
	// find the operation using method name as key
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetSOAPOperation(wstrOpName);
	if (pOperation == NULL)
	{
		return false;
	}
	// get the message name
	wstring wstrMsgName, wstrMsgNS;
	if (pOperation->GetOutput().GetHeaderPartMsg(wstrPartName,
												wstrPartNS,
												wstrMsgName,
												wstrMsgNS) == false)
	{
		// corresponding soap:header ext element not found
		return false;
	}
	// get the message object ptr
	WMMessageHandler *pMsg;
	pMsg = pWSDLDesc->GetSOAPDefinitions().GetMessage(wstrMsgName, wstrMsgNS);
	if (pMsg == NULL)
	{
		// no such message declared
		return false;
	}
	// get the message part type
	return pMsg->GetMessagePartType(wstrPartName, wstrType, wstrTypeNS);
}

bool WMSOAPWSDLClient::GetInputHeaderPartEncStyle(  const wstring& wstrOpName,
												    const wstring& wstrPartName,
												    const wstring& wstrPartNS,
												    wstring& wstrEncStyle)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the binding object
	WMSOAPBindingHandler *pBinding =
		pWSDLDesc->GetSOAPDefinitions().GetSOAPBinding(
											m_wstrServiceName,
											m_wstrPortName,
											pWSDLDesc->GetDefinitionsTNS());
	if (pBinding == NULL)
	{
		return false;
	}
	// find the operation using method name as key
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetSOAPOperation(wstrOpName);
	if (pOperation == NULL)
	{
		return false;
	}
	// get the encoding style
	return pOperation->GetInput().GetHeaderPartEncStyle(wstrPartName,
												        wstrPartNS,
												        wstrEncStyle);
}

bool WMSOAPWSDLClient::GetOutputHeaderPartEncStyle( const wstring& wstrOpName,
												    const wstring& wstrPartName,
												    const wstring& wstrPartNS,
												    wstring& wstrEncStyle)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the binding object
	WMSOAPBindingHandler *pBinding =
		pWSDLDesc->GetSOAPDefinitions().GetSOAPBinding(
											m_wstrServiceName,
											m_wstrPortName,
											pWSDLDesc->GetDefinitionsTNS());
	if (pBinding == NULL)
	{
		return false;
	}
	// find the operation using method name as key
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetSOAPOperation(wstrOpName);
	if (pOperation == NULL)
	{
		return false;
	}
	// get the encoding style
	return pOperation->GetOutput().GetHeaderPartEncStyle(   wstrPartName,
												            wstrPartNS,
												            wstrEncStyle);
}

bool WMSOAPWSDLClient::GetInHeaderFaultPartEncStyle(const wstring& wstrOpName,
												    const wstring& wstrPartName,
												    const wstring& wstrPartNS,
												    wstring& wstrEncStyle)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the binding object
	WMSOAPBindingHandler *pBinding =
		pWSDLDesc->GetSOAPDefinitions().GetSOAPBinding(
											m_wstrServiceName,
											m_wstrPortName,
											pWSDLDesc->GetDefinitionsTNS());
	if (pBinding == NULL)
	{
		return false;
	}
	// find the operation using method name as key
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetSOAPOperation(wstrOpName);
	if (pOperation == NULL)
	{
		return false;
	}
	// get the encoding style
	return pOperation->GetInput().GetHeaderFaultPartEncStyle(wstrPartName,
														    wstrPartNS,
														    wstrEncStyle);
}

bool WMSOAPWSDLClient::GetOutHeaderFaultPartEncStyle(const wstring& wstrOpName,
													const wstring& wstrPartName,
													const wstring& wstrPartNS,
													wstring& wstrEncStyle)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the binding object
	WMSOAPBindingHandler *pBinding =
		pWSDLDesc->GetSOAPDefinitions().GetSOAPBinding(
											m_wstrServiceName,
											m_wstrPortName,
											pWSDLDesc->GetDefinitionsTNS());
	if (pBinding == NULL)
	{
		return false;
	}
	// find the operation using method name as key
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetSOAPOperation(wstrOpName);
	if (pOperation == NULL)
	{
		return false;
	}
	// get the encoding style
	return pOperation->GetOutput().GetHeaderFaultPartEncStyle(  wstrPartName,
														        wstrPartNS,
														        wstrEncStyle);
}

bool WMSOAPWSDLClient::GetInHeaderFaultPartType(const wstring& wstrOpName,
												const wstring& wstrPartName,
												const wstring& wstrPartNS,
												wstring& wstrType,
												wstring& wstrTypeNS)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the binding object
	WMSOAPBindingHandler *pBinding =
		pWSDLDesc->GetSOAPDefinitions().GetSOAPBinding(
											m_wstrServiceName,
											m_wstrPortName,
											pWSDLDesc->GetDefinitionsTNS());
	if (pBinding == NULL)
	{
		return false;
	}
	// find the operation using method name as key
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetSOAPOperation(wstrOpName);
	if (pOperation == NULL)
	{
		return false;
	}
	// get the message name
	wstring wstrMsgName, wstrMsgNS;
	if (pOperation->GetInput().GetHeaderFaultPartMsg(   wstrPartName,
														wstrPartNS,
														wstrMsgName,
														wstrMsgNS) == false)
	{
		// corresponding soap:headerfault ext element not found
		return false;
	}
	// get the message object ptr
	WMMessageHandler *pMsg;
	pMsg = pWSDLDesc->GetSOAPDefinitions().GetMessage(wstrMsgName, wstrMsgNS);
	if (pMsg == NULL)
	{
		// no such message declared
		return false;
	}
	// get the message part type
	return pMsg->GetMessagePartType(wstrPartName, wstrType, wstrTypeNS);
}

bool WMSOAPWSDLClient::GetOutHeaderFaultPartType(   const wstring& wstrOpName,
													const wstring& wstrPartName,
													const wstring& wstrPartNS,
													wstring& wstrType,
													wstring& wstrTypeNS)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the binding object
	WMSOAPBindingHandler *pBinding =
		pWSDLDesc->GetSOAPDefinitions().GetSOAPBinding(
											m_wstrServiceName,
											m_wstrPortName,
											pWSDLDesc->GetDefinitionsTNS());
	if (pBinding == NULL)
	{
		return false;
	}
	// find the operation using method name as key
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetSOAPOperation(wstrOpName);
	if (pOperation == NULL)
	{
		return false;
	}
	// get the message name
	wstring wstrMsgName, wstrMsgNS;
	if (pOperation->GetOutput().GetHeaderFaultPartMsg(  wstrPartName,
														wstrPartNS,
														wstrMsgName,
														wstrMsgNS) == false)
	{
		// corresponding soap:headerfault ext element not found
		return false;
	}
	// get the message object ptr
	WMMessageHandler *pMsg;
	pMsg = pWSDLDesc->GetSOAPDefinitions().GetMessage(wstrMsgName, wstrMsgNS);
	if (pMsg == NULL)
	{
		// no such message declared
		return false;
	}
	// get the message part type
	return pMsg->GetMessagePartType(wstrPartName, wstrType, wstrTypeNS);
}

bool WMSOAPWSDLClient::GetFaultDetailPartType(  const wstring& wstrOpName,
												const wstring& wstrPartName,
												const wstring& wstrPartNS,
												wstring& wstrType,
												wstring& wstrTypeNS)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the binding object
	WMSOAPBindingHandler *pBinding =
		pWSDLDesc->GetSOAPDefinitions().GetSOAPBinding(
											m_wstrServiceName,
											m_wstrPortName,
											pWSDLDesc->GetDefinitionsTNS());
	if (pBinding == NULL)
	{
		return false;
	}
	// find the portType
	wstring wstrPortTypeName, wstrPortTypeNS;
	pBinding->GetPortTypeNames(wstrPortTypeName, wstrPortTypeNS);
	WMPortTypeHandler *pPortType =
		pWSDLDesc->GetSOAPDefinitions().GetPortType(wstrPortTypeName, wstrPortTypeNS);
	if (pPortType == NULL)
	{
		return false;
	}
	// now get the operation
	WMOperationHandler *pOp = pPortType->GetOperation(wstrOpName);
	if (pOp == NULL)
	{
		return false;
	}
	// find the soap:operation using method name as key
	WMSOAPOperationHandler *pSOAPOp;
	pSOAPOp = pBinding->GetSOAPOperation(wstrOpName);
	if (pSOAPOp == NULL)
	{
		return false;
	}
	// iterate over fault elements contained in soap:operation
	list<WMSOAPFaultElemHandler	*>::iterator iter;
	for (iter = pSOAPOp->GetFaultList().begin();
			iter != pSOAPOp->GetFaultList().end();
			iter++)
	{
		WMSOAPFaultElemHandler *pSOAPFault = *iter;
		if (pSOAPFault == NULL)
		{
			continue;
		}
		wstring wstrFaultName = pSOAPFault->GetSOAPFaultName();
		// see if this fault name is found in operation's fault map
		WMFaultHandler *pFault;
		pFault = pOp->GetFault(wstrFaultName);
		if (pFault != NULL)
		{
			// it's a candidate... get the message name
			wstring wstrMsgName, wstrMsgNS;
			pFault->GetMessage(wstrMsgName, wstrMsgNS);
			// get the message object ptr
			WMMessageHandler *pMsg;
			pMsg = pWSDLDesc->GetSOAPDefinitions().GetMessage(wstrMsgName, wstrMsgNS);
			if (pMsg == NULL)
			{
				// no such message declared
				continue;
			}
			// get the message part type
			if (pMsg->GetMessagePartType(wstrPartName, wstrType, wstrTypeNS) == true)
			{
				return true;
			}
		}
	}
	return false;
}

bool WMSOAPWSDLClient::GetFaultDetailEncStyle(  const wstring& wstrOpName,
												const wstring& wstrPartName,
												const wstring& wstrPartNS,
												wstring& wstrEncStyle)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the binding object
	WMSOAPBindingHandler *pBinding =
		pWSDLDesc->GetSOAPDefinitions().GetSOAPBinding(
											m_wstrServiceName,
											m_wstrPortName,
											pWSDLDesc->GetDefinitionsTNS());
	if (pBinding == NULL)
	{
		return false;
	}
	// find the portType
	wstring wstrPortTypeName, wstrPortTypeNS;
	pBinding->GetPortTypeNames(wstrPortTypeName, wstrPortTypeNS);
	WMPortTypeHandler *pPortType =
		pWSDLDesc->GetSOAPDefinitions().GetPortType(wstrPortTypeName, wstrPortTypeNS);
	if (pPortType == NULL)
	{
		return false;
	}
	// now get the operation
	WMOperationHandler *pOp = pPortType->GetOperation(wstrOpName);
	if (pOp == NULL)
	{
		return false;
	}
	// find the soap:operation using method name as key
	WMSOAPOperationHandler *pSOAPOp;
	pSOAPOp = pBinding->GetSOAPOperation(wstrOpName);
	if (pSOAPOp == NULL)
	{
		return false;
	}
	// iterate over fault elements contained in soap:operation
	list<WMSOAPFaultElemHandler	*>::iterator iter;
	for (iter = pSOAPOp->GetFaultList().begin();
			iter != pSOAPOp->GetFaultList().end();
			iter++)
	{
		WMSOAPFaultElemHandler *pSOAPFault = *iter;
		if (pSOAPFault == NULL)
		{
			continue;
		}
		wstring wstrFaultName = pSOAPFault->GetSOAPFaultName();
		// see if this fault name is found in operation's fault map
		WMFaultHandler *pFault;
		pFault = pOp->GetFault(wstrFaultName);
		if (pFault != NULL)
        {
			// it's a candidate... get the message name
			wstring wstrMsgName, wstrMsgNS;
			pFault->GetMessage(wstrMsgName, wstrMsgNS);
			// get the message object ptr
			WMMessageHandler *pMsg;
			pMsg = pWSDLDesc->GetSOAPDefinitions().GetMessage(wstrMsgName, wstrMsgNS);
			if (pMsg == NULL)
			{
				// no such message declared
				continue;
			}
			// is this part found in message?
            if (pMsg->GetMessagePart(wstrPartName) != NULL)
			{
                // yes, so make sure namespace given in soap:fault element matches
                if (pSOAPFault->GetSOAPFaultNamespace() == wstrPartNS)
                {
                    // this is it, get encoding style
                    wstrEncStyle = pSOAPFault->GetSOAPFaultEncStyle();
				    return true;
                }
			}
        }
	}
	return false;
}

bool WMSOAPWSDLClient::GetFaultDetailUse(   const wstring& wstrOpName,
											const wstring& wstrPartName,
											const wstring& wstrPartNS,
											wstring& wstrUse)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the binding object
	WMSOAPBindingHandler *pBinding =
		pWSDLDesc->GetSOAPDefinitions().GetSOAPBinding(
											m_wstrServiceName,
											m_wstrPortName,
											pWSDLDesc->GetDefinitionsTNS());
	if (pBinding == NULL)
	{
		return false;
	}
	// find the portType
	wstring wstrPortTypeName, wstrPortTypeNS;
	pBinding->GetPortTypeNames(wstrPortTypeName, wstrPortTypeNS);
	WMPortTypeHandler *pPortType =
		pWSDLDesc->GetSOAPDefinitions().GetPortType(wstrPortTypeName, wstrPortTypeNS);
	if (pPortType == NULL)
	{
		return false;
	}
	// now get the operation
	WMOperationHandler *pOp = pPortType->GetOperation(wstrOpName);
	if (pOp == NULL)
	{
		return false;
	}
	// find the soap:operation using method name as key
	WMSOAPOperationHandler *pSOAPOp;
	pSOAPOp = pBinding->GetSOAPOperation(wstrOpName);
	if (pSOAPOp == NULL)
	{
		return false;
	}
	// iterate over fault elements contained in soap:operation
	list<WMSOAPFaultElemHandler	*>::iterator iter;
	for (iter = pSOAPOp->GetFaultList().begin();
			iter != pSOAPOp->GetFaultList().end();
			iter++)
	{
		WMSOAPFaultElemHandler *pSOAPFault = *iter;
		if (pSOAPFault == NULL)
		{
			continue;
		}
		wstring wstrFaultName = pSOAPFault->GetSOAPFaultName();
		// see if this fault name is found in operation's fault map
		WMFaultHandler *pFault;
		pFault = pOp->GetFault(wstrFaultName);
		if (pFault != NULL)
        {
			// it's a candidate... get the message name
			wstring wstrMsgName, wstrMsgNS;
			pFault->GetMessage(wstrMsgName, wstrMsgNS);
			// get the message object ptr
			WMMessageHandler *pMsg;
			pMsg = pWSDLDesc->GetSOAPDefinitions().GetMessage(wstrMsgName, wstrMsgNS);
			if (pMsg == NULL)
			{
				// no such message declared
				continue;
			}
			// is this part found in message?
            if (pMsg->GetMessagePart(wstrPartName) != NULL)
			{
                // yes, so make sure namespace given in soap:fault element matches
                if (pSOAPFault->GetSOAPFaultNamespace() == wstrPartNS)
                {
                    // this is it, get encoding style
                    wstrUse = pSOAPFault->GetSOAPFaultUse();
				    return true;
                }
			}
        }
	}
	return false;
}

bool WMSOAPWSDLClient::GetArrayType(const wstring& wstrArrayName,
									const wstring& wstrArrayNS,
									wstring& wstrType,
									wstring& wstrTypeNS)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	return pWSDLDesc->GetSOAPDefinitions().GetArrayType(wstrArrayName,
														wstrArrayNS,
														wstrType,
														wstrTypeNS);
}

bool WMSOAPWSDLClient::GetArrayTypeLit( const wstring& wstrArrayName,
									    const wstring& wstrArrayNS,
									    wstring& wstrItemType,
									    wstring& wstrItemTypeNS,
                                        wstring& wstrItemName,
                                        wstring& wstrItemNS)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	return pWSDLDesc->GetSOAPDefinitions().GetArrayTypeLit( wstrArrayName,
														    wstrArrayNS,
														    wstrItemType,
														    wstrItemTypeNS,
                                                            wstrItemName,
                                                            wstrItemNS);
}

bool WMSOAPWSDLClient::GetArrayDims(const wstring& wstrArrayName,
									const wstring& wstrArrayNS,
									unsigned int& nDims)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	return pWSDLDesc->GetSOAPDefinitions().GetArrayDims(wstrArrayName,
														wstrArrayNS,
														nDims);
}

bool WMSOAPWSDLClient::GetComplexBaseType(  const wstring& wstrName,
											const wstring& wstrNS,
											wstring& wstrBaseType,
											wstring& wstrBaseTypeNS)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	return pWSDLDesc->GetSOAPDefinitions().GetComplexBaseType(  wstrName,
																wstrNS,
																wstrBaseType,
																wstrBaseTypeNS);
}

bool WMSOAPWSDLClient::GetStructMemberType( const wstring& wstrStructName,
											const wstring& wstrStructNS,
											const wstring& wstrMemberName,
											const wstring& wstrMemberNS,
											wstring& wstrType,
											wstring& wstrTypeNS)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	return pWSDLDesc->GetSOAPDefinitions().GetStructMemberType( wstrStructName,
																wstrStructNS,
																wstrMemberName,
																wstrMemberNS,
																wstrType,
																wstrTypeNS);
}

const wstring& WMSOAPWSDLClient::GetDefinitionsTNS()
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	return pWSDLDesc->GetDefinitionsTNS();
}

bool WMSOAPWSDLClient::GetSOAPInputBodyUse(  const wstring& wstrOpName,
											 wstring& wstrUse)
{
	// first the binding object
	WMSOAPBindingHandler *pBinding = GetSOAPBinding();
	if (pBinding == NULL)
	{
		return false;
	}
	// find the operation using method name as key
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetSOAPOperation(wstrOpName);
	if (pOperation == NULL)
	{
		return false;
	}
	wstrUse = pOperation->GetSOAPInputBodyUse();
	return true;
}

bool WMSOAPWSDLClient::GetSOAPInputBodyEncStyle(const wstring& wstrOpName,
													 wstring& wstrEncStyle)
{
	// first the binding object
	WMSOAPBindingHandler *pBinding = GetSOAPBinding();
	if (pBinding == NULL)
	{
		return false;
	}
	// find the operation using method name as key
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetSOAPOperation(wstrOpName);
	if (pOperation == NULL)
	{
		return false;
	}
    if (pOperation->GetSOAPInputBodyUse() != L"encoded")
    {
        return false;
    }
	wstrEncStyle = pOperation->GetSOAPInputBodyEncStyle();
	return true;
}

bool WMSOAPWSDLClient::GetSOAPOutputBodyUse(const wstring& wstrOpName,
											wstring& wstrUse)
{
	// first the binding object
	WMSOAPBindingHandler *pBinding = GetSOAPBinding();
	if (pBinding == NULL)
	{
		return false;
	}
	// find the operation using method name as key
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetSOAPOperation(wstrOpName);
	if (pOperation == NULL)
	{
		return false;
	}
	wstrUse = pOperation->GetSOAPOutputBodyUse();
	return true;
}

bool WMSOAPWSDLClient::GetSOAPOutputBodyEncStyle(const wstring& wstrOpName,
												wstring& wstrEncStyle)
{
	// first the binding object
	WMSOAPBindingHandler *pBinding = GetSOAPBinding();
	if (pBinding == NULL)
	{
		return false;
	}
	// find the operation using method name as key
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetSOAPOperation(wstrOpName);
	if (pOperation == NULL)
	{
		return false;
	}
    if (pOperation->GetSOAPOutputBodyUse() != L"encoded")
    {
        return false;
    }
	wstrEncStyle = pOperation->GetSOAPOutputBodyEncStyle();
	return true;
}

bool WMSOAPWSDLClient::GetSOAPBindingStyle(wstring& wstrStyle)
{
	// first the binding object
	WMSOAPBindingHandler *pBinding = GetSOAPBinding();
	if (pBinding == NULL)
	{
		return false;
	}
	wstrStyle = pBinding->GetSOAPBindingStyle();
	return true;
}

bool WMSOAPWSDLClient::GetSOAPBindingVersion(wstring& wstrVersionURI)
{
	// first the binding object
	WMSOAPBindingHandler *pBinding = GetSOAPBinding();
	if (pBinding == NULL)
	{
		return false;
	}
	wstrVersionURI = pBinding->GetSOAPBindingVersion();
	return true;
}

bool WMSOAPWSDLClient::GetSOAPBindingTransport(wstring& wstrTransport)
{
	// first the binding object
	WMSOAPBindingHandler *pBinding = GetSOAPBinding();
	if (pBinding == NULL)
	{
		return false;
	}
	wstrTransport = pBinding->GetSOAPBindingTransport();
	return true;
}

bool WMSOAPWSDLClient::GetOpBindingStyle(const wstring& wstrOpName, wstring& wstrStyle)
{
	WMSOAPBindingHandler *pBinding = GetSOAPBinding();
	if (pBinding == NULL)
	{
		return false;
	}
	// find the operation using method name as key
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetSOAPOperation(wstrOpName);
	if (pOperation == NULL)
	{
		return false;
	}
	// get value of 'style' attribute from soap:operation element in binding
	wstrStyle = pOperation->GetSOAPBindingStyle();
	// was it specified in soap:operation element?
	if (wstrStyle.empty() == true)
	{
		// no, so use default from soap:binding element
		wstrStyle = pBinding->GetSOAPBindingStyle();
		if (wstrStyle.empty() == false)
		{
			// ok, it was specified in soap:binding element
			return true;
		}
		// no luck at all, so use default
		wstrStyle = L"document";
		return true;
	}
	return true;
}

bool WMSOAPWSDLClient::GetOpNamesBySOAPAction(const wstring& wstrSOAPAction,
												wstring& wstrOpName,
												wstring& wstrOpNS)
{
	// first the binding object
	WMSOAPBindingHandler *pBinding = GetSOAPBinding();
	if (pBinding == NULL)
	{
		return false;
	}
	// find SOAPAction entry
	WMSOAPOperationHandler *pOperation;
	pOperation = pBinding->GetOpBySOAPAction(wstrSOAPAction);
	if (pOperation == NULL)
	{
		return false;
	}
	pOperation->GetNames(wstrOpName, wstrOpNS);
	return true;
}
 
bool WMSOAPWSDLClient::GetInputMsgPartType( const wstring& wstrOpName,
											const wstring& wstrPartName,
											wstring& wstrType,
											wstring& wstrTypeNS)
{
	WMMessageHandler *pInputMsg = GetInputMessage(wstrOpName);
	if (pInputMsg == NULL)
	{
		return false;
	}
	if (pInputMsg->GetMessagePartType(  wstrPartName,
										wstrType,
										wstrTypeNS) == false)
	{
		return false;
	}
	return true;
}

bool WMSOAPWSDLClient::GetOutputMsgPartType(const wstring& wstrOpName,
											const wstring& wstrPartName,
											wstring& wstrType,
											wstring& wstrTypeNS)
{
	WMMessageHandler *pOutputMsg = GetOutputMessage(wstrOpName);
	if (pOutputMsg == NULL)
	{
		return false;
	}
	if (pOutputMsg->GetMessagePartType( wstrPartName,
										wstrType,
										wstrTypeNS) == false)
	{
		return false;
	}
	return true;
}

bool WMSOAPWSDLClient::GetOperationReturnType(  const wstring& wstrOpName,
												const wstring& wstrPartName,
												wstring& wstrType,
												wstring& wstrTypeNS)
{
	WMMessageHandler *pOutputMsg = GetOutputMessage(wstrOpName);
	if (pOutputMsg == NULL)
	{
		return false;
	}
	// can it be found by name?
	if (pOutputMsg->GetMessagePartType( wstrPartName,
										wstrType,
										wstrTypeNS) == true)
	{
		return true;
	}
	// No, but since SOAP says name is not significant, use default as a last resort.
	// The first part in the output message is assumed to represent the return.
	// Although nothing in WSDL 1.1 guarantees this... it's a common convention.
	return  pOutputMsg->GetDefaultPartType(wstrType, wstrTypeNS);
}

bool WMSOAPWSDLClient::IsInputMsgPart(const wstring& wstrOpName, const wstring& wstrPartName)
{
	WMMessageHandler *pInputMsg = GetInputMessage(wstrOpName);
	if (pInputMsg == NULL)
	{
		return false;
	}
	if (pInputMsg->GetPartsMap().find(wstrPartName) != pInputMsg->GetPartsMap().end())
	{
		return true;
	}
	return false;
}

bool WMSOAPWSDLClient::IsOutputMsgPart(const wstring& wstrOpName, const wstring& wstrPartName)
{
	WMMessageHandler *pOutputMsg = GetOutputMessage(wstrOpName);
	if (pOutputMsg == NULL)
	{
		return false;
	}
	if (pOutputMsg->GetPartsMap().find(wstrPartName) != pOutputMsg->GetPartsMap().end())
	{
		return true;
	}
	return false;
}

bool WMSOAPWSDLClient::GetFirstInParamName(const wstring& wstrOpName,
										   wstring& wstrName,
										   long& lPosition)
{
	WMMessageHandler *pInputMsg = GetInputMessage(wstrOpName);
	if (pInputMsg == NULL)
	{
		return false;
	}
	map<wstring, WMMessagePartHandler *>::iterator iterInputMap;
	if ((iterInputMap = pInputMsg->GetPartsMap().begin()) !=
										pInputMsg->GetPartsMap().end())
	{
		wstrName = (*iterInputMap).first;
		lPosition = 0;
		return true;
	}
	return false;
}

bool WMSOAPWSDLClient::GetNextInParamName(const wstring& wstrOpName,
										  wstring& wstrName,
										  long& lPosition)
{
	WMMessageHandler *pInputMsg = GetInputMessage(wstrOpName);
	if (pInputMsg == NULL)
	{
		return false;
	}
	map<wstring, WMMessagePartHandler *>::iterator iterInputMap;
	iterInputMap = pInputMsg->GetPartsMap().begin();
	long lNext = lPosition + 1;
	for (long i = 0; i < lNext; i++)
	{
		iterInputMap++;
	}
	if (iterInputMap != pInputMsg->GetPartsMap().end())
	{
		lPosition = lNext;
		wstrName = (*iterInputMap).first;
		return true;
	}
	return false;
}

bool WMSOAPWSDLClient::GetFirstOutParamName(const wstring& wstrOpName,
											wstring& wstrName,
											long& lPosition)
{
	WMMessageHandler *pOutputMsg = GetOutputMessage(wstrOpName);
	if (pOutputMsg == NULL)
	{
		return false;
	}
	map<wstring, WMMessagePartHandler *>::iterator iterOutputMap;
	if ((iterOutputMap = pOutputMsg->GetPartsMap().begin()) !=
										pOutputMsg->GetPartsMap().end())
	{
		wstrName = (*iterOutputMap).first;
		lPosition = 0;
		return true;
	}
	return false;
}

bool WMSOAPWSDLClient::GetNextOutParamName(const wstring& wstrOpName,
										   wstring& wstrName,
										   long& lPosition)
{
	WMMessageHandler *pOutputMsg = GetOutputMessage(wstrOpName);
	if (pOutputMsg == NULL)
	{
		return false;
	}
	map<wstring, WMMessagePartHandler *>::iterator iterOutputMap;
	iterOutputMap = pOutputMsg->GetPartsMap().begin();
	long lNext = lPosition + 1;
	for (long i = 0; i < lNext; i++)
	{
		iterOutputMap++;
	}
	if (iterOutputMap != pOutputMsg->GetPartsMap().end())
	{
		lPosition = lNext;
		wstrName = (*iterOutputMap).first;
		return true;
	}
	return false;
}

bool WMSOAPWSDLClient::IsOperationParam(const wstring& wstrMethod, const wstring& wstrParam)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the binding object
	WMSOAPBindingHandler *pBinding = pWSDLDesc->GetSOAPDefinitions().GetSOAPBinding(
											m_wstrServiceName,
											m_wstrPortName,
											pWSDLDesc->GetDefinitionsTNS());
	if (pBinding == NULL)
	{
		return false;
	}
	// get portType
	wstring wstrPortTypeName, wstrPortTypeNS;
	pBinding->GetPortTypeNames(wstrPortTypeName, wstrPortTypeNS);
	WMPortTypeHandler *pPortType =
		pWSDLDesc->GetSOAPDefinitions().GetPortType(wstrPortTypeName, wstrPortTypeNS);
	if (pPortType == NULL)
	{
		return false;
	}
	WMOperationHandler *pOp = pPortType->GetOperation(wstrMethod);
	if (pOp == NULL)
	{
		return false;
	}
	int nIndex;
	return pOp->GetParamOrderIndex(wstrParam, nIndex);
}

bool WMSOAPWSDLClient::GetOperationParamIndex(const wstring& wstrMethod, const wstring& wstrParam, long *lIndex)
{
	WMSOAPWSDLDesc *pWSDLDesc = GetWSDLDesc();
	// get the binding object
	WMSOAPBindingHandler *pBinding = pWSDLDesc->GetSOAPDefinitions().GetSOAPBinding(
											m_wstrServiceName,
											m_wstrPortName,
											pWSDLDesc->GetDefinitionsTNS());
	if (pBinding == NULL)
	{
		return false;
	}
	// get portType
	wstring wstrPortTypeName, wstrPortTypeNS;
	pBinding->GetPortTypeNames(wstrPortTypeName, wstrPortTypeNS);
	WMPortTypeHandler *pPortType =
		pWSDLDesc->GetSOAPDefinitions().GetPortType(wstrPortTypeName, wstrPortTypeNS);
	if (pPortType == NULL)
	{
		return false;
	}
	WMOperationHandler *pOp = pPortType->GetOperation(wstrMethod);
	if (pOp == NULL)
	{
		return false;
	}
	int nIndex;
	if (pOp->GetParamOrderIndex(wstrParam, nIndex) == false)
	{
		return false;
	}
	*lIndex = nIndex;
	return true;
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

WMSOAPWSDLImporter::WMSOAPWSDLImporter()
{
}

WMSOAPWSDLImporter::~WMSOAPWSDLImporter()
{
}

bool WMSOAPWSDLImporter::ReadServiceDesc(const string& strWSDLFileURL, const string& strDocBase)
{
	// is this relative path?
	string strURL;
	if (strWSDLFileURL.find(':') == string::npos)
	{
		// no scheme... must be relative so use base
		strURL = strDocBase;
		strURL += strWSDLFileURL;
	}
	else
	{
		strURL = strWSDLFileURL;
	}
	// set current doc base
	string::size_type pos;
	pos = strURL.rfind('/');
	m_strDocBase = strURL.substr(0, pos + 1);
	// http:// or file:// ?
	if ((pos = strURL.find("http://")) != string::npos)
	{
		string strWSDLHost;
		int nWSDLPort = 80;
		string strTemp = strURL.substr(pos + 7);
		pos = strTemp.find('/');
		string strWSDLFilename = strTemp.substr(pos);
		strTemp = strTemp.substr(0, pos);
		if ((pos = strTemp.find(':')) != string::npos)
		{
			// port specified explicitly
			nWSDLPort = atoi(strTemp.substr(pos + 1).c_str());
			strWSDLHost = strTemp.substr(0, pos);
		}
		else
		{
			strWSDLHost = strTemp;
		}
		if (GetAndParseWSDLFile(strWSDLHost,
								strWSDLFilename,
								m_strUserAgent,
								m_strHTTPHeaders,
								nWSDLPort,
								m_nHTTPTimeout) == false)
		{
			return false;
		}
	}
	else if ((pos = strURL.find("file://")) != string::npos)
	{
		string strWSDLFilename = strURL.substr(pos + 7);
		if (LoadAndParseWSDLFile(strWSDLFilename) == false)
		{
			return false;
		}
	}
	else
	{
		return false;
	}
	return true;
}
