1 //------------------------------------------------------------------------------
2 // <copyright file="followingsibling.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7 
8 namespace MS.Internal.Xml.XPath {
9     using System;
10     using System.Xml;
11     using System.Xml.XPath;
12     using System.Diagnostics;
13     using System.Collections.Generic;
14     using StackNav = ClonableStack<System.Xml.XPath.XPathNavigator>;
15 
16     internal sealed class FollSiblingQuery : BaseAxisQuery {
17         StackNav              elementStk;
18         List<XPathNavigator>  parentStk;
19         XPathNavigator        nextInput;
20 
FollSiblingQuery(Query qyInput, string name, string prefix, XPathNodeType type)21         public FollSiblingQuery(Query qyInput, string name, string prefix, XPathNodeType type) : base (qyInput, name, prefix, type) {
22             this.elementStk = new StackNav();
23             this.parentStk  = new List<XPathNavigator>();
24         }
FollSiblingQuery(FollSiblingQuery other)25         private FollSiblingQuery(FollSiblingQuery other) : base(other) {
26             this.elementStk = other.elementStk.Clone();
27             this.parentStk = new List<XPathNavigator>(other.parentStk);
28             this.nextInput = Clone(other.nextInput);
29         }
30 
Reset()31         public override void Reset() {
32             elementStk.Clear();
33             parentStk.Clear();
34             nextInput = null;
35             base.Reset();
36         }
37 
Visited(XPathNavigator nav)38         private bool Visited(XPathNavigator nav) {
39             XPathNavigator parent = nav.Clone();
40             parent.MoveToParent();
41             for (int i = 0; i < parentStk.Count; i++) {
42                 if (parent.IsSamePosition(parentStk[i])) {
43                     return true;
44                 }
45             }
46             parentStk.Add(parent);
47             return false;
48         }
49 
FetchInput()50         private XPathNavigator FetchInput() {
51             XPathNavigator input;
52             do {
53                 input = qyInput.Advance();
54                 if (input == null) {
55                     return null;
56                 }
57             } while (Visited(input));
58             return input.Clone();
59         }
60 
Advance()61         public override XPathNavigator Advance() {
62         	while (true) {
63                 if (currentNode == null) {
64                     if (nextInput == null) {
65                         nextInput = FetchInput(); // This can happen at the begining and at the end
66                     }
67                     if (elementStk.Count == 0) {
68                         if (nextInput == null) {
69                             return null;
70                         }
71                         currentNode = nextInput;
72                         nextInput = FetchInput();
73                     } else {
74                         currentNode = elementStk.Pop();
75                     }
76                 }
77 
78                 while (currentNode.IsDescendant(nextInput)) {
79                     elementStk.Push(currentNode);
80                     currentNode = nextInput;
81                     nextInput = qyInput.Advance();
82                     if (nextInput != null) {
83                         nextInput = nextInput.Clone();
84                     }
85                 }
86 
87 				while (currentNode.MoveToNext()) {
88 				    if (matches(currentNode)) {
89 				        position++;
90     				    return currentNode;
91 			        }
92 			    }
93 		        currentNode = null;
94 			}
95         } // Advance
96 
Clone()97         public override XPathNodeIterator Clone() { return new FollSiblingQuery(this); }
98     }
99 }
100