using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Configuration;
using System.Web.Mvc;
using System.Xml;

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

using Vrh.OneReport.Lib.Areas.OneReport.Helpers;
using Vrh.OneReport.Lib.Areas.OneReport.XMLParametersFileProcessor;

namespace Vrh.OneReport.Lib.Areas.OneReport.Models
{
    public class OneReportModel : Report
    {
        private class ConnectionString
        {
            public string Name { get; set; }
            public string Value { get; set; }
        }

        private List<ConnectionString> connectionStrings;

        private string defaultLCID;

        private string connectionString;

        private string LCID;

        private static string GetOneReportFileName(string path = null)
        {
            string reportfile = string.Empty;

            if (!string.IsNullOrEmpty(path))
            {
                if (File.Exists(HttpContext.Current.Server.MapPath(path)))
                {
                    reportfile = HttpContext.Current.Server.MapPath(path);
                }
                else
                {
                    reportfile = HttpContext.Current.Server.MapPath("~/App_Data/OneReport/OneReports.xml");
                }
            }
            else
            {
                reportfile = HttpContext.Current.Server.MapPath("~/App_Data/OneReport/OneReports.xml");
            }

            return reportfile;
        }

        public static OneReportModel ReadOneReport(string listname, FormCollection formCollection)
        {
            var rv = new OneReportModel();

            try
            {
                if (rv.connectionStrings == null)
                {
                    rv.connectionStrings = new List<ConnectionString>();
                }
                rv.IsOneReport = true;
                LangHelperNS langHelper = LangHelperNS.ReportXML;
                string paramname, paramvalue;
                XmlNode tempNode;

                if (Xml == null)
                {
                    Xml = new XmlDocument();
                    var file = formCollection.AllKeys.FirstOrDefault(par => par == "xmlfile");
                    Xml.Load(GetOneReportFileName(string.IsNullOrEmpty(file) ? null : formCollection[file]));
                    XmlNSManager = new XmlNamespaceManager(Xml.NameTable);
                    XmlNSManager.AddNamespace("vlp", XmlNamespace);
                }

                if ((tempNode = Xml.SelectSingleNode("vlp:ReportDefinitions/vlp:general", XmlNSManager)) != null)
                {
                    foreach (XmlNode node in tempNode.ChildNodes)
                    {
                        if (node.NodeType == XmlNodeType.Element)
                        {
                            switch (node.Name.ToLower())
                            {
                                case "defaultlcid":
                                    rv.defaultLCID = node.InnerText;
                                    break;
                            }
                        }
                    }
                }

                if ((tempNode = Xml.SelectSingleNode("vlp:ReportDefinitions/vlp:connectionstrings", XmlNSManager)) != null)
                {
                    foreach (XmlNode node in tempNode.ChildNodes)
                    {
                        if (node.NodeType == XmlNodeType.Element)
                        {
                            switch (node.Name.ToLower())
                            {
                                case "connectionstring":
                                    rv.connectionStrings.Add(new ConnectionString { Name = node.Attributes["name"].Value, Value = node.InnerText });
                                    break;
                            }
                        }
                    }
                }

                if ((tempNode = Xml.SelectSingleNode($"vlp:ReportDefinitions/vlp:reports/vlp:report[@id='{listname}' and @LCID='{MultiLanguageManager.RelevantLanguageCode.Replace('-', '_')}']", XmlNSManager)) != null)
                {
                    if (tempNode.Attributes["LCID"] != null)
                    {
                        rv.LCID = tempNode.Attributes["LCID"].Value;
                    }

                    if (tempNode.Attributes["reportfile"] != null)
                    {
                        rv.FileName = tempNode.Attributes["reportfile"].Value;
                    }

                    string cs = string.Empty;
                    if (tempNode.Attributes["connectionstring"] != null)
                    {
                        cs = tempNode.Attributes["connectionstring"].Value;
                    }
                    if (string.IsNullOrEmpty(cs))
                    {
                        throw new Exception("Connection string attribue is empty!");
                    }
                    if (rv.connectionStrings.Count > 0)
                    {
                        rv.connectionString = rv.connectionStrings.FirstOrDefault(c => c.Name == cs)?.Value;
                    }
                    if (string.IsNullOrEmpty(rv.connectionString))
                    {
                        rv.connectionString = ConnectionStringStore.Get(cs);
                    }
                    if (string.IsNullOrEmpty(rv.connectionString))
                    {
                        throw new Exception($"Connection string not found! Id: {cs}");
                    }

                    foreach (XmlNode node in tempNode.ChildNodes)
                    {
                        if (node.NodeType == XmlNodeType.Element)
                        {
                            switch (node.Name.ToLower())
                            {
                                case "reportfile":
                                    foreach (XmlNode n in node.ChildNodes)
                                    {
                                        if (n.NodeType == XmlNodeType.Element)
                                        {
                                            switch (n.Name.ToLower())
                                            {
                                                case "param":
                                                    paramname = n.GetAttributeValue("name");
                                                    if (!string.IsNullOrEmpty(paramname))
                                                    {
                                                        paramvalue = n.GetNodeValue();
                                                        if (rv.RdlParameters.ContainsKey(paramname))
                                                        {
                                                            Log.Warning(string.Format(LangHelperNS.ReportView.GetTranslation("Report.DuplicateParameterNameText", "Duplikált paraméter (reportfile/param): {0}, lista ID: '{1}'"), paramname, listname));
                                                        }
                                                        else
                                                        {
                                                            rv.RdlParameters.Add(paramname, paramvalue);
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Log.Warning(string.Format(LangHelperNS.ReportView.GetTranslation("Report.MissingParameterNameText", "Hiányzó paraméternév (reportfile/param), lista ID: '{0}'"), listname));
                                                    }
                                                    break;
                                                default:
                                                    Log.Warning(string.Format(LangHelperNS.ReportView.GetTranslation("Report.UnknownTypeInReportText", "Ismeretlen típus: {0}, lista ID: '{1}'"), n.Name, listname));
                                                    break;
                                            }
                                        }
                                    }
                                    break;
                                case "displayname":
                                    rv.Name = langHelper.TranslateText(null, node.InnerText.Trim());
                                    break;
                                case "id":
                                    rv.ID = node.InnerText.Trim();
                                    break;
                                case "description":
                                    rv.Description = langHelper.TranslateText(null, node.InnerText.Trim());
                                    break;
                                case "datasets":
                                    ReadDataSetDescriptor(node, rv, rv.connectionString, langHelper);
                                    break;
                                case "parameters":
                                    ReadParameterDescriptor(node, rv, rv.connectionString, langHelper);
                                    break;
                                case "general":
                                    //Már korábban megtörtént.
                                    break;
                                default:
                                    Log.Warning(string.Format(LangHelperNS.ReportView.GetTranslation("Report.UnknownTypeInReportText", "Ismeretlen típus: {0}, lista ID: '{1}'"), node.Name, listname));
                                    break;
                            }
                        }
                    }
                }

                Xml = null;
            }
            catch (Exception ex)
            {
                Log.Error("OneReportModel ReadOneReport" + ex.Message);
                rv.isCompleted = false;
            }

            return rv;
        }

        public bool SwitchValues(FormCollection formCollection)
        {
            bool success = false;

            Dictionary<string, string> sql_replaces = new Dictionary<string, string>();
            Dictionary<string, string> param_replaces = new Dictionary<string, string>();

            try
            {
                var dataSet = DataSets.First();

                foreach (var pKey in formCollection.AllKeys)
                {
                    if (RdlParameters.ContainsValue(pKey))
                    {
                        RdlParameters[pKey] = formCollection[pKey];
                    }
                    else
                    {
                        sql_replaces.Add(pKey, formCollection[pKey]);
                        param_replaces.Add(pKey, formCollection[pKey]);
                    }
                }

                foreach (var ds in DataSets)
                {
                    if (ds.InitCommand != null)
                    {
                        ds.InitCommand.PrepareSQLCommand(sql_replaces, param_replaces);
                    }

                    if (ds.DataCommand != null)
                    {
                        ds.DataCommand.PrepareSQLCommand(sql_replaces, param_replaces);
                    }
                }

                if (RdlEvaluatedParameters == null)
                {
                    RdlEvaluatedParameters = new Dictionary<string, string>();
                }

                RdlEvaluatedParameters.Clear();

                foreach (var rdlparam in RdlParameters)
                {
                    if (RdlParameters.ContainsKey(rdlparam.Value))
                    {
                        RdlEvaluatedParameters.Add(rdlparam.Key, RdlParameters[rdlparam.Value]);
                    }
                }

                success = true;
            }
            catch (Exception)
            {
                success = false;
            }

            return success;
        }
    }
}