/*
 SPDX-FileCopyrightText: 2005 Tobias Koenig <tokoe@kde.org>

 SPDX-License-Identifier: MIT
*/

#include <common/messagehandler.h>
#include <common/nsmanager.h>
#include <common/parsercontext.h>

#include "soapbinding.h"
#include <QDebug>

using namespace KWSDL;

// TODO: set namespace correctly

static const char soapBindingTransportHTTP[] = "http://schemas.xmlsoap.org/soap/http";
static const char soapStandardNamespace[] = "http://schemas.xmlsoap.org/wsdl/soap/";

static QString soapPrefix(ParserContext *context)
{
    QString prefix = context->namespaceManager()->prefix(soapStandardNamespace);
    if (!prefix.isEmpty()) {
        return prefix + QLatin1Char(':');
    } else {
        return QString();
    }
}

SoapBinding::Binding::Binding()
    : mTransport(HTTPTransport)
    , mStyle(DocumentStyle)
{
}

SoapBinding::Binding::~Binding()
{
}

void SoapBinding::Binding::setTransport(Transport transport)
{
    mTransport = transport;
}

SoapBinding::Transport SoapBinding::Binding::transport() const
{
    return mTransport;
}

void SoapBinding::Binding::setStyle(Style style)
{
    mStyle = style;
}

SoapBinding::Style SoapBinding::Binding::style() const
{
    return mStyle;
}

void SoapBinding::Binding::loadXML(ParserContext *context, const QDomElement &element)
{
    if (element.hasAttribute(QLatin1String("transport"))) {
        if (element.attribute(QLatin1String("transport")) == soapBindingTransportHTTP) {
            mTransport = HTTPTransport;
        } else {
            context->messageHandler()->warning(QLatin1String("SoapBinding::Binding: unknown 'transport' value"));
        }
    }

    if (element.hasAttribute(QLatin1String("style"))) {
        if (element.attribute(QLatin1String("style")) == QLatin1String("rpc")) {
            mStyle = RPCStyle;
        } else if (element.attribute(QLatin1String("style")) == QLatin1String("document")) {
            mStyle = DocumentStyle;
        } else {
            context->messageHandler()->warning(QLatin1String("SoapBinding::Binding: unknown 'style' value"));
        }
    }
}

void SoapBinding::Binding::saveXML(ParserContext *context, QDomDocument &document, QDomElement &parent) const
{
    QDomElement element = document.createElementNS(soapStandardNamespace, soapPrefix(context) + QLatin1String("binding"));
    parent.appendChild(element);

    if (mTransport == HTTPTransport) {
        element.setAttribute(QLatin1String("transport"), soapBindingTransportHTTP);
    } else {
        context->messageHandler()->warning(QLatin1String("SoapBinding::Binding: unknown 'transport' value"));
    }

    if (mStyle == RPCStyle) {
        element.setAttribute(QLatin1String("style"), QLatin1String("rpc"));
    } else {
        element.setAttribute(QLatin1String("style"), QLatin1String("document"));
    }
}

SoapBinding::Operation::Operation()
    : mStyle(DocumentStyle)
{
}

SoapBinding::Operation::Operation(const QString &name)
    : mName(name)
    , mStyle(DocumentStyle)
{
}

SoapBinding::Operation::~Operation()
{
}

void SoapBinding::Operation::loadXML(ParserContext *context, const QDomElement &element)
{
    // read soapAction, discarding leading/trailing space (https://github.com/KDAB/KDSoap/issues/71)
    mSoapAction = element.attribute(QLatin1String("soapAction")).trimmed();

    // qDebug() << "style=" << element.attribute("style");

    if (element.hasAttribute(QLatin1String("style"))) {
        if (element.attribute(QLatin1String("style")) == QLatin1String("rpc")) {
            mStyle = RPCStyle;
        } else if (element.attribute(QLatin1String("style")) == QLatin1String("document")) {
            mStyle = DocumentStyle;
        } else {
            context->messageHandler()->warning(QLatin1String("SoapBinding::Operation: unknown 'style' value"));
        }
    }

    // TODO: fallback is style value of soap:binding
}

void SoapBinding::Operation::saveXML(ParserContext *context, QDomDocument &document, QDomElement &parent) const
{
    QDomElement element = document.createElementNS(soapStandardNamespace, soapPrefix(context) + QLatin1String("operation"));
    parent.appendChild(element);

    if (!mSoapAction.isEmpty()) {
        element.setAttribute(QLatin1String("soapAction"), mSoapAction);
    }

    if (mStyle == RPCStyle) {
        element.setAttribute(QLatin1String("style"), QLatin1String("rpc"));
    } else {
        element.setAttribute(QLatin1String("style"), QLatin1String("document"));
    }
}

void SoapBinding::Operation::setName(const QString &name)
{
    mName = name;
}

QString SoapBinding::Operation::name() const
{
    return mName;
}

void SoapBinding::Operation::setAction(const QString &action)
{
    mSoapAction = action;
}

QString SoapBinding::Operation::action() const
{
    return mSoapAction;
}

void SoapBinding::Operation::setStyle(Style style)
{
    mStyle = style;
}

SoapBinding::Style SoapBinding::Operation::style() const
{
    return mStyle;
}

void SoapBinding::Operation::setInput(const Body &input)
{
    mInputBody = input;
}

SoapBinding::Body SoapBinding::Operation::input() const
{
    return mInputBody;
}

void SoapBinding::Operation::setOutput(const Body &output)
{
    mOutputBody = output;
}

SoapBinding::Body SoapBinding::Operation::output() const
{
    return mOutputBody;
}

void SoapBinding::Operation::addInputHeader(const Header &inputHeader)
{
    mInputHeaders << inputHeader;
}

SoapBinding::Headers SoapBinding::Operation::inputHeaders() const
{
    return mInputHeaders;
}

void SoapBinding::Operation::addOutputHeader(const Header &outputHeader)
{
    mOutputHeaders << outputHeader;
}

SoapBinding::Headers SoapBinding::Operation::outputHeaders() const
{
    return mOutputHeaders;
}

void SoapBinding::Operation::setFault(const Fault &fault)
{
    mFault = fault;
}

SoapBinding::Fault SoapBinding::Operation::fault() const
{
    return mFault;
}

SoapBinding::Body::Body()
    : mUse(LiteralUse)
{
}

SoapBinding::Body::~Body()
{
}

#if 0
void SoapBinding::Body::setEncodingStyle(const QString &encodingStyle)
{
    mEncodingStyle = encodingStyle;
}

QString SoapBinding::Body::encodingStyle() const
{
    return mEncodingStyle;
}

void SoapBinding::Body::setPart(const QString &part)
{
    mPart = part;
}

void SoapBinding::Body::setUse(Use use)
{
    mUse = use;
}

void SoapBinding::Body::setNameSpace(const QString &nameSpace)
{
    mNameSpace = nameSpace;
}
#endif

QString SoapBinding::Body::part() const
{
    return mPart;
}

SoapBinding::Use SoapBinding::Body::use() const
{
    return mUse;
}

QString SoapBinding::Body::nameSpace() const
{
    return mNameSpace;
}

void SoapBinding::Body::loadXML(ParserContext *context, const QDomElement &element)
{
#if 0
    // ## Seems to be set to a namespace, always https://schemas.xmlsoap.org/soap/encoding/ ... unused here.
    if (element.hasAttribute("encodingStyle")) {
        mEncodingStyle = element.attribute("encodingStyle");
    } else {
        mEncodingStyle = QString();
    }
#endif

    mPart = element.attribute(QLatin1String("parts"));
    mNameSpace = element.attribute(QLatin1String("namespace"));

    if (element.hasAttribute(QLatin1String("use"))) {
        if (element.attribute(QLatin1String("use")) == QLatin1String("literal")) {
            mUse = LiteralUse;
        } else if (element.attribute(QLatin1String("use")) == QLatin1String("encoded")) {
            mUse = EncodedUse;
        } else {
            context->messageHandler()->warning(QLatin1String("SoapBinding::Body: unknown 'use' value"));
        }
    }
}

void SoapBinding::Body::saveXML(ParserContext *context, QDomDocument &document, QDomElement &parent) const
{
    QDomElement element = document.createElementNS(soapStandardNamespace, soapPrefix(context) + QLatin1String("body"));
    parent.appendChild(element);

#if 0
    if (!mEncodingStyle.isEmpty()) {
        element.setAttribute("encodingStyle", mEncodingStyle);
    }
#endif
    if (!mPart.isEmpty()) {
        element.setAttribute(QLatin1String("part"), mPart);
    }
    if (!mNameSpace.isEmpty()) {
        element.setAttribute(QLatin1String("namespace"), mNameSpace);
    }

    if (mUse == LiteralUse) {
        element.setAttribute(QLatin1String("use"), QLatin1String("literal"));
    } else {
        element.setAttribute(QLatin1String("use"), QLatin1String("encoded"));
    }
}

SoapBinding::Fault::Fault()
    : mUse(LiteralUse)
{
}

SoapBinding::Fault::~Fault()
{
}

#if 0
void SoapBinding::Fault::setEncodingStyle(const QString &encodingStyle)
{
    mEncodingStyle = encodingStyle;
}

QString SoapBinding::Fault::encodingStyle() const
{
    return mEncodingStyle;
}
#endif

void SoapBinding::Fault::setUse(Use use)
{
    mUse = use;
}

SoapBinding::Use SoapBinding::Fault::use() const
{
    return mUse;
}

void SoapBinding::Fault::setNameSpace(const QString &nameSpace)
{
    mNameSpace = nameSpace;
}

QString SoapBinding::Fault::nameSpace() const
{
    return mNameSpace;
}
void SoapBinding::Fault::loadXML(ParserContext *context, const QDomElement &element)
{
#if 0
    if (element.hasAttribute("encodingStyle")) {
        mEncodingStyle = element.attribute("encodingStyle");
    } else {
        mEncodingStyle = QString();
    }
#endif

    mNameSpace = element.attribute(QLatin1String("namespace"));

    if (element.hasAttribute(QLatin1String("use"))) {
        if (element.attribute(QLatin1String("use")) == QLatin1String("literal")) {
            mUse = LiteralUse;
        } else if (element.attribute(QLatin1String("use")) == QLatin1String("encoded")) {
            mUse = EncodedUse;
        } else {
            context->messageHandler()->warning(QLatin1String("SoapBinding::Fault: unknown 'use' value"));
        }
    }
}

void SoapBinding::Fault::saveXML(ParserContext *context, QDomDocument &document, QDomElement &parent) const
{
    QDomElement element = document.createElementNS(soapStandardNamespace, soapPrefix(context) + QLatin1String("fault"));
    parent.appendChild(element);

#if 0
    if (!mEncodingStyle.isEmpty()) {
        element.setAttribute("encodingStyle", mEncodingStyle);
    }
#endif
    if (!mNameSpace.isEmpty()) {
        element.setAttribute(QLatin1String("namespace"), mNameSpace);
    }

    if (mUse == LiteralUse) {
        element.setAttribute(QLatin1String("use"), QLatin1String("literal"));
    } else {
        element.setAttribute(QLatin1String("use"), QLatin1String("encoded"));
    }
}

SoapBinding::Header::Header()
    : mUse(LiteralUse)
{
}

SoapBinding::Header::~Header()
{
}

void SoapBinding::Header::setHeaderFault(const HeaderFault &headerFault)
{
    mHeaderFault = headerFault;
}

SoapBinding::HeaderFault SoapBinding::Header::headerFault() const
{
    return mHeaderFault;
}

void SoapBinding::Header::setMessage(const QName &message)
{
    mMessage = message;
}

QName SoapBinding::Header::message() const
{
    return mMessage;
}

void SoapBinding::Header::setPart(const QString &part)
{
    mPart = part;
}

QString SoapBinding::Header::part() const
{
    return mPart;
}

void SoapBinding::Header::setUse(Use use)
{
    mUse = use;
}

SoapBinding::Use SoapBinding::Header::use() const
{
    return mUse;
}

#if 0
void SoapBinding::Header::setEncodingStyle(const QString encodingStyle)
{
    mEncodingStyle = encodingStyle;
}

QString SoapBinding::Header::encodingStyle() const
{
    return mEncodingStyle;
}
#endif

void SoapBinding::Header::setNameSpace(const QString &nameSpace)
{
    mNameSpace = nameSpace;
}

QString SoapBinding::Header::nameSpace() const
{
    return mNameSpace;
}

void SoapBinding::Header::loadXML(ParserContext *context, const QDomElement &element)
{
    mMessage = element.attribute(QLatin1String("message"));
    if (mMessage.isEmpty()) {
        context->messageHandler()->warning(QLatin1String("SoapBinding::Header: 'message' required"));
    } else {
        if (!mMessage.prefix().isEmpty()) {
            mMessage.setNameSpace(context->namespaceManager()->uri(mMessage.prefix()));
        }
    }

    mPart = element.attribute(QLatin1String("part"));
    if (mPart.isEmpty()) {
        context->messageHandler()->warning(QLatin1String("SoapBinding::Header: 'part' required"));
    }

    if (element.attribute(QLatin1String("use")) == QLatin1String("literal")) {
        mUse = LiteralUse;
    } else if (element.attribute(QLatin1String("use")) == QLatin1String("encoded")) {
        mUse = EncodedUse;
    } else if (element.attribute(QLatin1String("use")).isEmpty()) {
        context->messageHandler()->warning(QLatin1String("SoapBinding::Header: 'use' required"));
    } else {
        context->messageHandler()->warning(QLatin1String("SoapBinding::Header: unknown 'use' value"));
    }

#if 0
    if (element.hasAttribute("encodingStyle")) {
        mEncodingStyle = element.attribute("encodingStyle");
    } else {
        mEncodingStyle = QString();
    }
#endif

    mNameSpace = element.attribute(QLatin1String("namespace"));

    QDomElement child = element.firstChildElement();
    while (!child.isNull()) {
        NSManager namespaceManager(context, child);
        if (child.tagName() == soapPrefix(context) + QLatin1String("headerfault")) {
            mHeaderFault.loadXML(context, child);
        } else {
            context->messageHandler()->warning(QString::fromLatin1("SoapBinding::Header: unknown tag %1").arg(child.tagName()));
        }

        child = child.nextSiblingElement();
    }
}

void SoapBinding::Header::saveXML(ParserContext *context, QDomDocument &document, QDomElement &parent) const
{
    QDomElement element = document.createElementNS(soapStandardNamespace, soapPrefix(context) + QLatin1String("header"));
    parent.appendChild(element);

    if (!mMessage.isEmpty()) {
        element.setAttribute(QLatin1String("message"), mMessage.qname());
    } else {
        context->messageHandler()->warning(QLatin1String("SoapBinding::Header: 'message' required"));
    }

    if (!mPart.isEmpty()) {
        element.setAttribute(QLatin1String("part"), mPart);
    } else {
        context->messageHandler()->warning(QLatin1String("SoapBinding::Header: 'part' required"));
    }

#if 0
    if (!mEncodingStyle.isEmpty()) {
        element.setAttribute("encodingStyle", mEncodingStyle);
    }
#endif
    if (!mNameSpace.isEmpty()) {
        element.setAttribute(QLatin1String("namespace"), mNameSpace);
    }

    if (mUse == LiteralUse) {
        element.setAttribute(QLatin1String("use"), QLatin1String("literal"));
    } else {
        element.setAttribute(QLatin1String("use"), QLatin1String("encoded"));
    }

    mHeaderFault.saveXML(context, document, element);
}

SoapBinding::HeaderFault::HeaderFault()
    : mUse(LiteralUse)
{
}

SoapBinding::HeaderFault::~HeaderFault()
{
}

void SoapBinding::HeaderFault::setMessage(const QName &message)
{
    mMessage = message;
}

QName SoapBinding::HeaderFault::message() const
{
    return mMessage;
}

#if 0
void SoapBinding::HeaderFault::setEncodingStyle(const QString &encodingStyle)
{
    mEncodingStyle = encodingStyle;
}

QString SoapBinding::HeaderFault::encodingStyle() const
{
    return mEncodingStyle;
}
#endif

void SoapBinding::HeaderFault::setPart(const QString &part)
{
    mPart = part;
}

QString SoapBinding::HeaderFault::part() const
{
    return mPart;
}

void SoapBinding::HeaderFault::setUse(Use use)
{
    mUse = use;
}

SoapBinding::Use SoapBinding::HeaderFault::use() const
{
    return mUse;
}

void SoapBinding::HeaderFault::setNameSpace(const QString &nameSpace)
{
    mNameSpace = nameSpace;
}

QString SoapBinding::HeaderFault::nameSpace() const
{
    return mNameSpace;
}

void SoapBinding::HeaderFault::loadXML(ParserContext *context, const QDomElement &element)
{
    mMessage = element.attribute(QLatin1String("message"));
    if (mMessage.isEmpty()) {
        context->messageHandler()->warning(QLatin1String("SoapBinding::HeaderFault: 'message' required"));
    }

    mPart = element.attribute(QLatin1String("part"));
    if (mPart.isEmpty()) {
        context->messageHandler()->warning(QLatin1String("SoapBinding::HeaderFault: 'part' required"));
    }

    if (element.attribute(QLatin1String("use")) == QLatin1String("literal")) {
        mUse = LiteralUse;
    } else if (element.attribute(QLatin1String("use")) == QLatin1String("encoded")) {
        mUse = EncodedUse;
    } else if (element.attribute(QLatin1String("use")).isEmpty()) {
        context->messageHandler()->warning(QLatin1String("SoapBinding::HeaderFault: 'use' required"));
    } else {
        context->messageHandler()->warning(QLatin1String("SoapBinding::HeaderFault: unknown 'use' value"));
    }

#if 0
    if (element.hasAttribute("encodingStyle")) {
        mEncodingStyle = element.attribute("encodingStyle");
    } else {
        mEncodingStyle = QString();
    }
#endif

    mNameSpace = element.attribute(QLatin1String("namespace"));
}

void SoapBinding::HeaderFault::saveXML(ParserContext *context, QDomDocument &document, QDomElement &parent) const
{
    QDomElement element = document.createElementNS(soapStandardNamespace, soapPrefix(context) + QLatin1String("headerfault"));
    parent.appendChild(element);

    if (!mMessage.isEmpty()) {
        element.setAttribute(QLatin1String("message"), mMessage.qname());
    } else {
        context->messageHandler()->warning(QLatin1String("SoapBinding::HeaderFault: 'message' required"));
    }

    if (!mPart.isEmpty()) {
        element.setAttribute(QLatin1String("part"), mPart);
    } else {
        context->messageHandler()->warning(QLatin1String("SoapBinding::HeaderFault: 'part' required"));
    }

#if 0
    if (!mEncodingStyle.isEmpty()) {
        element.setAttribute("encodingStyle", mEncodingStyle);
    }
#endif
    if (!mNameSpace.isEmpty()) {
        element.setAttribute(QLatin1String("namespace"), mNameSpace);
    }

    if (mUse == LiteralUse) {
        element.setAttribute(QLatin1String("use"), QLatin1String("literal"));
    } else {
        element.setAttribute(QLatin1String("use"), QLatin1String("encoded"));
    }
}

SoapBinding::Address::Address()
{
}

SoapBinding::Address::~Address()
{
}

void SoapBinding::Address::setLocation(const QUrl &location)
{
    mLocation = location;
}

QUrl SoapBinding::Address::location() const
{
    return mLocation;
}

void SoapBinding::setOperations(const Operation::Map &operations)
{
    mOperations = operations;
}

SoapBinding::Operation::Map SoapBinding::operations() const
{
    return mOperations;
}

void SoapBinding::Address::loadXML(ParserContext *context, const QDomElement &element)
{
    mLocation = QUrl(element.attribute(QLatin1String("location")));
    if (!mLocation.isValid()) {
        context->messageHandler()->warning(QLatin1String("SoapBinding::Address: 'location' required"));
    }
}

void SoapBinding::Address::saveXML(ParserContext *context, QDomDocument &document, QDomElement &parent) const
{
    QDomElement element = document.createElementNS(soapStandardNamespace, soapPrefix(context) + QLatin1String("address"));
    parent.appendChild(element);

    if (mLocation.isValid()) {
        element.setAttribute(QLatin1String("location"), mLocation.toString());
    } else {
        context->messageHandler()->warning(QLatin1String("SoapBinding::Address: 'location' required"));
    }
}

SoapBinding::SoapBinding()
{
}

SoapBinding::~SoapBinding()
{
}

SoapBinding::SoapBinding(const SoapBinding &other)
    : mBinding(other.mBinding)
    , mOperations(other.mOperations)
    , mAddress(other.mAddress)
{
}

SoapBinding &SoapBinding::operator=(const SoapBinding &other)
{
    SoapBinding copy(other);
    swap(copy);
    return *this;
}

void SoapBinding::swap(SoapBinding &other) noexcept
{
    using std::swap;
    swap(mBinding, other.mBinding);
    swap(mOperations, other.mOperations);
    swap(mAddress, other.mAddress);
}

void SoapBinding::setAddress(const Address &address)
{
    mAddress = address;
}

SoapBinding::Address SoapBinding::address() const
{
    return mAddress;
}

void SoapBinding::setBinding(const Binding &binding)
{
    mBinding = binding;
}

SoapBinding::Binding SoapBinding::binding() const
{
    return mBinding;
}

void SoapBinding::parseBinding(ParserContext *context, const QDomElement &parent)
{
    mBinding.loadXML(context, parent);
}

void SoapBinding::parseOperation(ParserContext *context, const QString &name, const QDomElement &parent)
{
    QDomElement child = parent.firstChildElement();
    while (!child.isNull()) {
        NSManager namespaceManager(context, child);
        if (NSManager::soapNamespaces().contains(namespaceManager.nameSpace(child))) {
            if (namespaceManager.localName(child) == QLatin1String("operation")) {
                Operation op(name);
                op.loadXML(context, child);
                mOperations.insert(name, op);
            }
        }

        child = child.nextSiblingElement();
    }
}

// Parse <operation><input>
void SoapBinding::parseOperationInput(ParserContext *context, const QString &name, const QDomElement &parent)
{
    QDomElement child = parent.firstChildElement();
    while (!child.isNull()) {
        NSManager namespaceManager(context, child);
        // qDebug() << Q_FUNC_INFO << namespaceManager.localName(child) << namespaceManager.nameSpace(child);
        if (NSManager::soapNamespaces().contains(namespaceManager.nameSpace(child))) {
            if (namespaceManager.localName(child) == QLatin1String("body")) {
                Operation &op = mOperations[name];
                Body inputBody;
                inputBody.loadXML(context, child);
                op.setInput(inputBody);
            } else if (namespaceManager.localName(child) == QLatin1String("header")) {
                Operation &op = mOperations[name];
                Header inputHeader;
                inputHeader.loadXML(context, child);
                op.addInputHeader(inputHeader);
            }
        }
        child = child.nextSiblingElement();
    }
}

// Parse <operation><output>
void SoapBinding::parseOperationOutput(ParserContext *context, const QString &name, const QDomElement &parent)
{
    QDomElement child = parent.firstChildElement();
    while (!child.isNull()) {
        NSManager namespaceManager(context, child);
        if (NSManager::soapNamespaces().contains(namespaceManager.nameSpace(child))) {
            if (namespaceManager.localName(child) == QLatin1String("body")) {
                Operation &op = mOperations[name];
                Body outputBody;
                outputBody.loadXML(context, child);
                op.setOutput(outputBody);
            } else if (namespaceManager.localName(child) == QLatin1String("header")) {
                Operation &op = mOperations[name];
                Header outputHeader;
                outputHeader.loadXML(context, child);
                op.addOutputHeader(outputHeader);
            }
        }

        child = child.nextSiblingElement();
    }
}

void SoapBinding::parseOperationFault(ParserContext *context, const QString &name, const QDomElement &parent)
{
    QDomElement child = parent.firstChildElement();
    while (!child.isNull()) {
        NSManager namespaceManager(context, child);
        if (NSManager::soapNamespaces().contains(namespaceManager.nameSpace(child))) {
            if (namespaceManager.localName(child) == QLatin1String("fault")) {
                Operation &op = mOperations[name];
                Fault fault;
                fault.loadXML(context, child);
                op.setFault(fault);
            }
        }
        child = child.nextSiblingElement();
    }
}

void SoapBinding::parsePort(ParserContext *context, const QDomElement &parent)
{
    QDomElement child = parent.firstChildElement();
    while (!child.isNull()) {
        NSManager namespaceManager(context, child);
        if (NSManager::soapNamespaces().contains(namespaceManager.nameSpace(child))) {
            if (namespaceManager.localName(child) == QLatin1String("address")) {
                mAddress.loadXML(context, child);
            }
        }

        child = child.nextSiblingElement();
    }
}

void SoapBinding::synthesizeBinding(ParserContext *context, QDomDocument &document, QDomElement &parent) const
{
    mBinding.saveXML(context, document, parent);
}

void SoapBinding::synthesizeOperation(ParserContext *context, const QString &name, QDomDocument &document, QDomElement &parent) const
{
    const Operation &op = mOperations[name];
    op.saveXML(context, document, parent);
}

void SoapBinding::synthesizeOperationInput(ParserContext *context, const QString &name, QDomDocument &document, QDomElement &parent) const
{
    const Operation &op = mOperations[name];
    op.input().saveXML(context, document, parent);
    const Headers inputHeaders = op.inputHeaders();
    for (const Header &header : inputHeaders) {
        header.saveXML(context, document, parent);
    }
}

void SoapBinding::synthesizeOperationOutput(ParserContext *context, const QString &name, QDomDocument &document, QDomElement &parent) const
{
    const Operation &op = mOperations[name];
    op.output().saveXML(context, document, parent);
    const Headers outputHeaders = op.outputHeaders();
    for (const Header &header : outputHeaders) {
        header.saveXML(context, document, parent);
    }
}

void SoapBinding::synthesizeOperationFault(ParserContext *context, const QString &name, QDomDocument &document, QDomElement &parent) const
{
    const Operation &op = mOperations[name];
    op.fault().saveXML(context, document, parent);
}

void SoapBinding::synthesizePort(ParserContext *context, QDomDocument &document, QDomElement &parent) const
{
    mAddress.saveXML(context, document, parent);
}

bool SoapBinding::Headers::contains(const Header &other) const
{
    for (const Header &header : std::as_const(*this)) {
        if (header.mMessage == other.mMessage && header.mPart == other.mPart && header.mUse == other.mUse &&
#if 0
                header.mEncodingStyle == other.mEncodingStyle &&
#endif
            header.mNameSpace == other.mNameSpace) {
            return true;
        }
    }
    return false;
}
