/// <summary>
        ///  The main method for the processor.  It simply overrides the Process method.
        /// </summary>
        public override void Process(HttpRequestArgs args)
        {
            // This processer is added to the pipeline after the Sitecore Item Resolver.  We want to skip everything if the item resolved successfully.
            // Also, skip processing for the visitor identification items related to DMS.
            Assert.ArgumentNotNull(args, "args");
            var allowExternalHost = AllowExternalHost(HttpContext.Current.Request.Url.Host);

            if ((allowExternalHost || Context.Item == null || AllowRedirectsOnFoundItem(Context.Database)) && args.LocalPath != Constants.Paths.VisitorIdentification && Context.Database != null)
            {
                // Grab the actual requested path for use in both the item and pattern match sections.
                var requestedUrl          = HttpContext.Current.Request.Url.ToString().TrimEnd('/');
                var requestedPath         = HttpContext.Current.Request.Url.AbsolutePath;
                var requestedPathAndQuery = HttpContext.Current.Request.Url.PathAndQuery;
                var currentIpAddress      = GetClientIPAddress();
                var db = Context.Database;

                // First, we check for exact matches because those take priority over pattern matches.
                if (Sitecore.Configuration.Settings.GetBoolSetting(Constants.Settings.RedirExactMatch, true))
                {
                    // Loop through the exact match entries to look for a match.
                    foreach (Item possibleRedirect in GetRedirects(db, Constants.Templates.RedirectUrl, Constants.Templates.VersionedRedirectUrl, Sitecore.Configuration.Settings.GetSetting(Constants.Settings.QueryExactMatch)))
                    {
                        var trimmedItemRequestedUrl = possibleRedirect[Constants.Fields.RequestedUrl].TrimEnd('/');

                        if (requestedUrl.Equals(trimmedItemRequestedUrl, StringComparison.OrdinalIgnoreCase) ||
                            requestedPath.Equals(trimmedItemRequestedUrl, StringComparison.OrdinalIgnoreCase))
                        {
                            var redirectToItemId = possibleRedirect.Fields[Constants.Fields.RedirectToItem];
                            var redirectToUrl    = possibleRedirect.Fields[Constants.Fields.RedirectToUrl];
                            var redirectFromCode = possibleRedirect.Fields[Constants.Fields.RedirectCode];
                            var maxMind          = Sitecore.Configuration.Settings.GetSetting(Constants.Settings.MaxMindType);

                            if (redirectToItemId.HasValue && !string.IsNullOrEmpty(redirectToItemId.ToString()))
                            {
                                var redirectToItem = db.GetItem(ID.Parse(redirectToItemId));

                                if (redirectToItem != null)
                                {
                                    var responseStatus = GetResponseStatus(possibleRedirect);

                                    switch (maxMind)
                                    {
                                    case "0":
                                    {
                                        SendResponse(redirectToItem, HttpContext.Current.Request.Url.Query, responseStatus, args);
                                        break;
                                    }

                                    case "1":
                                    {
                                        if (!redirectFromCode.HasValue || string.IsNullOrEmpty(redirectFromCode.ToString()))
                                        {
                                            goto case "0";
                                        }

                                        if (redirectFromCode.HasValue && !string.IsNullOrEmpty(redirectFromCode.ToString()) &&
                                            HaveCodeMatch(redirectFromCode.Value, DatabaseHelper.GetCodeFromIP(currentIpAddress)))
                                        {
                                            goto case "0";
                                        }

                                        break;
                                    }

                                    case "2":
                                    {
                                        if (!redirectFromCode.HasValue || string.IsNullOrEmpty(redirectFromCode.ToString()))
                                        {
                                            goto case "0";
                                        }

                                        if (redirectFromCode.HasValue && !string.IsNullOrEmpty(redirectFromCode.ToString()) &&
                                            HaveCodeMatch(redirectFromCode.Value, WebServiceHelper.GetCodeFromIP(currentIpAddress)))
                                        {
                                            goto case "0";
                                        }

                                        break;
                                    }

                                    default:
                                    {
                                        goto case "0";
                                    }
                                    }
                                }
                            }
                            else if (redirectToUrl.HasValue && !string.IsNullOrEmpty(redirectToUrl.ToString()))
                            {
                                var responseStatus = GetResponseStatus(possibleRedirect);

                                switch (maxMind)
                                {
                                case "0":
                                {
                                    SendResponse(redirectToUrl.Value, HttpContext.Current.Request.Url.Query, responseStatus, args);
                                    break;
                                }

                                case "1":
                                {
                                    if (!redirectFromCode.HasValue || string.IsNullOrEmpty(redirectFromCode.ToString()))
                                    {
                                        goto case "0";
                                    }

                                    if (redirectFromCode.HasValue && !string.IsNullOrEmpty(redirectFromCode.ToString()) &&
                                        HaveCodeMatch(redirectFromCode.Value, DatabaseHelper.GetCodeFromIP(currentIpAddress)))
                                    {
                                        goto case "0";
                                    }

                                    break;
                                }

                                case "2":
                                {
                                    if (!redirectFromCode.HasValue || string.IsNullOrEmpty(redirectFromCode.ToString()))
                                    {
                                        goto case "0";
                                    }

                                    if (redirectFromCode.HasValue && !string.IsNullOrEmpty(redirectFromCode.ToString()) &&
                                        HaveCodeMatch(redirectFromCode.Value, DatabaseHelper.GetCodeFromIP(currentIpAddress)))
                                    {
                                        goto case "0";
                                    }

                                    break;
                                }

                                default:
                                {
                                    goto case "0";
                                }
                                }
                            }
                        }
                    }
                }

                // Finally, we check for pattern matches because we didn't hit on an exact match.
                if (Sitecore.Configuration.Settings.GetBoolSetting(Constants.Settings.RedirPatternMatch, true))
                {
                    // Loop through the pattern match items to find a match
                    foreach (Item possibleRedirectPattern in GetRedirects(db, Constants.Templates.RedirectPattern, Constants.Templates.VersionedRedirectPattern, Sitecore.Configuration.Settings.GetSetting(Constants.Settings.QueryExactMatch)))
                    {
                        var redirectPath      = string.Empty;
                        var relativePathMatch = false;

                        if (Regex.IsMatch(requestedUrl, possibleRedirectPattern[Constants.Fields.RequestedExpression],
                                          RegexOptions.IgnoreCase))
                        {
                            redirectPath = Regex.Replace(requestedUrl,
                                                         possibleRedirectPattern[Constants.Fields.RequestedExpression],
                                                         possibleRedirectPattern[Constants.Fields.SourceItem], RegexOptions.IgnoreCase);
                        }
                        else if (Regex.IsMatch(requestedPathAndQuery,
                                               possibleRedirectPattern[Constants.Fields.RequestedExpression], RegexOptions.IgnoreCase))
                        {
                            if (!string.IsNullOrEmpty(possibleRedirectPattern[Constants.Fields.SourceItem]))
                            {
                                redirectPath = Regex.Replace(requestedPathAndQuery,
                                                             possibleRedirectPattern[Constants.Fields.RequestedExpression],
                                                             possibleRedirectPattern[Constants.Fields.SourceItem], RegexOptions.IgnoreCase);
                            }
                            else if (
                                !string.IsNullOrEmpty(
                                    possibleRedirectPattern[Constants.Fields.RelativeDestinationPath]))
                            {
                                redirectPath = Regex.Replace(requestedPathAndQuery,
                                                             possibleRedirectPattern[Constants.Fields.RequestedExpression],
                                                             possibleRedirectPattern[Constants.Fields.RelativeDestinationPath],
                                                             RegexOptions.IgnoreCase);
                                relativePathMatch = true;
                            }
                        }
                        if (string.IsNullOrEmpty(redirectPath))
                        {
                            continue;
                        }

                        // Query portion gets in the way of getting the sitecore item.
                        var pathAndQuery = redirectPath.Split('?');
                        var path         = pathAndQuery[0];
                        if (LinkManager.Provider != null &&
                            LinkManager.Provider.GetDefaultUrlOptions() != null &&
                            LinkManager.Provider.GetDefaultUrlOptions().EncodeNames)
                        {
                            path = MainUtil.DecodeName(path);
                        }
                        var redirectToItem = db.GetItem(path);
                        var responseStatus = GetResponseStatus(redirectToItem);
                        if (redirectToItem != null)
                        {
                            var query = pathAndQuery.Length > 1 ? "?" + pathAndQuery[1] : "";

                            SendResponse(redirectToItem, query, responseStatus, args);
                        }
                        else if (relativePathMatch)
                        {
                            var query = pathAndQuery.Length > 1 ? "?" + pathAndQuery[1] : "";
                            SendResponse(redirectPath, query, responseStatus, args);
                        }
                    }
                }
                if (!allowExternalHost)
                {
                    return;
                }
                //Couldn't find a mapping based on settings. For non-Sitecore hostnames
                var notFoundUrl = Sitecore.Configuration.Settings.GetSetting(Constants.Settings.ExternalHostsNotFoundUrl);
                SendTempResponse(notFoundUrl, HttpContext.Current.Request.Url.Query, args);
            }
        }