private void FragmentIterator(AnalysisContext context, INode node, FragmentComplexity qDepthComplexity, double avgImpact, double currentSubSelectionImpact, double currentEndNodeImpact)
        {
            context.AssertRecursion();

            if (node.Children != null &&
                node.Children.Any(
                    n => n is Field || (n is SelectionSet set && set.Children.Any()) || n is Operation))
            {
                if (node is Field)
                {
                    qDepthComplexity.Depth++;
                    var impactFromArgs = GetImpactFromArgs(node);
                    qDepthComplexity.Complexity += currentEndNodeImpact = impactFromArgs / avgImpact * currentSubSelectionImpact ?? currentSubSelectionImpact;
                    foreach (var nodeChild in node.Children.Where(n => n is SelectionSet))
                    {
                        FragmentIterator(context, nodeChild, qDepthComplexity, avgImpact, currentSubSelectionImpact * (impactFromArgs ?? avgImpact), currentEndNodeImpact);
                    }
                }
                else
                {
                    foreach (var nodeChild in node.Children)
                    {
                        FragmentIterator(context, nodeChild, qDepthComplexity, avgImpact, currentSubSelectionImpact, currentEndNodeImpact);
                    }
                }
            }
        private void FragmentIterator(AnalysisContext context, INode node, FragmentComplexity qDepthComplexity, double avgImpact, double currentSubSelectionImpact, double currentEndNodeImpact)
        {
            if (context.LoopCounter++ > _maxRecursionCount)
            {
                throw new InvalidOperationException("Query is too complex to validate.");
            }

            if (node.Children != null &&
                node.Children.Any(
                    n => n is Field || (n is SelectionSet set && set.Children.Any()) || n is Operation))
            {
                if (node is Field)
                {
                    qDepthComplexity.Depth++;
                    var impactFromArgs = GetImpactFromArgs(node);
                    qDepthComplexity.Complexity += currentEndNodeImpact = impactFromArgs / avgImpact * currentSubSelectionImpact ?? currentSubSelectionImpact;
                    foreach (var nodeChild in node.Children.Where(n => n is SelectionSet))
                    {
                        FragmentIterator(context, nodeChild, qDepthComplexity, avgImpact, currentSubSelectionImpact * (impactFromArgs ?? avgImpact), currentEndNodeImpact);
                    }
                }
                else
                {
                    foreach (var nodeChild in node.Children)
                    {
                        FragmentIterator(context, nodeChild, qDepthComplexity, avgImpact, currentSubSelectionImpact, currentEndNodeImpact);
                    }
                }
            }
        /// <summary>
        /// Analyzes the complexity of a document.
        /// </summary>
        internal ComplexityResult Analyze(Document doc, double avgImpact = 2.0d)
        {
            if (avgImpact <= 1)
            {
                throw new ArgumentOutOfRangeException(nameof(avgImpact));
            }

            var context = new AnalysisContext();

            foreach (var node in doc.Children.OfType <FragmentDefinition>())
            {
                var fragResult = new FragmentComplexity();
                FragmentIterator(context, node, fragResult, avgImpact, avgImpact, 1d);
                context.FragmentMap[node.Name] = fragResult;
            }

            TreeIterator(context, doc, avgImpact, avgImpact, 1d);

            return(context.Result);
        }
        /// <summary>
        /// Analyzes the complexity of a document.
        /// </summary>
        internal ComplexityResult Analyze(Document doc, double avgImpact = 2.0d)
        {
            if (avgImpact <= 1)
            {
                throw new ArgumentOutOfRangeException(nameof(avgImpact));
            }

            doc.Children.Where(node => node is FragmentDefinition).Apply(node =>
            {
                var fragResult = new FragmentComplexity();
                FragmentIterator(node, fragResult, avgImpact, avgImpact, 1d);
                _fragmentMap[(node as FragmentDefinition)?.Name] = fragResult;
            });

            TreeIterator(doc, _result, avgImpact, avgImpact, 1d);

            // Cleanup in case Analyze is called again
            _loopCounter = 0;
            var retVal = _result;

            _result = new ComplexityResult();

            return(retVal);
        }