/// <summary>
        /// Parses the node.
        /// </summary>
        /// <param name="node">The node to parse.</param>
        /// <param name="config">The rewriter configuration.</param>
        /// <returns>The parsed action, or null if no action parsed.</returns>
        public override IRewriteAction Parse(XmlNode node, IRewriterConfiguration config)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }

            string propertyName = node.GetRequiredAttribute(Constants.AttrProperty);
            string appSettingKey = node.GetRequiredAttribute(Constants.AttrKey);

            return new SetAppSettingPropertyAction(propertyName, appSettingKey);
        }
        /// <summary>
        ///     Parses the node.
        /// </summary>
        /// <param name="node">The node to parse.</param>
        /// <param name="config">The rewriter configuration.</param>
        /// <returns>The parsed action, or null if no action parsed.</returns>
        public override IRewriteAction Parse(XmlNode node, RewriterConfiguration config)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }

            string cookieName = node.GetRequiredAttribute(Constants.AttrCookie);
            string cookieValue = node.GetRequiredAttribute(Constants.AttrValue, true);

            return new SetCookieAction(cookieName, cookieValue);
        }
        /// <summary>
        /// Parses the node.
        /// </summary>
        /// <param name="node">The node to parse.</param>
        /// <param name="config">The rewriter configuration.</param>
        /// <returns>The parsed action, or null if no action parsed.</returns>
        public override IRewriteAction Parse(XmlNode node, IRewriterConfiguration config)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            string to = node.GetRequiredAttribute(Constants.AttrTo, true);
            bool permanent = node.GetBooleanAttribute(Constants.AttrPermanent) ?? true;

            RedirectAction action = new RedirectAction(to, permanent);
            ParseConditions(node, action.Conditions, false, config);
            return action;
        }
        /// <summary>
        ///     Parses the condition.
        /// </summary>
        /// <param name="node">The node to parse.</param>
        /// <returns>The condition parsed, or null if nothing parsed.</returns>
        public IRewriteCondition Parse(XmlNode node)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            XmlNode headerAttr = node.Attributes.GetNamedItem(Constants.AttrHeader);
            if (headerAttr == null)
            {
                return null;
            }

            string match = node.GetRequiredAttribute(Constants.AttrMatch, true);
            return new PropertyMatchCondition(headerAttr.Value, match);
        }
        /// <summary>
        /// Parses the condition.
        /// </summary>
        /// <param name="node">The node to parse.</param>
        /// <returns>The condition parsed, or null if nothing parsed.</returns>
        public IRewriteCondition Parse(XmlNode node)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            string property = node.GetOptionalAttribute(Constants.AttrProperty);
            if (property == null)
            {
                return null;
            }

            string match = node.GetRequiredAttribute(Constants.AttrMatch, true);

            return new PropertyMatchCondition(property, match);
        }
        /// <summary>
        /// Parses the node.
        /// </summary>
        /// <param name="node">The node to parse.</param>
        /// <param name="config">The rewriter configuration.</param>
        /// <returns>The parsed action, or null if no action parsed.</returns>
        public override IRewriteAction Parse(XmlNode node, IRewriterConfiguration config)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }

            string to = node.GetRequiredAttribute(Constants.AttrTo, true);

            RewriteProcessing processing = ParseProcessing(node);

            RewriteAction action = new RewriteAction(to, processing);
            ParseConditions(node, action.Conditions, false, config);

            return action;
        }
        /// <summary>
        /// Parses the node.
        /// </summary>
        /// <param name="node">The node to parse.</param>
        /// <param name="config">The rewriter configuration.</param>
        /// <returns>The parsed action, or null if no action parsed.</returns>
        public override IRewriteAction Parse(XmlNode node, IRewriterConfiguration config)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }

            string headerName = node.GetOptionalAttribute(Constants.AttrHeader);
            if (headerName == null)
            {
                return null;
            }

            string headerValue = node.GetRequiredAttribute(Constants.AttrValue, true);

            return new AddHeaderAction(headerName, headerValue);
        }
        private static void ReadRegisterTransform(XmlNode node, RewriterConfiguration config)
        {
            if (node.ChildNodes.Count > 0)
            {
                throw new ConfigurationErrorsException(
                    MessageProvider.FormatString(Message.ElementNoElements, Constants.ElementRegister), node);
            }

            string type = node.GetRequiredAttribute(Constants.AttrTransform);

            // Transform type specified.
            // Create an instance and add it as the mapper handler for this map.
            var transform = TypeHelper.Activate(type, null) as IRewriteTransform;
            if (transform == null)
            {
                throw new ConfigurationErrorsException(
                    MessageProvider.FormatString(Message.InvalidTypeSpecified, type, typeof (IRewriteTransform)), node);
            }

            config.TransformFactory.AddTransform(transform);
        }
        /// <summary>
        /// Parses the node.
        /// </summary>
        /// <param name="node">The node to parse.</param>
        /// <param name="config">The rewriter configuration.</param>
        /// <returns>The parsed action, or null if no action parsed.</returns>
        public override IRewriteAction Parse(XmlNode node, IRewriterConfiguration config)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }

            string propertyName = node.GetOptionalAttribute(Constants.AttrProperty);
            if (String.IsNullOrEmpty(propertyName))
            {
                return null;
            }

            string propertyValue = node.GetRequiredAttribute(Constants.AttrValue, true);

            return new SetPropertyAction(propertyName, propertyValue);
        }
        /// <summary>
        ///     Parses the node.
        /// </summary>
        /// <param name="node">The node to parse.</param>
        /// <param name="config">The rewriter configuration.</param>
        /// <returns>The parsed action, or null if no action parsed.</returns>
        public override IRewriteAction Parse(XmlNode node, RewriterConfiguration config)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }

            string to = node.GetRequiredAttribute(Constants.AttrTo, true);

            XmlNode processingNode = node.Attributes[Constants.AttrProcessing];

            var processing = RewriteProcessing.ContinueProcessing;
            if (processingNode != null)
            {
                if (processingNode.Value == Constants.AttrValueRestart)
                {
                    processing = RewriteProcessing.RestartProcessing;
                }
                else if (processingNode.Value == Constants.AttrValueStop)
                {
                    processing = RewriteProcessing.StopProcessing;
                }
                else if (processingNode.Value != Constants.AttrValueContinue)
                {
                    throw new ConfigurationErrorsException(
                        MessageProvider.FormatString(Message.ValueOfProcessingAttribute, processingNode.Value,
                                                     Constants.AttrValueContinue, Constants.AttrValueRestart,
                                                     Constants.AttrValueStop), node);
                }
            }

            var action = new RewriteAction(to, processing);
            ParseConditions(node, action.Conditions, false, config);
            return action;
        }
        /// <summary>
        /// Parses the node.
        /// </summary>
        /// <param name="node">The node to parse.</param>
        /// <param name="config">The rewriter configuration.</param>
        /// <returns>The parsed action, or null if no action parsed.</returns>
        public override IRewriteAction Parse(XmlNode node, RewriterConfiguration config)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            string to = node.GetRequiredAttribute(Constants.AttrTo, true);

            bool permanent = true;
            XmlNode permanentNode = node.Attributes.GetNamedItem(Constants.AttrPermanent);
            if (permanentNode != null)
            {
                if (!bool.TryParse(permanentNode.Value, out permanent))
                {
                    throw new ConfigurationErrorsException(MessageProvider.FormatString(Message.InvalidBooleanAttribute, Constants.AttrPermanent), node);
                }
            }

            RedirectAction action = new RedirectAction(to, permanent);
            ParseConditions(node, action.Conditions, false, config);
            return action;
        }
        private static void ReadErrorHandler(XmlNode node, IRewriterConfiguration config)
        {
            string code = node.GetRequiredAttribute(Constants.AttrCode);

            XmlNode typeNode = node.Attributes[Constants.AttrType];
            XmlNode urlNode = node.Attributes[Constants.AttrUrl];
            if (typeNode == null && urlNode == null)
            {
                throw new ConfigurationErrorsException(MessageProvider.FormatString(Message.AttributeRequired, Constants.AttrUrl), node);
            }

            IRewriteErrorHandler handler = null;
            if (typeNode != null)
            {
                // <error-handler code="500" url="/oops.aspx" />
                handler = TypeHelper.Activate(typeNode.Value, null) as IRewriteErrorHandler;
                if (handler == null)
                {
                    throw new ConfigurationErrorsException(MessageProvider.FormatString(Message.InvalidTypeSpecified, typeNode.Value, typeof(IRewriteErrorHandler)), node);
                }
            }
            else
            {
                handler = new DefaultErrorHandler(urlNode.Value);
            }

            int statusCode;
            if (!Int32.TryParse(code, out statusCode))
            {
                throw new ConfigurationErrorsException(MessageProvider.FormatString(Message.InvalidHttpStatusCode, code), node);
            }

            config.ErrorHandlers.Add(statusCode, handler);
        }
        private static void ReadRegisterParser(XmlNode node, IRewriterConfiguration config)
        {
            if (node.ChildNodes.Count > 0)
            {
                throw new ConfigurationErrorsException(MessageProvider.FormatString(Message.ElementNoElements, Constants.ElementRegister), node);
            }

            string type = node.GetRequiredAttribute(Constants.AttrParser);

            object parser = TypeHelper.Activate(type, null);
            IRewriteActionParser actionParser = parser as IRewriteActionParser;
            if (actionParser != null)
            {
                config.ActionParserFactory.Add(actionParser);
            }

            IRewriteConditionParser conditionParser = parser as IRewriteConditionParser;
            if (conditionParser != null)
            {
                config.ConditionParserPipeline.Add(conditionParser);
            }
        }
        private static void ReadRegisterLogger(XmlNode node, IRewriterConfiguration config)
        {
            if (node.ChildNodes.Count > 0)
            {
                throw new ConfigurationErrorsException(MessageProvider.FormatString(Message.ElementNoElements, Constants.ElementRegister), node);
            }

            string type = node.GetRequiredAttribute(Constants.AttrLogger);

            // Logger type specified.  Create an instance and add it
            // as the mapper handler for this map.
            IRewriteLogger logger = TypeHelper.Activate(type, null) as IRewriteLogger;
            if (logger != null)
            {
                config.Logger = logger;
            }
        }
        private static void ReadMapping(XmlNode node, IRewriterConfiguration config)
        {
            // Name attribute.
            string mappingName = node.GetRequiredAttribute(Constants.AttrName);

            // Mapper type not specified.  Load in the hash map.
            StringDictionary map = new StringDictionary();
            foreach (XmlNode mapNode in node.ChildNodes)
            {
                if (mapNode.NodeType == XmlNodeType.Element)
                {
                    if (mapNode.LocalName == Constants.ElementMap)
                    {
                        string fromValue = mapNode.GetRequiredAttribute(Constants.AttrFrom, true);
                        string toValue = mapNode.GetRequiredAttribute(Constants.AttrTo, true);

                        map.Add(fromValue, toValue);
                    }
                    else
                    {
                        throw new ConfigurationErrorsException(MessageProvider.FormatString(Message.ElementNotAllowed, mapNode.LocalName), node);
                    }
                }
            }

            IRewriteTransform mapping = new StaticMappingTransform(mappingName, map);

            config.TransformFactory.Add(mapping);
        }