namespace Vrh.OneReport
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.IO;
    using System.Xml.Linq;

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

    using Vrh.OneReport.Lib.Areas.OneReport.Models;

    public class ReportXMLProcessor : LinqXMLProcessorBase
    {
        #region Elements and Attributes private classes
        private class Elements
        {
            public const string REPORTDEFINITIONS = "ReportDefinitions";
            public const string STRINGS = "strings";
            public const string STRING = "string";
            public const string GENERAL = "general";

            //general alá tartozó elemek
            public const string CONNECTIONSTRING = "ConnectionString";
            public const string DEFAULTLCID = "defaultLCID";
            public const string INPUTROOT = "InputRoot";
            public const string DEFAULTOUTPUT = "defaultoutput";
            public const string WORDCODEPREFIX = "WordCodePrefix";
            public const string EXTERNALPARAMETERPRESETXML = "ExternalParameterPresetXml";
            public const string TIMEOUT = "Timeout";
            public const string EXPORT = "Export";  //ez van a <report alatt is>

            // Reports és az alá tartozó elemek
            public const string REPORTS = "reports";
            public const string REPORT = "report";
            public const string DISPLAYNAME = "Displayname";
            public const string EXTERNALPARAMETERPRESETS = "ExternalParameterPresets";
            public const string PRESET = "Preset";
            public const string PARAMETER = "Parameter";
            public const string VALUE = "Value";
            public const string EXTERNALPARAMETERS = "ExternalParameters";
            public const string INTERNALPARAMETERS = "InternalParameters";
            public const string CONDITIONS = "Conditions";
            public const string CONDITION = "Condition";
            public const string OUTPUT = "output";
            public const string REPORTFILE = "reportfile";

            //datasets, dataset, initcommand, datacommand, sql
            public const string DATASETS = "datasets";
            public const string DATASET = "dataset";
            public const string INITCOMMAND = "initcommand";
            public const string DATACOMMAND = "datacommand";
            public const string SQL = "sql";
        }

        private class Attributes
        {
            //General/Timout
            public const string SQLQUERY = "Sqlquery";
            public const string ASYNCPOSTBACKTIMEOUT = "AsyncPostBackTimeOut";
            public const string EXECUTIONTIMEOUT = "executionTimeout";

            //Report
            public const string ID = "id";
            public const string LCID = "LCID";
            public const string REPORTFILE = "reportfile";
            public const string CONNECTIONSTRING = "connectionstring";  // report, dataset

            //Displayname
            public const string WORDCODE = "WordCode";

            //Preset
            public const string NAME = "Name";  // String, ConnectionString, Preset, Parameter
            public const string DESCRIPTION = "Description";

            //Condition
            public const string TYPE = "Type";
            public const string TEST = "Test";
            public const string WITH = "With";

            //output
            public const string ACTION = "action";
            public const string FILE = "file";      // Export
            public const string FOLDER = "folder";  // Export
            public const string FORMAT = "format";  // Export

            //others
            public const string NAMELOWER = "name"; // reportfile, dataset, connectionstring
            public const string TYPELOWER = "type"; // datacommand
        }
        #endregion Elements and Attributes private classes

        public ReportXMLProcessor() : base()
        {
            _xmlNameSpace = string.Empty;
        }

        #region Public methods

        #region LoadReport method
        /// <summary>
        /// A OneReport.xml feldolgozása, betöltése.
        /// </summary>
        /// <param name="reportId">A keresett report azonosítója.</param>
        /// <param name="xmlc">XmlParser kapcsolati objektum.</param>
        /// <param name="appPath">A relatív útvonal feloldásának mappája.</param>
        /// <param name="LCID">A környezetben érvényes vagy a kért nyelvi kód.</param>
        /// <returns></returns>
        public ReportXMLModel LoadReport(string reportId, XmlConnection xmlc, string appPath, string LCID)
        {
            var model = new ReportXMLModel();
            try
            {
                _AppPath = appPath;
                _XmlParser_Root = xmlc.Root;
                _xmlFileDefinition = xmlc.File;
                string defaultRoot = System.IO.Path.GetDirectoryName(xmlc.File);

                GetDefaults(this.GetXElement(Elements.GENERAL), ref model);
                if (String.IsNullOrWhiteSpace(model.InputRoot)) model.InputRoot = defaultRoot;
                if (String.IsNullOrWhiteSpace(model.DefaultOutput.Folder)) model.DefaultOutput.Folder = defaultRoot;

                if (String.IsNullOrEmpty(LCID)) LCID = model.DefaultLCID;
                model.RequestLCID = LCID;

                // !!! Előbb kell a fenti értékadás, mert a FIX stringekhez kell már a RequestLCID !!!   
                XElement strings = this.GetXElement(Elements.STRINGS);
                if (strings != null) GetStrings(strings, ref model);

                IEnumerable<XElement> elements = GetAllXElements(Elements.REPORTDEFINITIONS, Elements.REPORTS, Elements.REPORT);
                XElement reportElement = GetReportById(GetAllXElements(Elements.REPORTDEFINITIONS, Elements.REPORTS, Elements.REPORT), reportId, LCID);
                if (reportElement == null) throw new ApplicationException($"Report is not found! Id={reportId}");
                ReadReport(reportElement, ref model);
            }
            catch (Exception ex)
            {
                throw new Exception($"Error when load report, id: {reportId}.", ex);
            }

            return model;
        }
        #endregion LoadReport method

        #region GetAllReport methods
        public Dictionary<string, string> GetAllReport(string xmlPath)
        {
            var result = new Dictionary<string, string>();

            try
            {
                _xmlFileDefinition = xmlPath;

                var reports = GetAllXElements(Elements.REPORTDEFINITIONS, Elements.REPORTS, Elements.REPORT);

                foreach (var report in reports)
                {
                    result.Add(GetAttribute(report, Attributes.ID, ""), GetAttribute(report, Attributes.LCID, ""));
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"Error when get all report from xml! Xml: {xmlPath}.", ex);
            }

            return result;
        }

        /// <summary>
        /// Az összes report listáját eredményezi egy szótárban.
        /// </summary>
        /// <param name="xmlPath"></param>
        /// <param name="LCID"></param>
        /// <param name="listmode"></param>
        /// <param name="reportId"></param>
        /// <returns></returns>
        public Dictionary<string, string> GetAllReport(string xmlPath, string LCID, string listmode, string reportId)
        {
            var result = new Dictionary<string, string>();

            try
            {
                _xmlFileDefinition = xmlPath;

                string wordCodePrefix = String.Concat(GetElementValue(GetXElement(Elements.GENERAL, Elements.WORDCODEPREFIX), Constants.DEFAULT_XML_WORDCODEPREFIX), ".");

                foreach (XElement report in GetAllXElements(Elements.REPORTDEFINITIONS, Elements.REPORTS, Elements.REPORT))
                {
                    string id = GetAttribute(report, Attributes.ID, "");
                    string lcidsall = GetAttribute(report, Attributes.LCID, "");

                    if (String.IsNullOrWhiteSpace(reportId) || id == reportId)
                    {
                        #region Preset-ek megszerzése, ha kell
                        var presets = new Dictionary<string, string>();
                        if (listmode == ReportService.ListModes.PresetYes
                            || listmode == ReportService.ListModes.OnlyPreset
                            || listmode == ReportService.ListModes.WithoutDefaultPreset)
                        {   //csak azért szűrünk, hogy feleslegesen ne töltse ezzel az időt
                            XElement presetsElement = report.Element(XName.Get(Elements.EXTERNALPARAMETERPRESETS, _xmlNameSpace));
                            if (presetsElement != null)
                            {
                                foreach (XElement preset in presetsElement.Elements(XName.Get(Elements.PRESET, _xmlNameSpace)))
                                {
                                    XAttribute nameAttribute = preset.Attribute(XName.Get(Attributes.NAME, _xmlNameSpace));
                                    if (nameAttribute != null && !String.IsNullOrEmpty(nameAttribute.Value))
                                    {
                                        XAttribute description = preset.Attribute(XName.Get(Attributes.DESCRIPTION, _xmlNameSpace));
                                        string desc = nameAttribute.Value;
                                        if (description != null && !String.IsNullOrWhiteSpace(description.Value)) desc = description.Value;
                                        presets.Add(nameAttribute.Value, desc);
                                    }
                                }
                            }
                        }
                        #endregion Preset-ek megszerzése, ha kell

                        if (listmode != ReportService.ListModes.OnlyPreset) //ha üres a reportId, akkor nem lehet OnlyPreset a listmode
                        {
                            #region Riport lista változatok

                            #region Riport címének és szókódjának (titleDefault, titleWordCode) megszerzése
                            string titleDefault = "";
                            string titleWordCode = "";

                            XElement displayElement = report.Element(XName.Get(Elements.DISPLAYNAME, _xmlNameSpace));
                            if (displayElement != null)
                            {
                                XAttribute wordCodeAttribute = displayElement.Attribute(XName.Get(Attributes.WORDCODE, _xmlNameSpace));
                                titleDefault = String.IsNullOrEmpty(displayElement.Value) ? id : displayElement.Value;
                                if (wordCodeAttribute != null && !String.IsNullOrEmpty(wordCodeAttribute.Value))
                                {
                                    titleWordCode = String.Concat(wordCodePrefix, wordCodeAttribute.Value);
                                }
                            }
                            #endregion Riport címének és szókódjának (titleDefault, titleWordCode) megszerzése


                            string[] lcids = lcidsall.Split(',');
                            foreach (string lcid in lcids.Where(x => String.IsNullOrEmpty(LCID) || x == LCID))
                            {
                                //reportcím fordításának megszerzése
                                string title = String.IsNullOrEmpty(titleWordCode) ? titleDefault : MultiLanguageManager.GetTranslation(titleWordCode, null, lcid);
                                SelectListJSON slj;

                                #region Alapértelmezett paraméterezés (preset nélküli) elem létrehozása
                                if (listmode != ReportService.ListModes.WithoutDefaultPreset)
                                {
                                    slj = GetListItem(listmode, title, id, lcid, "*", "*");
                                    result.Add(Guid.NewGuid().ToString(), $"{slj.Text}¤{slj.Value}");
                                }
                                #endregion Alapértelmezett paraméterezés (preset nélküli) elem létrehozása

                                #region Többi preset hozzáadása, ha van
                                foreach (var item in presets)
                                {
                                    slj = GetListItem(listmode, title, id, lcid, item.Key, item.Value);
                                    result.Add(Guid.NewGuid().ToString(), $"{slj.Text}¤{slj.Value}");
                                }
                                #endregion Többi preset hozzáadása, ha van
                            }
                            #endregion Riport lista változatok
                        }
                        else
                        {
                            #region Csak a presetek listája

                            result.Add(Guid.NewGuid().ToString(), $"*¤*"); //alapértelmezett paraméterezés jelölése
                            foreach (var item in presets)
                            {
                                result.Add(Guid.NewGuid().ToString(), $"{item.Value} ({item.Key})¤{item.Key}");
                            }

                            #endregion Csak a presetek listája
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"Error when get all report from xml! Xml: {xmlPath}.", ex);
            }

            return result;
        }
        #endregion GetAllReport methods

        #endregion Public methods

        #region Private Methods

        /// <summary>
        /// A paraméterek ismeretében előállítja a Value és Text értékét.
        /// </summary>
        /// <param name="listmode"></param>
        /// <param name="title"></param>
        /// <param name="id"></param>
        /// <param name="lcid"></param>
        /// <param name="presetid"></param>
        /// <returns></returns>
        private SelectListJSON GetListItem(string listmode, string title, string id, string lcid, string presetid, string presetname)
        {
            SelectListJSON slj = new SelectListJSON();
            switch (listmode)
            {
                case ReportService.ListModes.PresetYes:
                case ReportService.ListModes.WithoutDefaultPreset:
                    slj.Value = $"{id}/{lcid}/{presetid}";
                    slj.Text = $"{(String.IsNullOrWhiteSpace(title) ? slj.Value : title)}, {presetname} ({id}/{lcid}/{presetid})";
                    break;
                case ReportService.ListModes.OnlyId:
                    slj.Value = $"{id}";
                    slj.Text = $"{(String.IsNullOrWhiteSpace(title) ? slj.Value : title)} ({id}/{lcid})";
                    break;
                default:    //ReportService.ListModes.PresetNo az alapértelmezés
                    slj.Value = $"{id}/{lcid}/{presetid}";
                    slj.Text = $"{(String.IsNullOrWhiteSpace(title) ? slj.Value : title)} ({id}/{lcid})";
                    break;
            }
            return slj;
        }

        private XElement GetElementByAttributeValue(IEnumerable<XElement> elements, string attributeName, string attributeValue)
        {
            XElement result = null;

            try
            {
                foreach (var element in elements)
                {
                    foreach (var attr in element.Attributes())
                    {
                        if (attr.Name == attributeName)
                        {
                            if (attr.Value == attributeValue)
                            {
                                result = element;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"Get Element By Attribute Value error, element: {attributeName}, value{attributeValue}.", ex);
            }

            return result;
        }

        private XElement GetReportById(IEnumerable<XElement> elements, string reportId, string LCID)
        {
            XElement result = null;

            try
            {
                foreach (var element in elements)
                {
                    foreach (var attr in element.Attributes())
                    {
                        if (attr.Name == Attributes.ID)
                        {
                            if (attr.Value.ToLower() == reportId.ToLower())
                            {
                                foreach (var attrToLCID in element.Attributes())
                                {
                                    if (attrToLCID.Name == Attributes.LCID)
                                    {
                                        if (attrToLCID.Value.Contains(LCID))
                                        {
                                            result = element;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"Get Report By Id error, reportId: {reportId}, LCID{LCID}.", ex);
            }
            return result;
        }

        private void GetDefaults(XElement defaults, ref ReportXMLModel model)
        {
            try
            {
                model.DefaultConnectionStringName = defaults.Element(Elements.CONNECTIONSTRING)?.Value;
                if (string.IsNullOrWhiteSpace(model.DefaultConnectionStringName))
                {
                    model.DefaultConnectionStringName = Constants.DEFAULT_CONNECTIONSTRING_NAME;
                }
                model.DefaultLCID = defaults.Element(Elements.DEFAULTLCID)?.Value;
                model.InputRoot = defaults.Element(Elements.INPUTROOT)?.Value;

                var defaultOutputs = defaults.Element(Elements.DEFAULTOUTPUT);
                model.DefaultOutput.Action = this.GetAttribute(defaultOutputs, Attributes.ACTION, "");
                model.DefaultOutput.File = this.GetAttribute(defaultOutputs, Attributes.FILE, "");
                model.DefaultOutput.Folder = this.GetAttribute(defaultOutputs, Attributes.FOLDER, "");
                model.DefaultOutput.Format = this.GetAttribute(defaultOutputs, Attributes.FORMAT, "");

                var timeoutTag = defaults.Element(Elements.TIMEOUT);
                model.ReportTimeOuts.SQLQuery = GetAttribute(timeoutTag, Attributes.SQLQUERY, 60);
                model.ReportTimeOuts.AsyncPostBackTimeOut = GetAttribute(timeoutTag, Attributes.ASYNCPOSTBACKTIMEOUT, 60);
                model.ReportTimeOuts.ExecutionTimeout = GetAttribute(timeoutTag, Attributes.EXECUTIONTIMEOUT, 120);

                var exportelem = defaults.Element(Elements.EXPORT);
                if (exportelem == null)
                {
                    model.DefaultExport = new ReportXMLModel.ExportElement { Format = ReportService.ExportFormats.CSV };
                }
                else
                {
                    model.DefaultExport = new ReportXMLModel.ExportElement
                    {
                        Format = GetAttribute(exportelem, Attributes.FORMAT, ReportService.ExportFormats.CSV).ToLower(),
                        File = GetAttribute(exportelem, Attributes.FILE, "")
                    };
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Error when get defaults!", ex);
            }
        }

        private void GetStrings(XElement strings, ref ReportXMLModel model)
        {
            try
            {
                foreach (var stringItem in strings.Elements())
                {
                    model.Strings.Add(GetAttribute(stringItem, Attributes.NAME, ""), stringItem.Value);
                }

                #region Add fix strings

                string df = "yyyyMMdd";
                DateTime now = DateTime.Now;
                System.Globalization.CultureInfo ci = new System.Globalization.CultureInfo(model.RequestLCID);
                DayOfWeek firstDayOfWeek = ci.DateTimeFormat.FirstDayOfWeek;
                int difference = firstDayOfWeek - now.DayOfWeek;
                DateTime monday = now.AddDays(difference > 0 ? (difference - 7) : difference); //ez a hét kezdőnapja, de nem biztos, hogy hétfő
                while (monday.DayOfWeek != DayOfWeek.Monday) monday = monday.AddDays(1);
                DateTime firstOfMonth = new DateTime(now.Year, now.Month, 1);

                model.Strings.Add("LCID", model.RequestLCID);
                model.Strings.Add("TODAY", now.ToString(df));
                model.Strings.Add("YESTERDAY", now.AddDays(-1).ToString(df));
                model.Strings.Add("NOW", now.ToString(df + "HHmmss"));

                model.Strings.Add("THISWEEKMONDAY", monday.ToString(df));
                model.Strings.Add("THISWEEKFRIDAY", monday.AddDays(4).ToString(df));
                model.Strings.Add("LASTWEEKMONDAY", monday.AddDays(-7).ToString(df));
                model.Strings.Add("LASTWEEKFRIDAY", monday.AddDays(-3).ToString(df));

                model.Strings.Add("THISMONTH1STDAY", firstOfMonth.ToString(df));
                model.Strings.Add("THISMONTHLASTDAY", firstOfMonth.AddMonths(1).AddDays(-1).ToString(df));
                model.Strings.Add("LASTMONTH1STDAY", firstOfMonth.AddMonths(-1).ToString(df));
                model.Strings.Add("LASTMONTHLASTDAY", firstOfMonth.AddDays(-1).ToString(df));

                #endregion Add fix strings
            }
            catch (Exception ex)
            {
                throw new Exception("Error when get strings!", ex);
            }
        }

        /// <summary>
        /// Report attribútumainak és elemeinek feldolgozása.
        /// </summary>
        /// <param name="reportXE">A megtalált report elem (XElement).</param>
        /// <param name="model">Egy ReportXMLModel, melynek értékei beállítódnak.</param>
        private void ReadReport(XElement reportXE, ref ReportXMLModel model)
        {
            try
            {
                model.CurrentReport = new ReportXMLModel.Report()
                {
                    Id = GetAttribute(reportXE, Attributes.ID, ""),
                    LCID = GetAttribute(reportXE, Attributes.LCID, ""),
                    FilePath = Path.Combine(model.InputRoot, ApplyStringValue(GetAttribute(reportXE, Attributes.REPORTFILE, ""), model.Strings)),
                    ConnectionStringName = GetAttribute(reportXE, Attributes.CONNECTIONSTRING, "")
                };

                #region model.CurrentReport.Output beállítása
                XElement outputEX = reportXE.Element(Elements.OUTPUT);
                if (outputEX != null)
                {
                    model.CurrentReport.Output.Action = GetAttribute(outputEX, Attributes.ACTION, "");
                    model.CurrentReport.Output.File = GetAttribute(outputEX, Attributes.FILE, "");
                    model.CurrentReport.Output.Folder = GetAttribute(outputEX, Attributes.FOLDER, "");
                    model.CurrentReport.Output.Format = GetAttribute(outputEX, Attributes.FORMAT, "");
                }
                #endregion CurrentReport.Output beállítása

                GetAllPresets(reportXE, ref model);   //stringek belül behelyettesítődnek
                GetAllExternalParameters(reportXE, ref model);    //stringek belül behelyettesítődnek
                GetAllInternalParameters(reportXE, ref model);    //stringek NEM helyettesítődnek be !!!
                ReadParameters(reportXE, ref model);
                ReadDataSets(reportXE, ref model);

                model.CurrentReport.DisplayName = GetDisplayname(reportXE, model);//GetSubElementStringValue(report, "Displayname");

                #region model.CurrentReport.Export beállítása

                XElement exportXE = reportXE.Element(Elements.EXPORT);
                if (exportXE == null)
                {
                    model.CurrentReport.Export = model.DefaultExport;
                }
                else
                {
                    model.CurrentReport.Export = new ReportXMLModel.ExportElement
                    {
                        Format = GetAttribute(exportXE, Attributes.FORMAT, model.DefaultExport.Format).ToLower(),
                        File = GetAttribute(exportXE, Attributes.FILE, model.DefaultExport.File)
                    };
                }
                switch (model.CurrentReport.Export.Format.ToLower())
                {
                    case ReportService.ExportFormats.CSV:
                    case ReportService.ExportFormats.XML:
                        break;
                    default:
                        throw new ApplicationException($"The possible values for 'report.Export.format' attribute: {ReportService.ExportFormats.CSV}, {ReportService.ExportFormats.XML} !");
                }
                if (String.IsNullOrWhiteSpace(model.CurrentReport.Export.File))
                {
                    string sep = Constants.NameSeparator;
                    string file = String.Concat(model.CurrentReport.Id, "_", sep, "NOW", sep, ".", model.CurrentReport.Export.Format);
                    model.CurrentReport.Export.File = Path.Combine(Constants.DEFAULT_EXPORTFOLDER,file);
                }
                model.CurrentReport.Export.File = ApplyStringValue(model.CurrentReport.Export.File, model.Strings);

                #endregion model.CurrentReport.Export beállítása
            }
            catch (Exception ex)
            {
                throw new Exception("Error when read report!", ex);
            }
        }

        #region GetAllPresets    
        /// <summary>
        /// Kiszedi az összes érvényes ExternalParameterPresetetet az XML-ből, és betölti őket paraméterben kapott modelosztályba.
        /// A stringek behelyettesítése is megtörténik.
        /// </summary>
        /// <param name="reportElement">A report element , ami alatt  apresetek találhatóak</param>
        /// <param name="model">a riport BI modelje</param>
        private void GetAllPresets(XElement reportElement, ref ReportXMLModel model)
        {
            model.ExternalParameterPresets.Clear();
            XElement presetsElement = reportElement.Element(XName.Get(Elements.EXTERNALPARAMETERPRESETS, _xmlNameSpace));
            if (presetsElement != null)
            {
                foreach (var presetElement in presetsElement.Elements(XName.Get(Elements.PRESET, _xmlNameSpace)))
                {
                    XAttribute nameAttribute = presetElement.Attribute(XName.Get(Attributes.NAME, _xmlNameSpace));
                    if (nameAttribute != null && !String.IsNullOrEmpty(nameAttribute.Value))
                    {
                        Preset p = new Preset()
                        {
                            PresetName = nameAttribute.Value,
                            Parameters = new List<SimpleKeyValuePair>(),
                        };
                        foreach (var parameterElement in presetElement.Elements(XName.Get(Elements.PARAMETER, _xmlNameSpace)))
                        {
                            XAttribute pname = parameterElement.Attribute(XName.Get(Attributes.NAME, _xmlNameSpace));
                            XElement value = parameterElement.Element(XName.Get(Elements.VALUE, _xmlNameSpace));
                            if (pname != null && value != null && !String.IsNullOrEmpty(pname.Value) && value.Value != null)
                            {
                                p.Parameters.Add(
                                    new SimpleKeyValuePair()
                                    {
                                        Key = pname.Value,
                                        Value = ApplyStringValue(value.Value, model.Strings),
                                    });
                            }
                        }
                        model.ExternalParameterPresets.Add(p);
                    }
                }
            }
        }
        #endregion GetAllPresets    

        #region GetAllExternalParameters
        /// <summary>
        /// Kiszedi az XML-ből az összes external paraméter definiciót
        /// </summary>
        /// <param name="reportElement">a report, amin dolgozunk</param>
        /// <param name="model">a riport BI modelje</param>
        private void GetAllExternalParameters(XElement reportElement, ref ReportXMLModel model)
        {
            model.ExternalParameters.Clear();
            XElement externalParametersElement = reportElement.Element(XName.Get(Elements.EXTERNALPARAMETERS, _xmlNameSpace));
            if (externalParametersElement != null)
            {
                foreach (var parameterElement in externalParametersElement.Elements(XName.Get(Elements.PARAMETER, _xmlNameSpace)))
                {
                    XAttribute nameAttribute = parameterElement.Attribute(XName.Get(Attributes.NAME, _xmlNameSpace));
                    if (nameAttribute != null && !String.IsNullOrEmpty(nameAttribute.Value))
                    {
                        XAttribute pname = parameterElement.Attribute(XName.Get(Attributes.NAME, _xmlNameSpace));
                        XElement value = parameterElement.Element(XName.Get(Elements.VALUE, _xmlNameSpace));
                        if (pname != null && value != null && !String.IsNullOrEmpty(pname.Value))
                        {
                            model.ExternalParameters.Add(
                                    new SimpleKeyValuePair()
                                    {
                                        Key = pname.Value,
                                        Value = ApplyStringValue(value.Value, model.Strings),
                                    }
                                );
                        }
                    }
                }
            }
        }
        #endregion GetAllExternalParameters

        #region GetAllInternalParameters
        /// <summary>
        /// Kiszedi az XML-ből az összes internal paraméter definiciót
        /// </summary>
        /// <param name="reportElement">A report element , ami alatt  apresetek találhatóak</param>
        /// <param name="model">a riport BI modelje</param>
        private void GetAllInternalParameters(XElement reportElement, ref ReportXMLModel model)
        {
            model.InternalParameters.Clear();
            XElement internalParametersElement = reportElement.Element(XName.Get(Elements.INTERNALPARAMETERS, _xmlNameSpace));
            if (internalParametersElement != null)
            {
                foreach (var parameterElement in internalParametersElement.Elements(XName.Get(Elements.PARAMETER, _xmlNameSpace)))
                {
                    XAttribute nameAttribute = parameterElement.Attribute(XName.Get(Attributes.NAME, _xmlNameSpace));
                    if (nameAttribute != null && !String.IsNullOrEmpty(nameAttribute.Value))
                    {
                        XAttribute pname = parameterElement.Attribute(XName.Get(Attributes.NAME, _xmlNameSpace));
                        XElement value = parameterElement.Element(XName.Get(Elements.VALUE, _xmlNameSpace));
                        if (pname != null && !String.IsNullOrEmpty(pname.Value))
                        {
                            List<ConditionDefination> conditions = new List<ConditionDefination>();
                            XElement conditionsElement = parameterElement.Element(XName.Get(Elements.CONDITIONS, _xmlNameSpace));
                            if (conditionsElement != null)
                            {
                                foreach (var condition in conditionsElement.Elements(XName.Get(Elements.CONDITION, _xmlNameSpace)))
                                {
                                    XAttribute type = condition.Attribute(XName.Get(Attributes.TYPE, _xmlNameSpace));
                                    XAttribute test = condition.Attribute(XName.Get(Attributes.TEST, _xmlNameSpace));
                                    XAttribute with = condition.Attribute(XName.Get(Attributes.WITH, _xmlNameSpace));
                                    if (type != null && !String.IsNullOrEmpty(type.Value))
                                    {
                                        ConditionType typeValue = ConditionType.Else;
                                        if (Enum.TryParse<ConditionType>(type.Value, true, out typeValue))
                                        {
                                            XElement valueElement = condition.Element(XName.Get(Elements.VALUE, _xmlNameSpace));
                                            if (valueElement != null)
                                            {
                                                switch (typeValue)
                                                {
                                                    default:
                                                    case ConditionType.Else:
                                                        conditions.Add(ConditionDefination.Factory(typeValue, null, null, valueElement.Value));
                                                        break;
                                                    case ConditionType.Equal:
                                                        if (test != null && with != null)
                                                        {
                                                            conditions.Add(ConditionDefination.Factory(typeValue, test.Value, with.Value, valueElement.Value));
                                                        }
                                                        break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            model.InternalParameters.Add(InternalParameter.Factory(nameAttribute.Value, conditions, value?.Value));
                        }
                    }
                }
            }
        }
        #endregion GetAllInternalParameters

        /// <summary>
        /// az inputon helyetesíti az összes string előfordulást annak értékére
        /// </summary>
        /// <param name="input">ebben a stringben</param>
        /// <param name="strings">a definiált stringek</param>
        /// <returns>a bejövő input, a cserék elvégzése után</returns>
        private string ApplyStringValue(string input, Dictionary<string, string> strings)
        {
            input = input.ApplyDaysback();
            input = input.ApplyMonthsback();
            input = input.ApplyWeeksback();
            input = input.Replace(strings, Constants.NameSeparator, Constants.NameSeparator);
            return input;
        }

        private string GetDisplayname(XElement report, ReportXMLModel model)
        {
            XElement displayElement = report.Element(XName.Get(Elements.DISPLAYNAME, report.GetDefaultNamespace().NamespaceName));
            if (displayElement != null)
            {
                string defaultValue = displayElement.Value;
                string wordCode = String.Concat(GetElementValue(GetXElement(Elements.GENERAL, Elements.WORDCODEPREFIX), Constants.DEFAULT_XML_WORDCODEPREFIX), ".",
                                                GetAttribute<string>(displayElement, Attributes.WORDCODE, String.Empty));
                return MultiLanguageManager.GetTranslation(wordCode, defaultValue, model.RequestLCID);
            }
            else
            {
                return $"DisplayName not found in {_xmlFileDefinition}: report id: {model.CurrentReport.Id}, lcid: {model.CurrentReport.LCID}";
            }
        }

        private void ReadParameters(XElement reportElement, ref ReportXMLModel model)
        {
            try
            {
                foreach (var parameter in reportElement.Element(Elements.REPORTFILE).Elements())
                {
                    model.Parameters.Add(GetAttribute(parameter, Attributes.NAMELOWER, ""), parameter.Value);
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Error when read parameters!", ex);
            }
        }

        private void ReadDataSets(XElement reportElement, ref ReportXMLModel model)
        {
            try
            {
                foreach (var dataSet in reportElement.Element(Elements.DATASETS).Elements())
                {
                    model.DataSets.Add(new ReportXMLModel.DataSet
                    {
                        ConnectionString = GetSubElementStringValue(dataSet, Attributes.CONNECTIONSTRING),
                        InitCommandType = GetAttribute(dataSet.Element(Elements.INITCOMMAND), Attributes.TYPELOWER, ""),
                        InitCommandSql = GetSubElementStringValue(dataSet, Elements.INITCOMMAND, Elements.SQL),
                        DataSetName = GetAttribute(dataSet, Attributes.NAMELOWER, ""),
                        DataCommandType = GetAttribute(dataSet.Element(Elements.DATACOMMAND), Attributes.TYPELOWER, ""),
                        DataCommandSql = GetSubElementStringValue(dataSet, Elements.DATACOMMAND, Elements.SQL)
                    });
                }
            }
            catch (Exception ex)
            {
                throw new Exception("", ex);
            }
        }

        private string GetSubElementStringValue(XElement element, params string[] subElementNames)
        {
            try
            {
                XElement currentElement = element;

                foreach (var subElement in subElementNames)
                {
                    currentElement = currentElement.Element(subElement);

                    if (currentElement == null)
                    {
                        break;
                    }
                }

                return currentElement != null ? currentElement.Value : string.Empty;
            }
            catch (Exception ex)
            {
                throw new Exception($"Error when get sub element value, elements: {string.Join(",", subElementNames)}.", ex);
            }
        }

        #endregion
    }
}
