using System;
using System.Security.Cryptography.X509Certificates;
using System.Xml;

namespace pl.qumak
{
    class SoapMessage
    {
        public XmlElement Header { get; set; }
        public XmlElement Body { get; set; }
        public X509Certificate2 Certificate { get; set; }

        public XmlDocument GetXml(bool signed = false)
        {
            XmlDocument doc = new XmlDocument { PreserveWhitespace = true };

            XmlElement soapEnvelopeXml = doc.CreateElement("soap", "Envelope", "http://schemas.xmlsoap.org/soap/envelope/");
            soapEnvelopeXml.SetAttribute("xmlns:u", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

            XmlElement soapHeaderXml = doc.CreateElement("s", "Header", "http://schemas.xmlsoap.org/soap/envelope/");
            if (Header != null)
            {
                var imported = doc.ImportNode(Header, true);
                soapHeaderXml.AppendChild(imported);
            }
            soapEnvelopeXml.AppendChild(soapHeaderXml);

            XmlElement soapBodyXml = doc.CreateElement("soap", "Body", "http://schemas.xmlsoap.org/soap/envelope/");
            soapBodyXml.SetAttribute("Id", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "_1");
            if (Body == null)
            {
            }
            else
            {
                XmlNode imported = doc.ImportNode(Body, true);
                imported = RenameNode(imported, "http://datex2.eu/schema/3/messageContainer", "messageContainer");
                soapBodyXml.AppendChild(imported);
            }

            soapEnvelopeXml.AppendChild(soapBodyXml);
            doc.AppendChild(soapEnvelopeXml);

            if (signed)
            {
                SoapSigner signer = new SoapSigner();

                if (Certificate == null)
                {
                    throw new Exception("A X509 certificate is needed.");
                }

                XmlDocument tempDoc = new XmlDocument { PreserveWhitespace = true };
                tempDoc.LoadXml(doc.OuterXml);

                return signer.SignMessage(tempDoc, Certificate, SignAlgorithm.SHA256);
            }

            return doc;
        }

        public void ReadXml(XmlDocument document)
        {
            XmlNamespaceManager ns = new XmlNamespaceManager(document.NameTable);
            ns.AddNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");

            this.Header = document.DocumentElement.SelectSingleNode("//s:Header", ns) as XmlElement;
            this.Body = document.DocumentElement.SelectSingleNode("//s:Body", ns) as XmlElement;

            if (this.Body == null)
            {
                throw new Exception("No body found.");
            }
        }

        public static XmlNode RenameNode(XmlNode node, string namespaceURI, string qualifiedName)
        {
            if (node.NodeType == XmlNodeType.Element)
            {
                XmlElement oldElement = (XmlElement)node;
                XmlElement newElement =
                    node.OwnerDocument.CreateElement(qualifiedName, namespaceURI);
                while (oldElement.HasAttributes)
                {
                    newElement.SetAttributeNode(oldElement.RemoveAttributeNode(oldElement.Attributes[0]));
                }
                while (oldElement.HasChildNodes)
                {
                    newElement.AppendChild(oldElement.FirstChild);
                }
                if (oldElement.ParentNode != null)
                {
                    oldElement.ParentNode.ReplaceChild(newElement, oldElement);
                }
                return newElement;
            }
            else
            {
                return null;
            }
        }
    }


}
