using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using mustache.Properties;
namespace mustache
{
    /// 
    /// Defines the attributes of a custom tag.
    /// 
    public abstract class TagDefinition
    {
        private readonly string _tagName;
        /// 
        /// Initializes a new instance of a TagDefinition.
        /// 
        /// The name of the tag.
        /// The name of the tag is null or blank.
        protected TagDefinition(string tagName)
            : this(tagName, false)
        {
        }
        /// 
        /// Initializes a new instance of a TagDefinition.
        /// 
        /// The name of the tag.
        /// Specifies whether the tag is built-in or not. Checks are not performed on the names of built-in tags.
        internal TagDefinition(string tagName, bool isBuiltIn)
        {
            if (!isBuiltIn && !RegexHelper.IsValidIdentifier(tagName))
            {
                throw new ArgumentException(Resources.BlankTagName, "tagName");
            }
            _tagName = tagName;
        }
        /// 
        /// Gets the name of the tag.
        /// 
        public string Name
        {
            get { return _tagName; }
        }
        /// 
        /// Gets whether the tag is limited to the parent tag's context.
        /// 
        internal bool IsContextSensitive
        {
            get { return GetIsContextSensitive(); }
        }
        /// 
        /// Gets whether a tag is limited to the parent tag's context.
        /// 
        protected abstract bool GetIsContextSensitive();
        /// 
        /// Gets the parameters that are defined for the tag.
        /// 
        internal IEnumerable Parameters
        {
            get { return GetParameters(); }
        }
        /// 
        /// Specifies which parameters are passed to the tag.
        /// 
        /// The tag parameters.
        protected virtual IEnumerable GetParameters()
        {
            return new TagParameter[] { };
        }
        /// 
        /// Gets whether the tag contains content.
        /// 
        internal bool HasContent
        {
            get { return GetHasContent(); }
        }
        /// 
        /// Gets whether tag has content.
        /// 
        /// True if the tag has content; otherwise, false.
        protected abstract bool GetHasContent();
        /// 
        /// Gets the tags that can indicate that the tag has closed.
        /// This field is only used if no closing tag is expected.
        /// 
        internal IEnumerable ClosingTags
        {
            get  { return GetClosingTags(); }
        }
        protected virtual IEnumerable GetClosingTags()
        {
            if (HasContent)
            {
                return new string[] { Name };
            }
            else
            {
                return new string[] { };
            }
        }
        /// 
        /// Gets the tags that are in scope within the current tag.
        /// 
        internal IEnumerable ChildTags
        {
            get { return GetChildTags(); }
        }
        /// 
        /// Specifies which tags are scoped under the current tag.
        /// 
        /// The child tag definitions.
        protected virtual IEnumerable GetChildTags()
        {
            return new string[] { };
        }
        /// 
        /// Gets the scope to use when building the inner text of the tag.
        /// 
        /// The current scope.
        /// The arguments passed to the tag.
        /// The scope to use when building the inner text of the tag.
        public virtual IEnumerable GetChildScopes(KeyScope scope, Dictionary arguments)
        {
            yield return scope;
        }
        /// 
        /// Applies additional formatting to the inner text of the tag.
        /// 
        /// The format provider to use.
        /// The inner text of the tag.
        /// The arguments passed to the tag.
        /// The decorated inner text.
        public virtual string Decorate(IFormatProvider provider, string innerText, Dictionary arguments)
        {
            return innerText;
        }
        /// 
        /// Requests which generator group to associate the given tag type.
        /// 
        /// The child tag definition being grouped.
        /// The name of the group to associate the given tag with.
        public virtual bool ShouldCreateSecondaryGroup(TagDefinition definition)
        {
            return false;
        }
        /// 
        /// Gets whether the group with the given name should have text generated for them.
        /// 
        /// The arguments passed to the tag.
        /// True if text should be generated for the group; otherwise, false.
        public virtual bool ShouldGeneratePrimaryGroup(Dictionary arguments)
        {
            return true;
        }
    }
}