using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using mustache.Properties;
namespace mustache
{
    /// 
    /// Defines the attributes of a custom tag.
    /// 
    public sealed class TagDefinition
    {
        private readonly string _tagName;
        private readonly List _parameters;
        private readonly List _childTagDefinitions;
        private TagParameter _scopeParameter;
        /// 
        /// Initializes a new instance of a TagDefinition.
        /// 
        /// The name of the tag.
        /// The name of the tag is null or blank.
        public TagDefinition(string tagName)
        {
            if (!RegexHelper.IsValidIdentifier(tagName))
            {
                throw new ArgumentException(Resources.BlankTagName, "tagName");
            }
            _tagName = tagName;
            _parameters = new List();
            _childTagDefinitions = new List();
        }
        /// 
        /// Gets the name of the tag.
        /// 
        public string Name
        {
            get { return _tagName; }
        }
        /// 
        /// Specifies that the tag expects the given parameter information.
        /// 
        /// The parameter to add.
        /// The parameter is null.
        /// A parameter with the same name already exists.
        public void AddParameter(TagParameter parameter)
        {
            if (parameter == null)
            {
                throw new ArgumentNullException("parameter");
            }
            if (_parameters.Any(p => p.Name == parameter.Name))
            {
                throw new ArgumentException(Resources.DuplicateParameter, "parameter");
            }
            _parameters.Add(parameter);
            if (parameter.IsScopeContext)
            {
                _scopeParameter = parameter;
            }
        }
        /// 
        /// Gets the parameters that are defined for the tag.
        /// 
        public IEnumerable Parameters
        {
            get { return new ReadOnlyCollection(_parameters); }
        }
        /// 
        /// Gets or sets whether the tag contains content.
        /// 
        public bool HasBody
        {
            get;
            set;
        }
        /// 
        /// Gets or sets whether the tag defines a new scope based on an argument.
        /// 
        public bool IsScoped
        {
            get;
            set;
        }
        /// 
        /// Specifies that the given tag is in scope within the current tag.
        /// 
        /// The tag that is in scope within the current tag.
        public void AddChildTag(TagDefinition childTag)
        {
            if (childTag == null)
            {
                throw new ArgumentNullException("childTag");
            }
            _childTagDefinitions.Add(childTag);
        }
        /// 
        /// Gets the tags that are in scope within the current tag.
        /// 
        public IEnumerable ChildTags
        {
            get { return new ReadOnlyCollection(_childTagDefinitions); }
        }
    }
}