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

using VRH.Common;
using VRH.Log4Pro.MultiLanguageManager;
using Vrh.XmlProcessing;

namespace Vrh.iScheduler.Report
{
    /// <summary>
    /// Ütemezés.
    /// </summary>
    public class SchedulerReportXmlParser : XmlParser
    {
        #region Constants

        /// <summary>
        /// A szókódok elé kerülő bevezető sztring.
        /// </summary>
        private const string WORDCODEPREFIX = "iSchedulerReport" + MultiLanguageManager.WORDCODE_PART_SEPARATOR;

        #endregion Constants

        #region Built'in classes

        #region ElementNames class
        /// <summary>
        /// Az XML fájlban ilyen elem nevek találhatóak egy "WebAppAction" elemben.
        /// </summary>
        internal new class ElementNames : XmlLinqBase.ElementNames
        {
            /// <summary>
            /// 'DatabaseConnectionString' elem név.
            /// </summary>
            public const string DATABASECONNECTIONSTRING = "DatabaseConnectionString";

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

            /// <summary>
            /// 'ObjectEditor' elem név.
            /// </summary>
            public const string PACKAGEDITOR = "PackageEditor";

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

            /// <summary>
            /// 'WordCodePrefix' elem név.
            /// </summary>
            public const string WORDCODEPREFIX = "WordCodePrefix";
        }
        #endregion ElementNames class

        #region AttributeNames static class
        /// <summary>
        /// Az XML fájlban ilyen attribútum nevek találhatóak egy 'Plugin' elemben.
        /// </summary>
        private static class AttributeNames
        {
        }
        #endregion AttributeNames static class

        #endregion Built'in classes

        #region Properties

        /// <summary>
        /// Az objektum típuson belüli csoportosítás azonosítója.
        /// Ha akció indításakor adtak meg GroupId paramétert, akkor annak az értéke,
        /// egyébként az XML paraméterező fájlban talált érték.
        /// </summary>
        public string GroupId { get; private set; }

        /// <summary>
        /// Adatbázishoz való kapcsolódáshoz már feloldott szabványos string.
        /// </summary>
        public string ConnectionString { get; private set; }

        /// <summary>
        /// A xml szövegek fordításakor használatos szókód előzmény.
        /// A fordításhoz a WordCodePrefix + "." + WordCode szókódot fogja használni.
        /// </summary>
        public string WordCodePrefix { get; private set; }

		#region PackageEditor property
		/// <summary>
		/// ObjectEditor használatához szükséges elemek.
		/// </summary>
		public PackageEditorElement PackageEditor
        {
            get
            {
                if (m_PackageEditor == null)
                {
                    m_PackageEditor = new PackageEditorElement(this.RootElement.Element(ElementNames.PACKAGEDITOR));
                }
                return m_PackageEditor;
            }
        }
        private PackageEditorElement m_PackageEditor = null;
		#endregion PackageEditor property

		#region PackageExecute property
		/// <summary>
		/// Execute-hoz használható elemek.
		/// </summary>
		public PackageExecuteElement PackageExecute
        {
            get
            {
                if (m_PackageExecute == null)
                {
                    m_PackageExecute = new PackageExecuteElement(this.RootElement.Element(ElementNames.PACKAGEEXECUTE));
                }
                return m_PackageExecute;
            }
        }
        private PackageExecuteElement m_PackageExecute = null;
        #endregion PackageExecute property

        /// <summary>
        /// A modulban az URL-ekben használható változók szótára.
        /// </summary>
        public VariableDictionary UrlVars { get; set; }

        /// <summary>
        /// Az XML fájl fizikai elérési útvonala.
        /// </summary>
        public string XmlParserConnectionString { get; private set; }

        /// <summary>
        /// A paraméterező fájl feldolgozása közben keletkezett hibák felsorolása.
        /// </summary>
        public List<string> ErrorList { get; private set; } = new List<string>();

        #endregion Properties

        #region Constructor
        /// <summary>
        /// Paraméterező XML fájl feldolgozása.
        /// </summary>
        /// <param name="xmlc">XmlParser kapcsolati objektum.</param>
        /// <param name="appPath">>Az alkalmazás alap mappája. Ez alatt van az App_Path.</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="groupId">URL paraméterben érkezhet, amely felülírja az XML-ben megadottat.</param>
        public SchedulerReportXmlParser(
            XmlConnection xmlc,
            string appPath,
            string lcid,
            Dictionary<string, string> otherVars,
            string groupId = null) : base(xmlc, appPath, lcid, otherVars)
        {
            try
            {
                this.UrlVars = new VariableDictionary(this.LCID);
                this.XmlParserConnectionString = xmlc.ToString();

                #region GroupId beállítása és ellenőrzése
                // Ha paraméterben érkezik, akkor az lesz a groupId
                if (string.IsNullOrWhiteSpace(groupId))
                {
                    this.GroupId = GetValue(this.RootElement.Element(ElementNames.GROUPID), "");
                    if (string.IsNullOrWhiteSpace(this.GroupId) || this.GroupId == SRConstants.Groups.All)
                    {
                        AddError($"The GroupId element is missing, empty or equal to \"{SRConstants.Groups.All}\" !");
                    }
                }
                else
                {
                    this.GroupId = groupId;
                }
                #endregion GroupId beállítása és ellenőrzése

                #region ConnectionString beállítása
                string csName = GetValue(this.RootElement.Element(ElementNames.DATABASECONNECTIONSTRING), "");
                if (string.IsNullOrWhiteSpace(csName))
                {
                    csName = SRConstants.DEFAULT_CONNECTIONSTRINGNAME;
                }
                try
                {
                    this.ConnectionString = ConnectionStringStore.GetSQL(csName);
                }
                catch (Exception ex)
                {
                    this.ErrorList.AddRange(VrhCommon.ErrorListBuilder(ex));
                }
                #endregion ConnectionString beállítása

                #region WordCodePrefix beállítása
                string wc = GetValue(this.RootElement.Element(ElementNames.WORDCODEPREFIX), "");
                if (string.IsNullOrWhiteSpace(wc))
                {
                    this.WordCodePrefix = WORDCODEPREFIX;
                }
                else
                {
                    this.WordCodePrefix = string.Concat(WORDCODEPREFIX,
                        wc.Trim().Trim(MultiLanguageManager.WORDCODE_PART_SEPARATOR[0]),
                        MultiLanguageManager.WORDCODE_PART_SEPARATOR);
                }
                #endregion WordCodePrefix beállítása
            }
            catch (Exception ex)
            {
                this.ErrorList.AddRange(VrhCommon.ErrorListBuilder(ex));
            }
            if (this.ErrorList.Any())
            {
                this.ErrorList.Insert(0, $"Error occured when the {nameof(SchedulerReportXmlParser)} initialization!");
            }
        }
        #endregion Constructor

        #region Private methods

        private void AddError(string message)
        {
            this.ErrorList.Add(message);
        }

        #endregion Private methods
    }
}