namespace Caliburn.Micro.Core {
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text.RegularExpressions;
    /// 
    ///  Class for managing the list of rules for doing name transformation.
    /// 
    public class NameTransformer : BindableCollection {
#if NET
        private const RegexOptions options = RegexOptions.Compiled;
#else
        private const RegexOptions options = RegexOptions.None;
#endif
        bool useEagerRuleSelection = true;
        /// 
        /// Flag to indicate if transformations from all matched rules are returned. Otherwise, transformations from only the first matched rule are returned.
        /// 
        public bool UseEagerRuleSelection {
            get { return useEagerRuleSelection; }
            set { useEagerRuleSelection = value; }
        }
        /// 
        ///  Adds a transform using a single replacement value and a global filter pattern.
        /// 
        /// Regular expression pattern for replacing text
        /// The replacement value.
        /// Regular expression pattern for global filtering
        public void AddRule(string replacePattern, string replaceValue, string globalFilterPattern = null) {
            AddRule(replacePattern, new[] { replaceValue }, globalFilterPattern);
        }
        /// 
        ///  Adds a transform using a list of replacement values and a global filter pattern.
        /// 
        /// Regular expression pattern for replacing text
        /// The list of replacement values
        /// Regular expression pattern for global filtering
        public void AddRule(string replacePattern, IEnumerable replaceValueList, string globalFilterPattern = null) {
            Add(new Rule {
                ReplacePattern = replacePattern,
                ReplacementValues = replaceValueList,
                GlobalFilterPattern = globalFilterPattern
            });
        }
        /// 
        /// Gets the list of transformations for a given name.
        /// 
        /// The name to transform into the resolved name list
        /// The transformed names.
        public IEnumerable Transform(string source) {
            return Transform(source, r => r);
        }
        /// 
        /// Gets the list of transformations for a given name.
        /// 
        /// The name to transform into the resolved name list
        /// A function to do a transform on each item in the ReplaceValueList prior to applying the regular expression transform
        /// The transformed names.
        public IEnumerable Transform(string source, Func getReplaceString) {
            var nameList = new List();
            var rules = this.Reverse();
            foreach(var rule in rules) {
                if(!string.IsNullOrEmpty(rule.GlobalFilterPattern) && !rule.GlobalFilterPatternRegex.IsMatch(source)) {
                    continue;
                }
                if(!rule.ReplacePatternRegex.IsMatch(source)) {
                    continue;
                }
                nameList.AddRange(
                    rule.ReplacementValues
                        .Select(getReplaceString)
                        .Select(repString => rule.ReplacePatternRegex.Replace(source, repString))
                    );
                if (!useEagerRuleSelection) {
                    break;
                }
            }
            return nameList;
        }
        ///
        /// A rule that describes a name transform.
        ///
        public class Rule {
            private Regex replacePatternRegex;
            private Regex globalFilterPatternRegex;
            /// 
            /// Regular expression pattern for global filtering
            /// 
            public string GlobalFilterPattern;
            /// 
            /// Regular expression pattern for replacing text
            /// 
            public string ReplacePattern;
            /// 
            /// The list of replacement values
            /// 
            public IEnumerable ReplacementValues;
            /// 
            /// Regular expression for global filtering
            /// 
            public Regex GlobalFilterPatternRegex {
                get {
                    return globalFilterPatternRegex ?? (globalFilterPatternRegex = new Regex(GlobalFilterPattern, options));
                }
            }
            /// 
            /// Regular expression for replacing text
            /// 
            public Regex ReplacePatternRegex {
                get {
                    return replacePatternRegex ?? (replacePatternRegex = new Regex(ReplacePattern, options));
                }
            }
        }
    }
}