using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace Wayne.Lib.Log
{
    /// <summary>
    /// Log config builder, constructs Wayne.Lib.Log configuration files in code.
    /// </summary>
    public class LogConfigBuilder
    {
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="name"></param>
        public LogConfigBuilder(string name)
        {
            Name = name;
        }

        /// <summary>
        /// Deserialization constructor
        /// </summary>
        /// <param name="logConfigNode"></param>
        /// <param name="ns"></param>
        internal LogConfigBuilder(XmlNode logConfigNode, string ns)
        {
            Name = logConfigNode.Attributes["Name"].Value;

            XmlNode filtersNode = logConfigNode["Filters", ns];
            if (filtersNode != null)
            {
                foreach (XmlNode filterNode in filtersNode.ChildNodes)
                {
                    if (filterNode.Name.Equals("Filter", StringComparison.Ordinal))
                    {
                        XmlAttribute enabledAttribute = filterNode.Attributes["Enabled"];
                        if ((enabledAttribute != null) && !XmlConvert.ToBoolean(enabledAttribute.Value))
                            continue;

                        Filters.Add(new LogConfigFilter(filterNode));
                    }
                }
            }

            XmlElement outputListNode = logConfigNode["Outputs", ns];
            if (outputListNode != null)
            {
                foreach (XmlNode outputNode in outputListNode.ChildNodes)
                {
                    if ((outputNode.LocalName == "Output") && (outputNode.NodeType == XmlNodeType.Element))
                    {
                        XmlAttribute enabledAttribute = outputNode.Attributes["Enabled"];
                        if ((enabledAttribute != null) && !XmlConvert.ToBoolean(enabledAttribute.Value))
                            continue;

                        LogConfigOutput logConfigOutput = LogConfigOutput.Create(outputNode, ns);
                        if (logConfigOutput != null)
                            Outputs.Add(logConfigOutput);
                    }
                }
            }
        }

        /// <summary>
        /// Filters
        /// </summary>
        public readonly List<LogConfigFilter> Filters = new List<LogConfigFilter>();

        /// <summary>
        /// Outputs
        /// </summary>
        public readonly List<LogConfigOutput> Outputs = new List<LogConfigOutput>();

        /// <summary>
        /// Name of the log builder
        /// </summary>
        public readonly string Name;

        /// <summary>
        /// ToString
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return Name;
        }

        internal bool MatchFilter(EntityCategory entityCategory, out DebugLogLevel debugLogLevel)
        {
            if (Filters.Count == 0)
            {
                debugLogLevel = DebugLogLevel.Normal;
                return true;
            }

            foreach (LogConfigFilter logFilter in Filters)
                if (logFilter.MatchFilter(entityCategory, out debugLogLevel))
                    return true;

            debugLogLevel = DebugLogLevel.Excluded;
            return false;
        }

        private void WriteXml(XmlWriter xmlWriter)
        {
            xmlWriter.WriteStartElement("LogConfig");
            xmlWriter.WriteAttributeString("Name", Name);

            xmlWriter.WriteStartElement("Filters");
            foreach (LogConfigFilter logConfigFilter in Filters)
                logConfigFilter.WriteXml(xmlWriter);
            xmlWriter.WriteEndElement(); // Filters

            xmlWriter.WriteStartElement("Outputs");
            foreach (LogConfigOutput logConfigOutput in Outputs)
                logConfigOutput.WriteXml(xmlWriter);
            xmlWriter.WriteEndElement(); // Outputs

            xmlWriter.WriteEndElement(); // LogConfig
        }

        /// <summary>
        /// Constructs an XML logconfig file from a range of log config builders.
        /// </summary>
        /// <param name="logConfigBuilders"></param>
        /// <returns></returns>
        public static string[] GetLogConfigFileLines(params LogConfigBuilder[] logConfigBuilders)
        {
            StringBuilder output = new StringBuilder();
            XmlWriterSettings xmlWriterSettings = new XmlWriterSettings { Indent = true, NewLineHandling = NewLineHandling.Entitize, NewLineChars = "\n" };
            XmlWriter xmlWriter = XmlWriter.Create(output, xmlWriterSettings);
            xmlWriter.WriteProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"");
            xmlWriter.WriteStartElement("LogConfigFile", "http://www.wayne.com/2010-01-05/LogConfig.xsd");
            foreach (LogConfigBuilder logConfigBuilder in logConfigBuilders)
                logConfigBuilder.WriteXml(xmlWriter);
            xmlWriter.WriteEndElement(); // LogConfigFile
            xmlWriter.Close();
            return output.ToString().Split('\n');
        }
    }
}