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

using C4IT.FASD.Base;
using C4IT.XML;
using static C4IT.Logging.cLogManager;

namespace FasdDesktopUi.Config
{
    public class cF4SDCustomDialogConfig : cFasdBaseConfig, IXmlConfigNode
    {
        private const string constFileNameFasdConfig = "F4SD-CustomDialog-Configuration.xml";
        private const string constFileNameFasdConfigSchema = "F4SD-CustomDialog-Configuration.xsd";
        private const string constConfigRootElement = "F4SD-CustomDialog-Configuration";

        public static cF4SDCustomDialogConfig Instance { get; set; }

        public IXmlConfigNode ParentNode { get; set; }

        public Dictionary<string, cHealthCardComputationBase> GlobalComputations { get; set; } = new Dictionary<string, cHealthCardComputationBase>();
        public Dictionary<string, cHealthCardStateContainer> CustomDialogContainers { get; set; } = new Dictionary<string, cHealthCardStateContainer>();

        public cF4SDCustomDialogConfig()
            : base(constFileNameFasdConfig, constFileNameFasdConfigSchema, constConfigRootElement)
        { }

        public override bool InstantiateProperties(XmlElement RootElement, cXmlParser Parser)
        {
            bool output = false;
            try
            {
                if (RootElement is null || Parser is null)
                    return false;

                GlobalComputations = cF4SDHealthCardConfig.GetComputationsOfNode(RootElement, Parser, "Global-Computations");

                var customDialogsNode = RootElement.SelectSingleNode("CustomDialogs");

                if (customDialogsNode != null && customDialogsNode is XmlElement customDialogsElement)
                {
                    Parser.EnterElement("CustomDialogs");

                    var stateContainerNodes = customDialogsElement.SelectNodes("State-Container");
                    if (stateContainerNodes != null)
                    {
                        Parser.EnterElement("State-Container");

                        foreach (var stateContainerNode in stateContainerNodes)
                        {
                            try
                            {
                                if (!(stateContainerNode is XmlElement stateContainerElement))
                                    continue;

                                var tempStateContainer = new cHealthCardStateContainer(stateContainerElement, Parser, this);

                                if (tempStateContainer is null || tempStateContainer.IsValid is false)
                                    continue;

                                if(string.IsNullOrEmpty(tempStateContainer.Name))
                                {                                    
                                    Parser.AddInvalidAttribute(stateContainerElement, null, "Name", C4IT.Logging.LogLevels.Warning);
                                    continue;
                                }

                                if (CustomDialogContainers.ContainsKey(tempStateContainer.Name))
                                    Parser.AddDuplicateName(stateContainerElement, tempStateContainer.Name, C4IT.Logging.LogLevels.Warning);
                                else
                                    CustomDialogContainers.Add(tempStateContainer.Name, tempStateContainer);
                            }
                            catch (Exception E)
                            {
                                LogException(E);
                            }
                            finally
                            {
                                Parser.SelectElementNext();
                            }
                        }
                        Parser.LeaveElement("State-Container");
                    }

                    Parser.LeaveElement("CustomDialogs");
                }

                output = true;
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return output;
        }

        public HashSet<string> GetRequiredTables(List<enumFasdInformationClass> informationClasses)
        {
            HashSet<string> output = new HashSet<string>();

            try
            {
                foreach (var customDialog in CustomDialogContainers.Values
                    .Where(dialog => dialog.InformationClasses?.Count == 0
                    || informationClasses.All(informationClass => dialog.InformationClasses.Contains(informationClass))))
                {
                    foreach (var state in customDialog.StateContainerElements)
                    {
                        state.GetRequiredTables().ForEach(table => output.Add(table));
                    }
                }

                //Get all tables which are required for computations
                string computationPrefix = "Computation_";
                while (output.Any(tableName => tableName.StartsWith(computationPrefix)))
                {
                    string tableName = output.First(name => name.StartsWith(computationPrefix));

                    string computationName = tableName.Substring(computationPrefix.Length);
                    var computation = cF4SDHealthCardConfig.GetComputationsWithName(this, computationName);

                    if (computation?.Values?.Length > 0)
                    {
                        foreach (var computationValue in computation.Values)
                        {
                            if (computationValue.ValueTable != null)
                                output.Add(computationValue.ValueTable);
                        }
                    }

                    output.Remove(tableName);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return output;
        }
    }
}
