using System.Globalization;
using System.Text.RegularExpressions;
using System.Xml;

namespace Wayne.Lib.Log
{
    /// <summary>
    /// Subfilter for ancestor and/ or category of the logging
    /// </summary>
    public class LogConfigSubFilter
    {
        /// <summary>
        /// Entitytype for ancestor
        /// </summary>
        public string AncestorEntityTypeRegexFilter { get; set; }

        /// <summary>
        /// Entitysubtype for the ancestor
        /// </summary>
        public string AncestorEntitySubTypeRegexFilter { get; set; }

        /// <summary>
        /// Id of the ancestor
        /// </summary>
        public string AncestorIdRegexFilter { get; set; }

        /// <summary>
        /// Category name of the log entry
        /// </summary>
        public string CategoryNameRegexFilter { get; set; }

        /// <summary>
        /// Filter level.
        /// </summary>
        public DebugLogLevel FilterLevel { get; set; }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="ancestorEntityTypeRegexFilter"></param>
        /// <param name="ancestorEntitySubTypeRegexFilter"></param>
        /// <param name="ancestorIdRegexFilter"></param>
        /// <param name="categoryNameRegexFilter"></param>
        /// <param name="filterLevel"></param>
        public LogConfigSubFilter(string ancestorEntityTypeRegexFilter, string ancestorEntitySubTypeRegexFilter, string ancestorIdRegexFilter, string categoryNameRegexFilter, DebugLogLevel filterLevel)
        {
            AncestorEntityTypeRegexFilter = ancestorEntityTypeRegexFilter;
            AncestorEntitySubTypeRegexFilter = ancestorEntitySubTypeRegexFilter;
            AncestorIdRegexFilter = ancestorIdRegexFilter;
            CategoryNameRegexFilter = categoryNameRegexFilter;
            FilterLevel = filterLevel;
        }

        /// <summary>
        /// Deserialization constructor
        /// </summary>
        /// <param name="logFilterAncestorNode"></param>
        internal LogConfigSubFilter(XmlNode logFilterAncestorNode)
        {
            XmlAttribute entityTypeAttribute = logFilterAncestorNode.Attributes["AncestorEntityType"];
            if (entityTypeAttribute != null)
                AncestorEntityTypeRegexFilter = entityTypeAttribute.Value;
            else
                AncestorEntityTypeRegexFilter = string.Empty;

            XmlAttribute entitySubTypeAttribute = logFilterAncestorNode.Attributes["AncestorEntitySubType"];
            if (entitySubTypeAttribute != null)
                AncestorEntitySubTypeRegexFilter = entitySubTypeAttribute.Value;
            else
                AncestorEntitySubTypeRegexFilter = string.Empty;

            XmlAttribute idAttribute = logFilterAncestorNode.Attributes["AncestorId"];
            if (idAttribute != null)
                AncestorIdRegexFilter = idAttribute.Value;
            else
                AncestorIdRegexFilter = string.Empty;

            XmlAttribute categoryNameAttribute = logFilterAncestorNode.Attributes["CategoryName"];
            if (categoryNameAttribute != null)
                CategoryNameRegexFilter = categoryNameAttribute.Value;
            else
                CategoryNameRegexFilter = string.Empty;

            XmlAttribute filterLevelttribute = logFilterAncestorNode.Attributes["FilterLevel"];
            if (filterLevelttribute != null)
                FilterLevel = EnumSupport.Parse(filterLevelttribute.Value, false, DebugLogLevel.Normal);
            else
                FilterLevel = DebugLogLevel.Normal;
        }

        /// <summary>
        /// ToString
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return string.Concat("AncestorEntityType=\"", AncestorEntityTypeRegexFilter ?? string.Empty,
                "\", AncestorSubType=\"", AncestorEntitySubTypeRegexFilter ?? string.Empty,
                "\", AncestorId=\"", AncestorIdRegexFilter ?? string.Empty,
                "\", Category=\"", CategoryNameRegexFilter ?? string.Empty,
                "\", Level=\"", FilterLevel, "\"");
        }

        /// <summary>
        /// Serialization
        /// </summary>
        /// <param name="xmlWriter"></param>
        internal void WriteXml(XmlWriter xmlWriter)
        {
            xmlWriter.WriteStartElement("SubFilter");

            if (!string.IsNullOrEmpty(AncestorEntityTypeRegexFilter))
                xmlWriter.WriteAttributeString("AncestorEntityType", AncestorEntityTypeRegexFilter);

            if (!string.IsNullOrEmpty(AncestorEntitySubTypeRegexFilter))
                xmlWriter.WriteAttributeString("AncestorEntitySubType", AncestorEntitySubTypeRegexFilter);

            if (!string.IsNullOrEmpty(AncestorIdRegexFilter))
                xmlWriter.WriteAttributeString("AncestorId", AncestorIdRegexFilter);

            if (!string.IsNullOrEmpty(CategoryNameRegexFilter))
                xmlWriter.WriteAttributeString("CategoryName", CategoryNameRegexFilter);

            if (FilterLevel != DebugLogLevel.Normal)
                xmlWriter.WriteAttributeString("FilterLevel", FilterLevel.ToString());

            xmlWriter.WriteEndElement(); // SubFilter
        }

        internal bool MatchFilter(EntityCategory entityCategory, out DebugLogLevel debugLogLevel)
        {
            if (string.IsNullOrEmpty(CategoryNameRegexFilter) || Regex.IsMatch(entityCategory.CategoryString, CategoryNameRegexFilter, RegexOptions.IgnoreCase))
            {
                if (string.IsNullOrEmpty(AncestorEntityTypeRegexFilter) && string.IsNullOrEmpty(AncestorEntitySubTypeRegexFilter) && string.IsNullOrEmpty(AncestorIdRegexFilter))
                {
                    debugLogLevel = FilterLevel;
                    return true;
                }

                foreach (var identifableValue in entityCategory.GetAncestors())
                {
                    bool entityTypeMatch = (string.IsNullOrEmpty(AncestorEntityTypeRegexFilter) || Regex.IsMatch(identifableValue.EntityType, AncestorEntityTypeRegexFilter, RegexOptions.IgnoreCase));
                    if (!entityTypeMatch)
                        continue;
                    bool entitySubTypeMatch = (string.IsNullOrEmpty(AncestorEntitySubTypeRegexFilter) || Regex.IsMatch(identifableValue.EntitySubType, AncestorEntitySubTypeRegexFilter, RegexOptions.IgnoreCase));
                    if (!entitySubTypeMatch)
                        continue;
                    bool idMatch = string.IsNullOrEmpty(AncestorIdRegexFilter);
                    if (!idMatch)
                    {
                        if (identifableValue.Id == IdentifiableEntity.NoId)
                            idMatch = Regex.IsMatch(string.Empty, AncestorIdRegexFilter, RegexOptions.IgnoreCase);
                        else
                            idMatch = Regex.IsMatch(identifableValue.Id.ToString(CultureInfo.InvariantCulture), AncestorIdRegexFilter, RegexOptions.IgnoreCase);
                    }
                    if (idMatch)
                    {
                        debugLogLevel = FilterLevel;
                        return true;
                    }
                }
            }
            debugLogLevel = DebugLogLevel.Excluded;
            return false;
        }
    }
}