<commit_before>﻿namespace Superscribe.Utils
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Policy;

    using Superscribe.Models;

    public class RouteWalker<T> where T : IRouteData
    {
        private readonly SuperscribeNode baseNode;

        public RouteWalker(SuperscribeNode baseNode)
        {
            this.baseNode = baseNode;
        }

        public bool ExtraneousMatch { get; private set; }

        public bool IncompleteMatch { get; private set; }

        public bool ParamConversionError { get; private set; }

        public string Method { get; set; }

        public Queue<string> RemainingSegments { get; private set; }

        public void WalkRoute(string route, string method, T info)
        {
            string querystring = null;
            this.Method = method;

            var parts = route.Split('?');
            if (parts.Length > 0)
            {
                route = parts[0];
            }

            if (parts.Length > 1)
            {
                querystring = parts[1];
            }

            if (!string.IsNullOrEmpty(querystring))
            {
                var queries = querystring.Split('&');
                foreach (var query in queries)
                {
                    if (query.Contains("="))
                    {
                        var operands = query.Split('=');
                        info.Parameters[operands[0]] = operands[1];
                    }
                }
            }

            this.RemainingSegments = new Queue<string>(route.Split('/'));
            this.WalkRoute(info, this.baseNode);
        }

        public string PeekNextSegment()
        {
            if (this.RemainingSegments.Any())
            {
                return this.RemainingSegments.Peek();
            }

            return string.Empty;
        }

        public void WalkRoute(T info, SuperscribeNode match)
        {
            FinalFunction onComplete = null;
            while (match != null)
            {
                if (match.ActionFunction != null)
                {
                    match.ActionFunction(info, this.PeekNextSegment());
                }

                if (!(match is NonConsumingNode))
                {
                    if (this.RemainingSegments.Any())
                    {
                        this.RemainingSegments.Dequeue();
                    }
                }

                if (onComplete != null)
                {
                    if (onComplete.IsExclusive)
                    {
                        onComplete = null;
                    }
                }

                if (match.FinalFunctions.Count > 0)
                {
                    var function = match.FinalFunctions.FirstOrDefault(o => o.Method == this.Method)
                                   ?? match.FinalFunctions.FirstOrDefault(o => string.IsNullOrEmpty(o.Method));

                    if (function != null)
                    {
                        onComplete = function;
                    }
                }

                var nextMatch = this.FindNextMatch(info, this.PeekNextSegment(), match.Edges);
                if (nextMatch == null
                    && !match.FinalFunctions.Any(o => string.IsNullOrEmpty(o.Method) || o.Method == this.Method)
                    && match.Edges.Any()
                    && match.Edges.All(o => !(o.IsOptional || o is NonConsumingNode)))
                {
                    this.IncompleteMatch = true;
                    return;
                }

                match = nextMatch;
            }

            if (this.RemainingSegments.Any(o => !string.IsNullOrEmpty(o)))
            {
                this.ExtraneousMatch = true;
                return;
            }

            if (onComplete != null)
            {
                //o => function.Function(o)
                info.Response = onComplete.Function(info);
            }
        }

        private SuperscribeNode FindNextMatch(T info, string segment, IEnumerable<SuperscribeNode> states)
        {
            return !string.IsNullOrEmpty(segment) ?
                states.FirstOrDefault(o => o.ActivationFunction(info, segment) && (!o.AllowedMethods.Any() || o.AllowedMethods.Contains(this.Method)))
                : null;
        }
    }
}
<commit_msg>Fixed an issue where querystring parameter values were not being properly decoded<commit_after>﻿namespace Superscribe.Utils
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Policy;

    using Superscribe.Models;

    public class RouteWalker<T> where T : IRouteData
    {
        private readonly SuperscribeNode baseNode;

        public RouteWalker(SuperscribeNode baseNode)
        {
            this.baseNode = baseNode;
        }

        public bool ExtraneousMatch { get; private set; }

        public bool IncompleteMatch { get; private set; }

        public bool ParamConversionError { get; private set; }

        public string Method { get; set; }

        public Queue<string> RemainingSegments { get; private set; }

        public void WalkRoute(string route, string method, T info)
        {
            string querystring = null;
            this.Method = method;

            var parts = route.Split('?');
            if (parts.Length > 0)
            {
                route = parts[0];
            }

            if (parts.Length > 1)
            {
                querystring = parts[1];
            }

            if (!string.IsNullOrEmpty(querystring))
            {
                var queries = querystring.Split('&');
                foreach (var query in queries)
                {
                    if (query.Contains("="))
                    {
                        var operands = query.Split('=');
                        info.Parameters[operands[0]] = Uri.UnescapeDataString(operands[1]);
                    }
                }
            }

            this.RemainingSegments = new Queue<string>(route.Split('/'));
            this.WalkRoute(info, this.baseNode);
        }

        public string PeekNextSegment()
        {
            if (this.RemainingSegments.Any())
            {
                return this.RemainingSegments.Peek();
            }

            return string.Empty;
        }

        public void WalkRoute(T info, SuperscribeNode match)
        {
            FinalFunction onComplete = null;
            while (match != null)
            {
                if (match.ActionFunction != null)
                {
                    match.ActionFunction(info, this.PeekNextSegment());
                }

                if (!(match is NonConsumingNode))
                {
                    if (this.RemainingSegments.Any())
                    {
                        this.RemainingSegments.Dequeue();
                    }
                }

                if (onComplete != null)
                {
                    if (onComplete.IsExclusive)
                    {
                        onComplete = null;
                    }
                }

                if (match.FinalFunctions.Count > 0)
                {
                    var function = match.FinalFunctions.FirstOrDefault(o => o.Method == this.Method)
                                   ?? match.FinalFunctions.FirstOrDefault(o => string.IsNullOrEmpty(o.Method));

                    if (function != null)
                    {
                        onComplete = function;
                    }
                }

                var nextMatch = this.FindNextMatch(info, this.PeekNextSegment(), match.Edges);
                if (nextMatch == null
                    && !match.FinalFunctions.Any(o => string.IsNullOrEmpty(o.Method) || o.Method == this.Method)
                    && match.Edges.Any()
                    && match.Edges.All(o => !(o.IsOptional || o is NonConsumingNode)))
                {
                    this.IncompleteMatch = true;
                    return;
                }

                match = nextMatch;
            }

            if (this.RemainingSegments.Any(o => !string.IsNullOrEmpty(o)))
            {
                this.ExtraneousMatch = true;
                return;
            }

            if (onComplete != null)
            {
                //o => function.Function(o)
                info.Response = onComplete.Function(info);
            }
        }

        private SuperscribeNode FindNextMatch(T info, string segment, IEnumerable<SuperscribeNode> states)
        {
            return !string.IsNullOrEmpty(segment) ?
                states.FirstOrDefault(o => o.ActivationFunction(info, segment) && (!o.AllowedMethods.Any() || o.AllowedMethods.Contains(this.Method)))
                : null;
        }
    }
}

{'fraction_non_alphanumeric': 0.09456398640996602, 'fraction_numerical': 0.0015855039637599094, 'mean_word_length': 1.2071982004498876, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5979316', 'n_tokens_mistral': 2277, 'n_tokens_neox': 2097, 'n_words': 433}