using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

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

namespace Vrh.OneReport
{
    /// <summary>
    /// A 'ReportDirectory' elem leképezése az XML paraméterfájlból.
    /// Teljes XmlParser struktúra.
    /// </summary>
    public class DirectoryXmlParser : XmlParser
    {
        #region Built'in classes

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

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

		#endregion Built'in classes

		#region Private variables

		#endregion Private variables


		#region Properties

		#region CommonPresets property
		/// <summary>
		/// A riporthoz tartozó alapértelmezett paraméter-értékek.
		/// Késleltetett feldolgozással, hogy ha csak a riport elnevezése kell, akkor
		/// ne töltsön időt a Preset-ek összeszedésével.
		/// Mindig van értéke, de lehet 0 tételszámmal, ha nincs Preset.
		/// </summary>
		public List<PresetElement> CommonPresets
		{
			get
			{
				if (m_CommonPresets == null)
				{
					this.m_CommonPresets = PresetElement.PresetElementList(this.RootElement.Element(XName.Get(ElementNames.COMMONPRESETS)));
				}
				return m_CommonPresets;
			}
		}
		private List<PresetElement> m_CommonPresets = null;
		#endregion CommonPresets property


		#region Reports property
		/// <summary>
		/// A "Report" elemek listája.
		/// Mindig van értéke, ha nincs "Report" elem, akkor egy 0 elemű lista.
		/// </summary>
		public List<ReportListItem> Reports
        {
            get
            {
                if (m_Reports == null)
                {
                    m_Reports = new List<ReportListItem>();
                    IEnumerable<XElement> reportsXE = this.RootElement.Elements(ElementNames.REPORT);
                    if (reportsXE != null && reportsXE.Any())
                    {
                        foreach (var reportXE in reportsXE)
                        {
                            m_Reports.Add(new ReportListItem(reportXE, this.CommonPresets, this.LCID));
                        }
                    }
                }
                return m_Reports;
            }
        }
        private List<ReportListItem> m_Reports = null;
        #endregion Reports property

        #endregion Properties

        #region Constructor
        /// <summary>
        /// A OneReport xml paraméter fájl "General" elemének feldolgozása.
        /// A "General" egy önálló XmlParser struktúra.
        /// </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>
        public DirectoryXmlParser(
            XmlConnection xmlc,
			string appPath = null,
            string lcid = null,
			Dictionary<string, string> otherVars = null)
            : base(xmlc, appPath, lcid, otherVars)
        {
            try
            {
            }
            catch (Exception ex)
            {
                throw new ApplicationException($"Error in {nameof(GeneralXmlParser)} constructor!", ex);
            }
        }
        #endregion Constructor

        #region Public methods

        #region GetDisplayName public method
        /// <summary>
        /// Egy megadott riport megnevezésével tér vissza.
        /// </summary>
        /// <param name="reportId">A riport azonosítója.</param>
        /// <returns>Ha megtalálja, akkor az ottani megnevezés, ha nem akkor null.</returns>
        /// <remarks>
        /// Ha csak a riport megnevezése kell ezt használd, mert ez nem kér le minden egyebet!
        /// </remarks>
        public string GetDisplayName(string reportId)
        {
            string result = null;
            if (m_Reports == null)
            {
                IEnumerable<XElement> reportsXE = this.RootElement.Elements(ElementNames.REPORT);
                if (reportsXE != null && reportsXE.Any())
                {
                    foreach (var reportXE in reportsXE)
                    {
                        string id = GetValue(reportXE.Attribute(ReportListItem.AttributeNames.ID), "", true, true);
                        if (id == reportId)
                        {
                            var reportListItem = new ReportListItem(reportXE, this.CommonPresets, this.LCID);
                            return reportListItem.DisplayName;
                        }
                    }
                }
            }
            else
            {
                return m_Reports.FirstOrDefault(x => x.Id == reportId)?.DisplayName;
            }
            return result;
        }
        #endregion GetDisplayName public method

        #region List public method
        /// <summary>
        /// Riportok vagy presetek listázása a <paramref name="listMode"/>
        /// paraméternek megfelelően.
        /// </summary>
        /// <param name="listMode">A listázás módja.</param>
        /// <param name="listlcid">Melyik nyelvi riportok vagy ahhoz tartozó presetek kerüljenek bele.</param>
        /// <param name="reportId">OnlyPreset-nél kötelező paraméter.</param>
        /// <returns>Egy SelectListJSON típusú elemekből álló lista.</returns>
        public List<SelectListJSON> List(string listMode, string listlcid, string reportId = null)
        {
            List<SelectListJSON> result = new List<SelectListJSON>();
            listMode = listMode.ToLower();

            if (listMode == ReportService.ListModes.OnlyPreset)
            {   
                #region Egy adott riportoz tartozó preseteket kell visszaadni
                var report = this.Reports.FirstOrDefault(x => x.Id == reportId);
                if (report == null)
                {   // ha nincs megadva a riport azonosító, akkor üres listát adjon vissza
                    return result;
                    //throw new ApplicationException($"Report (Id={reportId}) does not exist in the \"ReportDirectory\" element!");
                }
                foreach (var preset in report.Presets)
                {
                    result.Add(new SelectListJSON
                    {
                        Value = preset.Id,
                        Text = string.Concat(preset.DisplayName, " (", preset.Id.ToString(), ")")
                    });
                }
                #endregion Egy adott riportoz tartozó preseteket kell visszaadni
            }
            else
            {
                if (listMode == ReportService.ListModes.PresetNo || listMode == ReportService.ListModes.OnlyId)
                {    
                    #region Csak a riportok kellenek, különböző ID-val 
                    foreach (var report in this.Reports)
                    {
                        string id = report.Id.ToString();
                        string[] replcids = report.LCIDList.Split(',');
                        foreach (var replcid in replcids.Where(x => string.IsNullOrWhiteSpace(listlcid) || x=="*" || x == listlcid))
                        {
                            if (listMode == ReportService.ListModes.PresetNo)
                            {
                                id = string.Concat(id, "/", replcid, "/*");
                            }
                            result.Add(new SelectListJSON
                            {
                                Value = id,
                                Text = string.Concat(report.DisplayName, " (", report.Id.ToString(), "/", replcid, ")")
                            });
                        }
                    }
                    #endregion Csak a riportok kellenek, különböző ID-val 
                }
                else
                {
                    #region Amikor a presetek is kellenek
                    foreach (var report in this.Reports)
                    {
                        string[] replcids = report.LCIDList.Split(',');
                        foreach (var replcid in replcids.Where(x => string.IsNullOrWhiteSpace(listlcid) || x == listlcid))
                        {
                            string id;
                            if (listMode == ReportService.ListModes.PresetYes)
                            {   // alapértelmezés hozzáadása
                                id = string.Concat(report.Id, "/", replcid, "/*");
                                result.Add(new SelectListJSON
                                {
                                    Value = id,
                                    Text = string.Concat(report.DisplayName, ", * (", id, ")")
                                });
                            }

                            foreach (var preset in report.Presets)
                            {   // presetek hozzáadása
                                id = string.Concat(report.Id, "/", replcid, "/", preset.Id);
                                result.Add(new SelectListJSON
                                {
                                    Value = id,
                                    Text = string.Concat(report.DisplayName, ", ", preset.DisplayName, " (", id, ")")
                                });
                            }
                        }
                    }
                    #endregion Amikor a presetek is kellenek
                }
            }
            return result;
        }
        #endregion List public method

        #endregion Public methods
    }
}
