1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Collections.Generic;
6 using System.Xml.XPath;
7 using StackNav = MS.Internal.Xml.XPath.ClonableStack<System.Xml.XPath.XPathNavigator>;
8 
9 namespace MS.Internal.Xml.XPath
10 {
11     internal sealed class FollSiblingQuery : BaseAxisQuery
12     {
13         private StackNav _elementStk;
14         private List<XPathNavigator> _parentStk;
15         private XPathNavigator _nextInput;
16 
FollSiblingQuery(Query qyInput, string name, string prefix, XPathNodeType type)17         public FollSiblingQuery(Query qyInput, string name, string prefix, XPathNodeType type) : base(qyInput, name, prefix, type)
18         {
19             _elementStk = new StackNav();
20             _parentStk = new List<XPathNavigator>();
21         }
FollSiblingQuery(FollSiblingQuery other)22         private FollSiblingQuery(FollSiblingQuery other) : base(other)
23         {
24             _elementStk = other._elementStk.Clone();
25             _parentStk = new List<XPathNavigator>(other._parentStk);
26             _nextInput = Clone(other._nextInput);
27         }
28 
Reset()29         public override void Reset()
30         {
31             _elementStk.Clear();
32             _parentStk.Clear();
33             _nextInput = null;
34             base.Reset();
35         }
36 
Visited(XPathNavigator nav)37         private bool Visited(XPathNavigator nav)
38         {
39             XPathNavigator parent = nav.Clone();
40             parent.MoveToParent();
41             for (int i = 0; i < _parentStk.Count; i++)
42             {
43                 if (parent.IsSamePosition(_parentStk[i]))
44                 {
45                     return true;
46                 }
47             }
48             _parentStk.Add(parent);
49             return false;
50         }
51 
FetchInput()52         private XPathNavigator FetchInput()
53         {
54             XPathNavigator input;
55             do
56             {
57                 input = qyInput.Advance();
58                 if (input == null)
59                 {
60                     return null;
61                 }
62             } while (Visited(input));
63             return input.Clone();
64         }
65 
Advance()66         public override XPathNavigator Advance()
67         {
68             while (true)
69             {
70                 if (currentNode == null)
71                 {
72                     if (_nextInput == null)
73                     {
74                         _nextInput = FetchInput(); // This can happen at the beginning and at the end
75                     }
76                     if (_elementStk.Count == 0)
77                     {
78                         if (_nextInput == null)
79                         {
80                             return null;
81                         }
82                         currentNode = _nextInput;
83                         _nextInput = FetchInput();
84                     }
85                     else
86                     {
87                         currentNode = _elementStk.Pop();
88                     }
89                 }
90 
91                 while (currentNode.IsDescendant(_nextInput))
92                 {
93                     _elementStk.Push(currentNode);
94                     currentNode = _nextInput;
95                     _nextInput = qyInput.Advance();
96                     if (_nextInput != null)
97                     {
98                         _nextInput = _nextInput.Clone();
99                     }
100                 }
101 
102                 while (currentNode.MoveToNext())
103                 {
104                     if (matches(currentNode))
105                     {
106                         position++;
107                         return currentNode;
108                     }
109                 }
110                 currentNode = null;
111             }
112         } // Advance
113 
Clone()114         public override XPathNodeIterator Clone() { return new FollSiblingQuery(this); }
115     }
116 }
117