Follow formatting NUI
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / Xaml / ExpandMarkupsVisitor.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Xml;
4 using Tizen.NUI.Binding.Internals;
5
6 namespace Tizen.NUI.Xaml
7 {
8     internal class ExpandMarkupsVisitor : IXamlNodeVisitor
9     {
10         public ExpandMarkupsVisitor(HydrationContext context)
11         {
12             Context = context;
13         }
14
15         public static readonly IList<XmlName> Skips = new List<XmlName>
16         {
17             XmlName.xKey,
18             XmlName.xTypeArguments,
19             XmlName.xFactoryMethod,
20             XmlName.xName,
21             XmlName.xDataType
22         };
23
24         Dictionary<INode, object> Values
25         {
26             get { return Context.Values; }
27         }
28
29         HydrationContext Context { get; }
30
31         public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
32         public bool StopOnDataTemplate => false;
33         public bool StopOnResourceDictionary => false;
34         public bool VisitNodeOnDataTemplate => true;
35         public bool SkipChildren(INode node, INode parentNode) => false;
36         public bool IsResourceDictionary(ElementNode node) => false;
37
38         public void Visit(ValueNode node, INode parentNode)
39         {
40         }
41
42         public void Visit(MarkupNode markupnode, INode parentNode)
43         {
44             var parentElement = parentNode as IElementNode;
45             XmlName propertyName;
46             if (!ApplyPropertiesVisitor.TryGetPropertyName(markupnode, parentNode, out propertyName))
47                 return;
48             if (Skips.Contains(propertyName))
49                 return;
50             if (parentElement.SkipProperties.Contains(propertyName))
51                 return;
52
53             var markupString = markupnode.MarkupString;
54             var node =
55                 ParseExpression(ref markupString, markupnode.NamespaceResolver, markupnode, markupnode, parentNode) as IElementNode;
56             if (node != null)
57             {
58                 ((IElementNode)parentNode).Properties[propertyName] = node;
59                 node.Parent = parentNode;
60             }
61         }
62
63         public void Visit(ElementNode node, INode parentNode)
64         {
65         }
66
67         public void Visit(RootNode node, INode parentNode)
68         {
69         }
70
71         public void Visit(ListNode node, INode parentNode)
72         {
73         }
74
75         INode ParseExpression(ref string expression, IXmlNamespaceResolver nsResolver, IXmlLineInfo xmlLineInfo, INode node,
76             INode parentNode)
77         {
78             if (expression.StartsWith("{}", StringComparison.Ordinal))
79                 return new ValueNode(expression.Substring(2), null);
80
81             if (expression[expression.Length - 1] != '}')
82                 throw new Exception("Expression must end with '}'");
83
84             int len;
85             string match;
86             if (!MarkupExpressionParser.MatchMarkup(out match, expression, out len))
87                 throw new Exception();
88             expression = expression.Substring(len).TrimStart();
89             if (expression.Length == 0)
90                 throw new Exception("Expression did not end in '}'");
91
92             var serviceProvider = new XamlServiceProvider(node, Context);
93             serviceProvider.Add(typeof(IXmlNamespaceResolver), nsResolver);
94
95             return new MarkupExpansionParser().Parse(match, ref expression, serviceProvider);
96         }
97
98         public class MarkupExpansionParser : MarkupExpressionParser, IExpressionParser<INode>
99         {
100             IElementNode node;
101
102             object IExpressionParser.Parse(string match, ref string remaining, IServiceProvider serviceProvider)
103             {
104                 return Parse(match, ref remaining, serviceProvider);
105             }
106
107             public INode Parse(string match, ref string remaining, IServiceProvider serviceProvider)
108             {
109                 var nsResolver = serviceProvider.GetService(typeof(IXmlNamespaceResolver)) as IXmlNamespaceResolver;
110                 if (nsResolver == null)
111                     throw new ArgumentException(nameof(nsResolver));
112                 IXmlLineInfo xmlLineInfo = null;
113                 var xmlLineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider;
114                 if (xmlLineInfoProvider != null)
115                     xmlLineInfo = xmlLineInfoProvider.XmlLineInfo;
116
117                 var split = match.Split(':');
118                 if (split.Length > 2)
119                     throw new ArgumentException(nameof(split.Length));
120
121                 string prefix; //, name;
122                 if (split.Length == 2)
123                 {
124                     prefix = split[0];
125                     //                                  name = split [1];
126                 }
127                 else
128                 {
129                     prefix = "";
130                     //                                  name = split [0];
131                 }
132
133                 Type type;
134                 var typeResolver = serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlTypeResolver;
135                 if (typeResolver == null)
136                     type = null;
137                 // Add Binding and StaticResource support, The ordinal code can't find BindingExtension for Binding
138                 //else if (match == "Binding")
139                 //{
140                 //    type = typeof(BindingExtension);
141                 //}
142                 //else if (match == "StaticResource")
143                 //{
144                 //    type = typeof(StaticResourceExtension);
145                 //}
146                 else
147                 {
148                     //The order of lookup is to look for the Extension-suffixed class name first and then look for the class name without the Extension suffix.
149                     if (!typeResolver.TryResolve(match + "Extension", out type) && !typeResolver.TryResolve(match, out type))
150                     {
151                         var lineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider;
152                         var lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
153                         throw new XamlParseException(String.Format("MarkupExtension not found for {0}", match), lineInfo);
154                     }
155                 }
156
157                 var namespaceuri = nsResolver.LookupNamespace(prefix) ?? "";
158                 var xmltype = new XmlType(namespaceuri, type?.Name, null);
159
160                 if (type == null)
161                     throw new NotSupportedException();
162
163                 node = xmlLineInfo == null
164                     ? new ElementNode(xmltype, null, nsResolver)
165                     : new ElementNode(xmltype, null, nsResolver, xmlLineInfo.LineNumber, xmlLineInfo.LinePosition);
166
167                 if (remaining.StartsWith("}", StringComparison.Ordinal))
168                 {
169                     remaining = remaining.Substring(1);
170                     return node;
171                 }
172
173                 char next;
174                 string piece;
175                 while ((piece = GetNextPiece(ref remaining, out next)) != null)
176                     HandleProperty(piece, serviceProvider, ref remaining, next != '=');
177
178                 return node;
179             }
180
181             protected override void SetPropertyValue(string prop, string strValue, object value, IServiceProvider serviceProvider)
182             {
183                 var nsResolver = serviceProvider.GetService(typeof(IXmlNamespaceResolver)) as IXmlNamespaceResolver;
184
185                 var childnode = value as INode ?? new ValueNode(strValue, nsResolver);
186                 childnode.Parent = node;
187                 if (prop != null)
188                 {
189                     var name = new XmlName(node.NamespaceURI, prop);
190                     node.Properties[name] = childnode;
191                 }
192                 else //ContentProperty
193                     node.CollectionItems.Add(childnode);
194             }
195         }
196     }
197 }