[NUI] TCSACR-226 code change (#1032)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / Xaml / XamlNode.cs
1 using System.Collections.Generic;
2 using System.Diagnostics;
3 using System.Linq;
4 using System.Xml;
5 using Tizen.NUI.Binding;
6 using Tizen.NUI.Binding.Internals;
7
8 namespace Tizen.NUI.Xaml
9 {
10     internal interface INode
11     {
12         List<string> IgnorablePrefixes { get; set; }
13
14         IXmlNamespaceResolver NamespaceResolver { get; }
15
16         INode Parent { get; set; }
17
18         void Accept(IXamlNodeVisitor visitor, INode parentNode);
19         INode Clone();
20     }
21
22     internal interface IValueNode : INode
23     {
24     }
25
26     internal interface IElementNode : INode, IListNode
27     {
28         Dictionary<XmlName, INode> Properties { get; }
29         List<XmlName> SkipProperties { get; }
30         INameScope Namescope { get; }
31         XmlType XmlType { get; }
32         string NamespaceURI { get; }
33     }
34
35     internal interface IListNode : INode
36     {
37         List<INode> CollectionItems { get; }
38     }
39
40     [DebuggerDisplay("{NamespaceUri}:{Name}")]
41     internal class XmlType
42     {
43         public XmlType(string namespaceUri, string name, IList<XmlType> typeArguments)
44         {
45             NamespaceUri = namespaceUri;
46             Name = name;
47             TypeArguments = typeArguments;
48         }
49
50         public string NamespaceUri { get; }
51         public string Name { get; }
52         public IList<XmlType> TypeArguments { get; }
53     }
54
55     internal abstract class BaseNode : IXmlLineInfo, INode
56     {
57         protected BaseNode(IXmlNamespaceResolver namespaceResolver, int linenumber = -1, int lineposition = -1)
58         {
59             NamespaceResolver = namespaceResolver;
60             LineNumber = linenumber;
61             LinePosition = lineposition;
62         }
63
64         public IXmlNamespaceResolver NamespaceResolver { get; }
65         public INode Parent { get; set; }
66         public List<string> IgnorablePrefixes { get; set; }
67         public int LineNumber { get; set; }
68         public int LinePosition { get; set; }
69
70         public bool HasLineInfo() => LineNumber >= 0 && LinePosition >= 0;
71
72         public abstract void Accept(IXamlNodeVisitor visitor, INode parentNode);
73         public abstract INode Clone();
74     }
75
76     [DebuggerDisplay("{Value}")]
77     internal class ValueNode : BaseNode, IValueNode
78     {
79         public ValueNode(object value, IXmlNamespaceResolver namespaceResolver, int linenumber = -1, int lineposition = -1)
80             : base(namespaceResolver, linenumber, lineposition)
81         {
82             Value = value;
83         }
84
85         public object Value { get; set; }
86
87         public override void Accept(IXamlNodeVisitor visitor, INode parentNode)
88         {
89             visitor.Visit(this, parentNode);
90         }
91
92         public override INode Clone() => new ValueNode(Value, NamespaceResolver, LineNumber, LinePosition) {
93             IgnorablePrefixes = IgnorablePrefixes
94         };
95     }
96
97     [DebuggerDisplay("{MarkupString}")]
98     internal class MarkupNode : BaseNode, IValueNode
99     {
100         public MarkupNode(string markupString, IXmlNamespaceResolver namespaceResolver, int linenumber = -1, int lineposition = -1)
101             : base(namespaceResolver, linenumber, lineposition)
102         {
103             MarkupString = markupString;
104         }
105
106         public string MarkupString { get; }
107
108         public override void Accept(IXamlNodeVisitor visitor, INode parentNode)
109         {
110             visitor.Visit(this, parentNode);
111         }
112
113         public override INode Clone() => new MarkupNode(MarkupString, NamespaceResolver, LineNumber, LinePosition) {
114             IgnorablePrefixes = IgnorablePrefixes
115         };
116     }
117
118     [DebuggerDisplay("{XmlType.Name}")]
119     internal class ElementNode : BaseNode, IValueNode, IElementNode
120     {
121         public ElementNode(XmlType type, string namespaceURI, IXmlNamespaceResolver namespaceResolver, int linenumber = -1,
122             int lineposition = -1)
123             : base(namespaceResolver, linenumber, lineposition)
124         {
125             Properties = new Dictionary<XmlName, INode>();
126             SkipProperties = new List<XmlName>();
127             CollectionItems = new List<INode>();
128             XmlType = type;
129             NamespaceURI = namespaceURI;
130         }
131
132         public Dictionary<XmlName, INode> Properties { get; }
133         public List<XmlName> SkipProperties { get; }
134         public List<INode> CollectionItems { get; }
135         public XmlType XmlType { get; }
136         public string NamespaceURI { get; }
137         public INameScope Namescope { get; set; }
138
139         public override void Accept(IXamlNodeVisitor visitor, INode parentNode)
140         {
141             if (!SkipVisitNode(visitor, parentNode) && visitor.VisitingMode == TreeVisitingMode.TopDown)
142                 visitor.Visit(this, parentNode);
143
144             if (!SkipChildren(visitor, this, parentNode)) {
145                 foreach (var node in Properties.Values.ToList())
146                     node.Accept(visitor, this);
147                 foreach (var node in CollectionItems)
148                     node.Accept(visitor, this);
149             }
150
151             if (!SkipVisitNode(visitor, parentNode) && visitor.VisitingMode == TreeVisitingMode.BottomUp)
152                 visitor.Visit(this, parentNode);
153
154         }
155
156         bool IsDataTemplate(INode parentNode)
157         {
158             var parentElement = parentNode as IElementNode;
159             INode createContent;
160             if (parentElement != null &&
161                 parentElement.Properties.TryGetValue(XmlName._CreateContent, out createContent) &&
162                 createContent == this)
163                 return true;
164             return false;
165         }
166
167         protected bool SkipChildren(IXamlNodeVisitor visitor, INode node, INode parentNode) =>
168                (visitor.StopOnDataTemplate && IsDataTemplate(parentNode))
169             || (visitor.StopOnResourceDictionary && visitor.IsResourceDictionary(this))
170             || visitor.SkipChildren(node, parentNode);
171
172         protected bool SkipVisitNode(IXamlNodeVisitor visitor, INode parentNode) =>
173             !visitor.VisitNodeOnDataTemplate && IsDataTemplate(parentNode);
174
175         public override INode Clone()
176         {
177             var clone = new ElementNode(XmlType, NamespaceURI, NamespaceResolver, LineNumber, LinePosition) {
178                 IgnorablePrefixes = IgnorablePrefixes
179             };
180             foreach (var kvp in Properties)
181                 clone.Properties.Add(kvp.Key, kvp.Value.Clone());
182             foreach (var p in SkipProperties)
183                 clone.SkipProperties.Add(p);
184             foreach (var p in CollectionItems)
185                 clone.CollectionItems.Add(p.Clone());
186             return clone;
187         }
188     }
189
190     internal abstract class RootNode : ElementNode
191     {
192         protected RootNode(XmlType xmlType, IXmlNamespaceResolver nsResolver) : base(xmlType, xmlType.NamespaceUri, nsResolver)
193         {
194         }
195
196         public override void Accept(IXamlNodeVisitor visitor, INode parentNode)
197         {
198             if (!SkipVisitNode(visitor, parentNode) && visitor.VisitingMode == TreeVisitingMode.TopDown)
199                 visitor.Visit(this, parentNode);
200
201             if (!SkipChildren(visitor, this, parentNode)) {
202                 foreach (var node in Properties.Values.ToList())
203                     node.Accept(visitor, this);
204                 foreach (var node in CollectionItems)
205                     node.Accept(visitor, this);
206             }
207
208             if (!SkipVisitNode(visitor, parentNode) && visitor.VisitingMode == TreeVisitingMode.BottomUp)
209                 visitor.Visit(this, parentNode);
210         }
211     }
212
213     internal class ListNode : BaseNode, IListNode, IValueNode
214     {
215         public ListNode(IList<INode> nodes, IXmlNamespaceResolver namespaceResolver, int linenumber = -1, int lineposition = -1)
216             : base(namespaceResolver, linenumber, lineposition)
217         {
218             CollectionItems = nodes.ToList();
219         }
220
221         public XmlName XmlName { get; set; }
222         public List<INode> CollectionItems { get; set; }
223
224         public override void Accept(IXamlNodeVisitor visitor, INode parentNode)
225         {
226             if (visitor.VisitingMode == TreeVisitingMode.TopDown)
227                 visitor.Visit(this, parentNode);
228             foreach (var node in CollectionItems)
229                 node.Accept(visitor, this);
230             if (visitor.VisitingMode == TreeVisitingMode.BottomUp)
231                 visitor.Visit(this, parentNode);
232         }
233
234         public override INode Clone()
235         {
236             var items = new List<INode>();
237             foreach (var p in CollectionItems)
238                 items.Add(p.Clone());
239             return new ListNode(items, NamespaceResolver, LineNumber, LinePosition) {
240                 IgnorablePrefixes = IgnorablePrefixes
241             };
242         }
243     }
244
245     internal static class INodeExtensions
246     {
247         public static bool SkipPrefix(this INode node, string prefix)
248         {
249             do {
250                 if (node.IgnorablePrefixes != null && node.IgnorablePrefixes.Contains(prefix))
251                     return true;
252                 node = node.Parent;
253             } while (node != null);
254             return false;
255         }
256     }
257 }