using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Mercury.Mobile.Logging
{
    /// <summary>
    /// Provides filtering support by specified categories.
    /// </summary>
    public class CategoryFilter
        : LogFilter
    {
        /// <summary>
        /// Initializes a default instance of the <see cref="Mercury.Mobile.Logging.CategoryFilter"/> class.  
        /// Assumes an inclusive list of categories to allow.
        /// </summary>
        public CategoryFilter()
            : this(true)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Mercury.Mobile.Logging.CategoryFilter"/> class.
        /// </summary>
        /// <param name="isInclude">A value indicating whether the categories 
        /// on this filter comprise an inclusive list.</param>
        public CategoryFilter(bool isInclude)
        {
            this.IsInclude = isInclude;
        }

        private IDictionary<string, bool> _categories = new Dictionary<string, bool>();

        /// <summary>
        /// Gets a value indicating whether the categories on this filter comprise an inclusive list.
        /// </summary>
        /// <returns>True if the categories on this filter comprise an inclusive list; otherwise, false.</returns>
        public bool IsInclude { get; private set; }

        /// <summary>
        /// Adds the specified category to this filter.
        /// </summary>
        /// <param name="category">The category to add.</param>
        public void AddCategory(string category)
        {
            if (category == null)
                throw new ArgumentNullException("category");
            if (!this._categories.ContainsKey(category))
                this._categories.Add(category, true);
        }

        /// <summary>
        /// Removes all categories from this filter.
        /// </summary>
        public void Clear()
        {
            this._categories.Clear();
        }

        /// <summary>
        /// Removes the specified category from this filter.
        /// </summary>
        /// <param name="category">The category to remove.</param>
        public void RemoveCategory(string category)
        {
            this._categories.Remove(category);
        }

        /// <summary>
        /// Returns a value indicating whether the specified log entry can pass the filter.
        /// </summary>
        /// <param name="entry">The log entry to test.</param>
        /// <returns>True if the specified log entry can pass the filter; otherwise, false.</returns>
        public override bool Allow(LogEntry entry)
        {
            var data = entry.FilterData != null ? entry.FilterData.ToString() : null;
            if (this.IsInclude)
            {
                if (data == null)
                    return false;
                return this._categories.ContainsKey(data);
            }
            else
            {
                if (data == null)
                    return true;
                return (!this._categories.ContainsKey(data));
            }
        }
    }
}
