using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Web;
using System.Xml;
using System.Xml.Serialization;
using MOH_CRA_XCRMS_Service.Entities;

namespace MOH_CRA_XCRMS_Service.Common
{
    public static class Helpers
    {
        private static readonly Dictionary<string, X509Certificate2> Certificates = new Dictionary<string, X509Certificate2>();

        /// <summary>
        /// Finds node in xml recursively by name
        /// </summary>
        /// <param name="xmlNode">Source xml node</param>
        /// <param name="name">Search node name</param>
        /// <param name="deep">If true performs recursive search</param>
        /// <returns></returns>
        internal static XmlNode GetSubnode(this XmlNode xmlNode, string name, bool deep = true)
        {
            foreach (XmlNode childNode in xmlNode.ChildNodes)
            {
                if (childNode.Name == name)
                    return childNode;

                if (deep)
                {
                    var node = childNode.GetSubnode(name, deep);
                    if (node != null && node.Name == name)
                        return node;
                }
            }
            return null;
        }

        /// <summary>
        /// Returns whether xml is in or not in GovTalk format
        /// </summary>
        /// <param name="xmlMessage">Source xml string</param>
        /// <returns></returns>
        internal static bool IsGovTalkMessage(this string xmlMessage)
        {
            return xmlMessage.StartsWith(@"<GovTalkMessage xmlns=""http://www.govtalk.gov.uk/CM/envelope"">");
        }

        /// <summary>
        /// When async transaction has been called through DEA, call result should be made by speial GovTalk message with Qualifier="poll". This type of request is being posted on different url
        /// </summary>
        /// <param name="xmlMessage">Source xml string</param>
        /// <returns></returns>
        internal static bool IsPollMessage(this string xmlMessage)
        {
            XmlDocument xdoc = new XmlDocument();
            xdoc.LoadXml(xmlMessage);
            XmlNode qualifierNode = xdoc.GetSubnode("Qualifier", true);
            return (qualifierNode != null && qualifierNode.InnerText.ToLower() == "poll");
        }


        /// <summary>
        /// ჩემი ვერსია, რომ არ დავაინსტალო, ვაკითხებ დისკიდან
        /// </summary>
        /// <returns></returns>
        internal static X509Certificate2 GetSigningCertificate_FileVersion(string subContractId, string certificateOrganizationUnit1, string unitName)
        {
            if (!Certificates.ContainsKey(subContractId))
            {
                var cert = GetCertificate(subContractId, certificateOrganizationUnit1, unitName);
                Certificates.Add(subContractId, cert);
            }
            return Certificates[subContractId];
        }

        internal static X509Certificate2 GetCertificate(string certPatch, string certificateOrganizationUnit1, string unitName)
        {
            var certfilePatch = ConfigurationSettings.AppSettings[certPatch + "_Certificate"];
            var certFile = HttpContext.Current.Server.MapPath(string.Format("{0}", certfilePatch));
            var passwordFile = certFile.Replace(".pfx", ".txt");
            var password = File.ReadAllText(passwordFile);
            return new X509Certificate2(certFile, password, X509KeyStorageFlags.MachineKeySet);
        }

        /// <summary>
        /// Put request parameter object xml in api acceptible xml format using template
        /// </summary>
        /// <param name="subcontractId">Value of SubcontractId of which request will be composed</param>
        /// <param name="paramObjectsDocument">XmlDocument which contains parameter objects' nodes</param>
        /// <returns></returns>
        /// //todo esec shesacvleli iqneba
        internal static XmlElement ComposeRequestXmlWithParamObjects(string subcontractId, XmlDocument paramObjectsDocument)
        {
            var document = new XmlDocument();
            var requestTemplatesXMLPatch = ConfigurationSettings.AppSettings["RequestTemplatesXMLFileName"];
            var requestTemplatesXMLFile = HttpContext.Current.Server.MapPath(requestTemplatesXMLPatch);
            document.Load(requestTemplatesXMLFile);

            var requestNode = (XmlElement)document.GetSubnode("Request");
            var subcontractNode = (XmlElement)requestNode.FirstChild;
            subcontractNode.InnerText = subcontractId;
            var paramsNode = (XmlElement)requestNode.LastChild;

            foreach (XmlNode paramObject in paramObjectsDocument.ChildNodes)
            {
                var pObject = document.ImportNode(paramObject, true);
                paramsNode.AppendChild(pObject);
            }

            return (XmlElement)document.FirstChild;
        }

        /// <summary>
        /// Deserializes response's 'ResultStatus' node into ResultStatus object
        /// </summary>
        /// <param name="response">Response xml string returned by service</param>
        /// <returns></returns>
        /// //todo esec agar unda ikos sachiro
        //internal static ResultStatus GetResponseStatus(string response)
        //{
        //    XmlDocument responseDoc = new XmlDocument();
        //    responseDoc.LoadXml(response);
        //    XmlNode statusNode = responseDoc.GetSubnode("ResultStatus");
        //    XmlSerializer serializer = new XmlSerializer(typeof(ResultStatus), statusNode.NamespaceURI);

        //    XmlReader reader = XmlReader.Create(new StringReader(statusNode.OuterXml));
        //    ResultStatus status = (ResultStatus)serializer.Deserialize(reader);

        //    return status;
        //}

        internal static XmlDocument GetRequestXML(string subContractId, string xMLOrganizationUnit, string privateNumber, string year,
            X509Certificate2 signingCertificate)
        {
            var requestXmlName = ConfigurationSettings.AppSettings[subContractId + "_RequestXMLFileName"];
            var requestXml = HttpContext.Current.Server.MapPath(requestXmlName);

            var requestDoc = new XmlDocument();
            requestDoc.Load(requestXml);

            XmlNodeList nodeListPid = requestDoc.GetElementsByTagName("PrivateNumber");
            nodeListPid[0].FirstChild.Value = privateNumber;

            XmlNodeList nodeListYear = requestDoc.GetElementsByTagName("BirthYear");
            nodeListYear[0].FirstChild.Value = year;

            ((XmlElement)requestDoc.GetSubnode("Request")).SignXml(signingCertificate, Guid.NewGuid());

            //long keyId;
            //var keyExchangeSubcontractId = ConfigurationSettings.AppSettings["KeyExchangeSubcontractId"];
            //byte[] key = SymetricEncrypting.GetSymetricEncryptionKey(keyExchangeSubcontractId, signingCertificate, out keyId);

            //((XmlElement)requestDoc.GetSubnode("Parameters")).EncryptXml(key, keyId);

            return requestDoc;
        }

        internal static ResultStatus GetResponseStatus(string response)
        {
            XmlDocument responseDoc = new XmlDocument();
            responseDoc.LoadXml(response);
            XmlNode statusNode = responseDoc.GetSubnode("ResultStatus");
            XmlSerializer serializer = new XmlSerializer(typeof(ResultStatus), statusNode.NamespaceURI);

            XmlReader reader = XmlReader.Create(new StringReader(statusNode.OuterXml));
            ResultStatus status = (ResultStatus)serializer.Deserialize(reader);

            return status;
        }


        internal static void ResponseXML_HEADER_Parse(XmlDocument xmlInputDoc, string msgNamespace,/* out XmlNamespaceManager xnsManager, */
              out string metodStr, out string correlationID, out string SMSSenderID
            /*, out string userName, out string password*/
            )
        {
            const string xpGt = "gt";
            const string xpMsg = "msg";
            const string gtNamespace = "http://www.govtalk.gov.uk/CM/envelope";

            const string xpClass = "/gt:GovTalkMessage/gt:Header/gt:MessageDetails/gt:Class";
            const string xpCorrId = "/gt:GovTalkMessage/gt:Header/gt:MessageDetails/gt:CorrelationID";
            const string xpSenderID = "/gt:GovTalkMessage/gt:Header/gt:SenderDetails/gt:IDAuthentication/gt:SenderID";
            //const string xpuserName = "/gt:GovTalkMessage/gt:Body/msg:Message/msg:UserName";
            //const string xppassword = "/gt:GovTalkMessage/gt:Body/msg:Message/msg:Password";

            var xnsManager = new XmlNamespaceManager(xmlInputDoc.NameTable);

            xnsManager.AddNamespace(xpGt, gtNamespace);
            xnsManager.AddNamespace(xpMsg, msgNamespace);

            //  Response ClassName
            metodStr = GetNodeText(xmlInputDoc.SelectSingleNode(xpClass, xnsManager)).Trim();
            //  Response CorrelationId
            correlationID = GetNodeText(xmlInputDoc.SelectSingleNode(xpCorrId, xnsManager));
            //  Response SenderID
            SMSSenderID = GetNodeText(xmlInputDoc.SelectSingleNode(xpSenderID, xnsManager));
            ////  Request UserName
            //userName = GetNodeText(xmlInputDoc.SelectSingleNode(xpuserName, xnsManager)).Trim();
            ////Request Password
            //password = GetNodeText(xmlInputDoc.SelectSingleNode(xppassword, xnsManager)).Trim();
            ////  return xpname;

        }

        private static string GetNodeText(XmlNode xNode)
        {
            return xNode != null ? xNode.InnerText : String.Empty;
        }

    }
}