using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.Linq;
using System.Xml.Serialization;

using Vrh.XmlProcessing;

namespace Vrh.OneMessage
{
    /// <summary>
    /// OneMessage üzenetküldő paraméterező XML fájl leképezése.
    /// </summary>
    public sealed class OneMessageXmlParser : XmlParser
    {
        private const string ELEMENT_NOTFOUND = "Element \"{0}\" not found where \"{1}\" attribute equals \"{2}\"!";

        #region Private variables
        private readonly XElement m_MessageXE = null;
        #endregion Private variables

        #region ElementNames private classes
        private new class ElementNames : XmlLinqBase.ElementNames
        {
            /// <summary>
            /// 'Attachment' elem név.
            /// </summary>
            public const string ATTACHMENT = "Attachment";

            /// <summary>
            /// 'Attachments' elem név.
            /// </summary>
            public const string ATTACHMENTS = "Attachments";

            /// <summary>
            /// 'DeliveryDefinition' elem név.
            /// </summary>
            public const string DELIVERYDEFINITION = "DeliveryDefinition";

            /// <summary>
            /// 'DeliveryDefinitions' elem név.
            /// </summary>
            public const string DELIVERYDEFINITIONS = "DeliveryDefinitions";

            /// <summary>
            /// 'MessageBody' elem név.
            /// </summary>
            public const string MESSAGEBODY = "MessageBody";

            /// <summary>
            /// 'OneMessage' elem név.
            /// </summary>
            public const string ONEMESSAGE = "OneMessage";

            /// <summary>
            /// 'OneMessageDefinitions' elem név.
            /// </summary>
            public const string ONEMESSAGEDEFINITIONS = "OneMessageDefinitions";

            /// <summary>
            /// 'SendTo' elem név.
            /// </summary>
            public const string SENDTO = "SendTo";

            /// <summary>
            /// 'Subject' elem név.
            /// </summary>
            public const string SUBJECT = "Subject";
        }
        #endregion ElementNames private classes

        #region AttributeNames static class
        /// <summary>
        /// XML fájlokban ilyen attribútum nevek találhatóak egy MenuItem-ben.
        /// </summary>
        public static class AttributeNames
        {
            /// <summary>
            /// 'DeleteAfterSend' attribútum név.
            /// </summary>
            public const string DELETEAFTERSEND = "DeleteAfterSend";

            /// <summary>
            /// 'Delivery' attribútum név.
            /// </summary>
            public const string DELIVERY = "Delivery";

            /// <summary>
            /// 'Folder' attribútum név.
            /// </summary>
            public const string FOLDER = "Folder";

            /// <summary>
            /// 'Id' attribútum név.
            /// </summary>
            public const string ID = "Id";

            /// <summary>
            /// 'LCID' attribútum név.
            /// </summary>
            public const string LCID = "LCID";

            /// <summary>
            /// 'Name' attribútum név.
            /// </summary>
            public const string NAME = "Name";
        }
        #endregion AttributeNames static class

        #region Properties

        /// <summary>
        /// A már beazonosított (hozzárendelt) szállítási definició.
        /// </summary>
        public DeliveryDefinition Delivery { get; private set; }

        #region SendTo property
        /// <summary>
        /// Címzettek vesszővel elválasztott listája.
        /// </summary>
        public string SendTo
        {
            get
            {
                if (m_SendTo == null)
                {
                    m_SendTo = GetValue(m_MessageXE.Element(ElementNames.SENDTO), "");
                }
                return m_SendTo;
            }
        }
        private string m_SendTo = null;
        #endregion SendTo property

        #region Subject property
        /// <summary>
        /// A levél tárgya.
        /// </summary>
        public string Subject
        {
            get
            {
                if (m_Subject == null)
                {
                    m_Subject = GetValue(m_MessageXE.Element(ElementNames.SUBJECT), "");
                }
                return m_Subject;
            }
        }
        private string m_Subject = null;
        #endregion Subject property

        #region MessageBody property
        /// <summary>
        /// Az üzenet tartalma.
        /// </summary>
        public string MessageBody
        {
            get
            {
                if (m_MessageBody == null)
                {
                    m_MessageBody = GetValue(m_MessageXE.Element(ElementNames.MESSAGEBODY), "");
                }
                return m_MessageBody;
            }
        }
        private string m_MessageBody = null;
        #endregion MessageBody property

        #region Attachments property
        /// <summary>
        /// A paraméterező fájlban megadott csatolmányok.
        /// </summary>
        public List<AttachmentElement> Attachments
        {
            get
            {
                if (m_Attachments == null)
                {
                    m_Attachments = new List<AttachmentElement>();
                    XElement xe = m_MessageXE.Element(ElementNames.ATTACHMENTS);
                    if (xe != null)
                    {
                        string folder = GetValue(AttributeNames.FOLDER, xe, "");
                        m_IsDeleteAfterSend = GetValue(AttributeNames.DELETEAFTERSEND, xe, false);
                        m_IsInitializedDeleteAfterSend = true;
                        IEnumerable<XElement> attachmentsXE = xe.Elements(ElementNames.ATTACHMENT);
                        if (attachmentsXE != null && attachmentsXE.Any())
                        {
                            foreach (XElement attXE in attachmentsXE)
                            {
                                var ae = new AttachmentElement(attXE, folder);
                                if (!string.IsNullOrWhiteSpace(ae.File))
                                {   // Ha van érték is File tulajdonságokban, csak akkor adjuk hozzá
                                    m_Attachments.Add(ae);
                                }
                            }
                        }
                    }
                }
                return m_Attachments;
            }
        }
        private List<AttachmentElement> m_Attachments = null;
        #endregion Attachments property

        #region IsDeleteAfterSend property
        /// <summary>
        /// A csatolmányokat kell-e törölni a küldés után.
        /// </summary>
        public bool IsDeleteAfterSend
        {
            get
            {
                if (!m_IsInitializedDeleteAfterSend)
                {
                    XElement xe = m_MessageXE.Element(ElementNames.ATTACHMENTS);
                    if (xe != null)
                    {
                        m_IsDeleteAfterSend = GetValue(AttributeNames.DELETEAFTERSEND, xe, false);
                    }
                    m_IsInitializedDeleteAfterSend = true;
                }
                return m_IsDeleteAfterSend;
            }
        }
        private bool m_IsDeleteAfterSend = false;
        private bool m_IsInitializedDeleteAfterSend = false;
        #endregion IsDeleteAfterSend property

        #endregion Properties

        #region Constructor
        /// <summary>
        /// XML paraméterező fájl feldolgozásának konstruktora.
        /// </summary>
        /// <param name="xmlc">XmlParser kapcsolati sztring (connection string).</param>
        /// <param name="appPath">Az alkalmazás alap mappája. Ez alatt van az App_Data.</param>
        /// <param name="lcid">A környezetben érvényes nyelvi kód. Ha üres, akkor az XmlParser-ben beállított lesz érvényes.</param>
        /// <param name="otherVars">A környezetben az XmlParser részére létrehozott változók.</param>
        /// <param name="messageId"></param>
        /// <param name="delivery"></param>
        public OneMessageXmlParser(
            XmlConnection xmlc,
            string appPath,
            string lcid,
            Dictionary<string, string> otherVars,
            string messageId,
            string delivery = null)
            : base(xmlc, appPath, lcid, otherVars)
        {
            try
            {
                #region Üzenetdefiníciós XElement megkeresése és megjegyzése
                XElement defXE = this.RootElement.Element(ElementNames.ONEMESSAGEDEFINITIONS);
                if (defXE == null)
                {
                    throw new ApplicationException(string.Format(Messages.ERR_MISSINGELEMENT, ElementNames.ONEMESSAGEDEFINITIONS));
                }
                IEnumerable<XElement> messagesXE = defXE.Elements(ElementNames.ONEMESSAGE);
                if (messagesXE == null || !messagesXE.Any())
                {
                    throw new ApplicationException(string.Format(Messages.ERR_MISSINGELEMENT, ElementNames.ONEMESSAGE));
                }
                foreach (XElement messXE in messagesXE)
                {
                    string messId = GetValue(AttributeNames.ID, messXE, "", true, true);
                    string messLCID = GetValue(AttributeNames.LCID, messXE, "");
                    if (messId == messageId && (string.IsNullOrWhiteSpace(messLCID) || messLCID == this.LCID))
                    {
                        m_MessageXE = messXE;
                    }
                }
                if (m_MessageXE == null)
                {
                    throw new ApplicationException(string.Format(ELEMENT_NOTFOUND, ElementNames.ONEMESSAGE, AttributeNames.ID, messageId));
                }
                #endregion Üzenetdefiníciós XElement megkeresése és megjegyzése

                #region Delivery megkeresése és beállítása
                string deliveryName = delivery;
                if (string.IsNullOrWhiteSpace(deliveryName))
                {
                    deliveryName = GetValue(AttributeNames.DELIVERY, m_MessageXE, "", true, true);
                }
                XElement deliveryDefsXE = this.RootElement.Element(ElementNames.DELIVERYDEFINITIONS);
                if (deliveryDefsXE == null)
                {
                    throw new ApplicationException(string.Format(Messages.ERR_MISSINGELEMENT, ElementNames.DELIVERYDEFINITIONS));

                }
                IEnumerable<XElement> deliveriesXE = deliveryDefsXE.Elements(ElementNames.DELIVERYDEFINITION);
                if (deliveriesXE == null || !deliveriesXE.Any())
                {
                    throw new ApplicationException(string.Format(Messages.ERR_MISSINGELEMENT, ElementNames.DELIVERYDEFINITION));
                }
                foreach (XElement delXE in deliveriesXE)
                {
                    string delName = GetValue(AttributeNames.NAME, delXE, "", true, true);
                    if (delName == deliveryName)
                    {
                        this.Delivery = new DeliveryDefinition(delXE);
                    }
                }
                if (this.Delivery == null)
                {
                    throw new ApplicationException(string.Format(ELEMENT_NOTFOUND, ElementNames.DELIVERYDEFINITION, AttributeNames.NAME, deliveryName));
                }
                #endregion Delivery megkeresése és beállítása
            }
            catch (Exception ex)
            {
                throw new ApplicationException("Error occured when OneMessageXmlParser initialization!", ex);
            }
        }
        #endregion Constructor
    }
}