// SoapFaultMessage.cpp
//
//////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002 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.
//
//////////////////////////////////////////////////////////////////////
//
// WMSOAPFaultMessage class - a class representing a SOAP Fault message.
// 
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "soapfaultmessage.h"
#include "charencode.h"
#include "xmlparser.h"
#include "soap.h"

WMSOAPFaultMessage::WMSOAPFaultMessage(void)
{
    m_nSOAPVersion = SOAP_VERSION_1_1;
    m_bDetailRequired = false;
}

WMSOAPFaultMessage::WMSOAPFaultMessage( const wstring& wstrCodeNS,
                                        const wstring& wstrCode,
                                        const wstring& wstrReason,
                                        bool bDetailRequired)
{
    m_wstrCodeNS = wstrCodeNS;
    m_wstrCode = wstrCode;
    m_wstrReason = wstrReason;
    m_bDetailRequired = bDetailRequired;
    m_nSOAPVersion = SOAP_VERSION_1_1;
}

WMSOAPFaultMessage::~WMSOAPFaultMessage(void)
{
    ClearDetails();
}

void WMSOAPFaultMessage::ClearDetails()
{
    list<WMXMLElement *>::iterator iL;
    for (iL = m_listDetailEntries.begin();
        iL != m_listDetailEntries.end();
        iL++)
    {
        if (*iL != NULL)
        {
            delete *iL;
        }
    }
}

bool WMSOAPFaultMessage::FromElement(WMXMLElement *pElem)
{
    m_pRoot = new WMXMLElement(*pElem);
    if (m_pRoot != NULL)
    {
        if (m_pRoot->GetURI() == g_pwszSoapEnvelopeNS)
        {
            m_nSOAPVersion = SOAP_VERSION_1_1;
        }
        else if (m_pRoot->GetURI() == g_pwszSoap12EnvelopeNS)
        {
            m_nSOAPVersion = SOAP_VERSION_1_2;
        }
        else
        {
            return false;
        }
    }
    return true;
}

WMXMLElement *WMSOAPFaultMessage::ToElement(int nSOAPVersion)
{
    return BuildFaultMsg(nSOAPVersion);
}

WMXMLElement *WMSOAPFaultMessage::BuildFaultMsg(int nSOAPVersion)
{
    wstring wstrSOAPEnvNS;
    if (nSOAPVersion == SOAP_VERSION_1_1)
    {
        wstrSOAPEnvNS = g_pwszSoapEnvelopeNS;
    }
    else
    {
        wstrSOAPEnvNS = g_pwszSoap12EnvelopeNS;
    }
    WMXMLElement *pFault = CreateRootElem(  wstrSOAPEnvNS,
                                            wstring(L"SOAP-ENV"),
                                            wstring(L"Fault"));
	if (pFault == NULL)
	{
		return NULL;
	}
    WMXMLElement *pDetail = NULL;
    if (nSOAPVersion == SOAP_VERSION_1_1)
    {
        // faultcode
        WMXMLElement *pElem = CreateChildElem(  pFault,
                                                wstring(L""),
                                                wstring(L""),
                                                wstring(L"faultcode"));
        pElem->SetNSPrefix(wstring(L"ns"), m_wstrCodeNS);
        wstring wstrTemp(L"ns:");
        wstrTemp += m_wstrCode;
        if (pElem == NULL || SerializeString(wstrTemp, pElem) == false)
        {
            return NULL;
        }
        // faultstring
        pElem = CreateChildElem(pFault,
                                wstring(L""),
                                wstring(L""),
                                wstring(L"faultstring"));
        if (pElem == NULL || SerializeString(m_wstrReason, pElem) == false)
        {
            return NULL;
        }
        // actor
        if (m_wstrRole.empty() == false)
        {
            pElem = CreateChildElem(pFault,
                                    wstring(L""),
                                    wstring(L""),
                                    wstring(L"faultactor"));
            if (pElem == NULL || SerializeString(m_wstrRole, pElem) == false)
            {
                return NULL;
            }
        }
        if (m_bDetailRequired == true)
        {
            pDetail = CreateChildElem(pFault,
                                    wstring(L""),
                                    wstring(L""),
                                    wstring(L"detail"));
            if (pElem == NULL)
            {
                return NULL;
            }
        }
    }
    else
    {
        // code
        WMXMLElement *pElem = CreateChildElem(  pFault,
                                                wstrSOAPEnvNS,
                                                wstring(L"SOAP-ENV"),
                                                wstring(L"Code"));
        pElem->SetNSPrefix(wstring(L"ns"), m_wstrCodeNS);
        wstring wstrTemp(L"ns:");
        wstrTemp += m_wstrCode;
        if (pElem == NULL || SerializeString(wstrTemp, pElem) == false)
        {
            return NULL;
        }
        // fault string
        pElem = CreateChildElem(pFault,
                                wstrSOAPEnvNS,
                                wstring(L"SOAP-ENV"),
                                wstring(L"Reason"));
        if (pElem == NULL || SerializeString(m_wstrReason, pElem) == false)
        {
            return NULL;
        }
        // actor
        if (m_wstrRole.empty() == false)
        {
            pElem = CreateChildElem(pFault,
                                    wstrSOAPEnvNS,
                                    wstring(L"SOAP-ENV"),
                                    wstring(L"Role"));
            if (pElem == NULL || SerializeString(m_wstrRole, pElem) == false)
            {
                return NULL;
            }
        }
        if (m_wstrNode.empty() == false)
        {
            pElem = CreateChildElem(pFault,
                                    wstrSOAPEnvNS,
                                    wstring(L"SOAP-ENV"),
                                    wstring(L"Node"));
            if (pElem == NULL || SerializeString(m_wstrNode, pElem) == false)
            {
                return NULL;
            }
        }
        if (m_bDetailRequired == true)
        {
            pDetail = CreateChildElem(pFault,
                                    wstrSOAPEnvNS,
                                    wstring(L"SOAP-ENV"),
                                    wstring(L"Detail"));
            if (pElem == NULL)
            {
                return NULL;
            }
        }
    }
    // details
    if (m_bDetailRequired == true && pDetail != NULL)
    {
        // add detail entries
        list<WMXMLElement *>::iterator iL;
        for (iL = m_listDetailEntries.begin();
            iL != m_listDetailEntries.end();
            iL++)
        {
            if (*iL != NULL)
            {
                WMXMLElement *pEntry = *iL;
		        pDetail->AddChildElement(pEntry);
                iL = m_listDetailEntries.erase(iL);
            }
        }
    }
    return pFault;
}

bool WMSOAPFaultMessage::Serialize(string& strXML,
                                 int nSOAPVersion)
{
	WMXMLElement *pMsg = BuildFaultMsg(nSOAPVersion);
    if (pMsg == NULL)
    {
        return false;
    }
	wstring wstrMsg;
	pMsg->Serialize(NULL, wstrMsg);
	delete pMsg;
	WideStringToUTF8(wstrMsg, strXML);
    m_nSOAPVersion = nSOAPVersion;
    return true;
}

bool WMSOAPFaultMessage::Serialize(wstring& wstrXML,
                                 int nSOAPVersion)
{
	WMXMLElement *pMsg = BuildFaultMsg(nSOAPVersion);
    if (pMsg == NULL)
    {
        return false;
    }
	pMsg->Serialize(NULL, wstrXML);
	delete pMsg;
    m_nSOAPVersion = nSOAPVersion;
    return true;
}

bool WMSOAPFaultMessage::Serialize(BSTR *pbstrXML,
                                 int nSOAPVersion)
{
	WMXMLElement *pMsg = BuildFaultMsg(nSOAPVersion);
    if (pMsg == NULL)
    {
        return false;
    }
	*pbstrXML = pMsg->Serialize(NULL);
	delete pMsg;
    m_nSOAPVersion = nSOAPVersion;
    return true;
}

bool WMSOAPFaultMessage::Deserialize(const string& strXML)
{
    if (DeserializeXML(strXML) == false)
    {
        return false;
    }
    if (m_pRoot != NULL)
    {
        if (m_pRoot->GetURI() == g_pwszSoapEnvelopeNS)
        {
            m_nSOAPVersion = SOAP_VERSION_1_1;
        }
        else if (m_pRoot->GetURI() == g_pwszSoap12EnvelopeNS)
        {
            m_nSOAPVersion = SOAP_VERSION_1_2;
        }
        else
        {
            return false;
        }
    }
	return m_pRoot != NULL;
}

bool WMSOAPFaultMessage::Deserialize(const BSTR bstrXML)
{
    if (DeserializeXML(bstrXML) == false)
    {
        return false;
    }
    if (m_pRoot != NULL)
    {
        if (m_pRoot->GetURI() == g_pwszSoapEnvelopeNS)
        {
            m_nSOAPVersion = SOAP_VERSION_1_1;
        }
        else if (m_pRoot->GetURI() == g_pwszSoap12EnvelopeNS)
        {
            m_nSOAPVersion = SOAP_VERSION_1_2;
        }
        else
        {
            return false;
        }
    }
	return m_pRoot != NULL;
}

bool WMSOAPFaultMessage::Deserialize(const wstring& wstrXML)
{
    if (DeserializeXML(wstrXML) == false)
    {
        return false;
    }
    if (m_pRoot != NULL)
    {
        if (m_pRoot->GetURI() == g_pwszSoapEnvelopeNS)
        {
            m_nSOAPVersion = SOAP_VERSION_1_1;
        }
        else if (m_pRoot->GetURI() == g_pwszSoap12EnvelopeNS)
        {
            m_nSOAPVersion = SOAP_VERSION_1_2;
        }
        else
        {
            return false;
        }
    }
	return m_pRoot != NULL;
}

bool WMSOAPFaultMessage::AddDetailEntry(WMXMLElement *pElem)
{
   m_listDetailEntries.push_back(pElem);
   return true;
}

WMXMLElement *WMSOAPFaultMessage::CreateDetailEntry(  const wstring& wstrNamespace,
                                                    const wstring& wstrPrefix,
                                                    const wstring& wstrLocalName)
{
    wstring wstrName;
    if (wstrNamespace.empty() == false && wstrPrefix.empty() == false)
    {
        wstrName = wstrPrefix;
        wstrName += L":";
        wstrName += wstrLocalName;
    }
    else
    {
        wstrName = wstrLocalName;
    }
    WMXMLElement *pElem = new WMXMLElement(wstrName);
	if (pElem == NULL)
	{
        return NULL;
    }
    if (wstrNamespace.empty() == false)
    {
        if (wstrPrefix.empty() == false)
        {
    	    pElem->SetNSPrefix(wstrPrefix, wstrNamespace);
        }
        else
        {
            // default namespace
    	    pElem->SetAttribute(wstring(L"xmlns"), wstrNamespace);
        }
    }
    AddDetailEntry(pElem);
    return pElem;
}

WMXMLElement *WMSOAPFaultMessage::GetDetailEntry(   const wstring& wstrNamespace,
                                                    const wstring& wstrName)
{
    if (m_pRoot == NULL)
    {
        return NULL;
    }
    wstring wstrSOAPEnvNS, wstrElemName;
    if (m_nSOAPVersion == SOAP_VERSION_1_1)
    {
        wstrSOAPEnvNS = L"";
        wstrElemName = L"detail";
    }
    else
    {
        wstrSOAPEnvNS = g_pwszSoap12EnvelopeNS;
        wstrElemName = L"Detail";
    }
    WMXMLElement *pElement = m_pRoot->GetChildElement(wstrSOAPEnvNS, wstrElemName);
    if (pElement == NULL)
    {
        return false;
    }
    return pElement->GetChildElement(wstrNamespace, wstrName);
}

bool WMSOAPFaultMessage::GetSOAPFaultCode(wstring& wstrValueNS, wstring& wstrValue)
{
    if (m_pRoot == NULL)
    {
        return NULL;
    }
    wstring wstrSOAPEnvNS, wstrElemName;
    if (m_nSOAPVersion == SOAP_VERSION_1_1)
    {
        wstrSOAPEnvNS = L"";
        wstrElemName = L"faultcode";
    }
    else
    {
        wstrSOAPEnvNS = g_pwszSoap12EnvelopeNS;
        wstrElemName = L"Code";
    }
    WMXMLElement *pElement = m_pRoot->GetChildElement(wstrSOAPEnvNS, wstrElemName);
    if (pElement == NULL)
    {
        return false;
    }
    wstring wstrTemp = pElement->GetContent();
	wstring::size_type pos = wstrTemp.find(':');
	if (pos != wstring::npos)
	{
		// get NS prefix
		NSPrefixMap::iterator iNS;
        if ((iNS = pElement->GetNSPrefixMap().find(wstrTemp.substr(0, pos))) != pElement->GetNSPrefixMap().end())
		{
			wstrValueNS = (*iNS).second;
		}
		else
		{
			// unresolvable namespace prefix
            return false;
		}
		wstrValue = wstrTemp.substr(++pos);
	}
	else
	{
		// default namespace
		NSPrefixMap::iterator iNS;
		if ((iNS = pElement->GetNSPrefixMap().find(wstring(L""))) != pElement->GetNSPrefixMap().end())
		{
			wstrValueNS = (*iNS).second;
		}
		else
		{
			// unresolvable default namespace
            return false;
		}
		wstrValue = wstrTemp;
	}
    return true;
}

bool WMSOAPFaultMessage::GetSOAPFaultString(wstring& wstrValue)
{
    if (m_pRoot == NULL)
    {
        return NULL;
    }
    wstring wstrSOAPEnvNS, wstrElemName;
    if (m_nSOAPVersion == SOAP_VERSION_1_1)
    {
        wstrSOAPEnvNS = L"";
        wstrElemName = L"faultstring";
    }
    else
    {
        wstrSOAPEnvNS = g_pwszSoap12EnvelopeNS;
        wstrElemName = L"Reason";
    }
    WMXMLElement *pElement = m_pRoot->GetChildElement(wstrSOAPEnvNS, wstrElemName);
    if (pElement == NULL)
    {
        return false;
    }
    return DeserializeString(wstrValue, pElement);
}

bool WMSOAPFaultMessage::GetSOAPFaultActor(wstring& wstrValue)
{
    if (m_pRoot == NULL)
    {
        return NULL;
    }
    wstring wstrSOAPEnvNS, wstrElemName;
    if (m_nSOAPVersion == SOAP_VERSION_1_1)
    {
        wstrSOAPEnvNS = L"";
        wstrElemName = L"faultactor";
    }
    else
    {
        wstrSOAPEnvNS = g_pwszSoap12EnvelopeNS;
        wstrElemName = L"Role";
    }
    WMXMLElement *pElement = m_pRoot->GetChildElement(wstrSOAPEnvNS, wstrElemName);
    if (pElement == NULL)
    {
        return false;
    }
    return DeserializeString(wstrValue, pElement);
}

bool WMSOAPFaultMessage::GetSOAPFaultNode(wstring& wstrValue)
{
    if (m_pRoot == NULL || m_nSOAPVersion == SOAP_VERSION_1_1)
    {
        return NULL;
    }
    WMXMLElement *pElement = m_pRoot->GetChildElement(wstring(g_pwszSoap12EnvelopeNS), wstring(L"Node"));
    if (pElement == NULL)
    {
        return false;
    }
    return DeserializeString(wstrValue, pElement);
}
