[NUI] remove "_" and refactoring naming to pascal case.
[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) 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, INode node)
76         {
77             if (expression.StartsWith("{}", StringComparison.Ordinal))
78                 return new ValueNode(expression.Substring(2), null);
79
80             if (expression[expression.Length - 1] != '}')
81                 throw new Exception("Expression must end with '}'");
82
83             int len;
84             string match;
85             if (!MarkupExpressionParser.MatchMarkup(out match, expression, out len))
86                 throw new Exception();
87             expression = expression.Substring(len).TrimStart();
88             if (expression.Length == 0)
89                 throw new Exception("Expression did not end in '}'");
90
91             var serviceProvider = new XamlServiceProvider(node, Context);
92             serviceProvider.Add(typeof(IXmlNamespaceResolver), nsResolver);
93
94             return new MarkupExpansionParser().Parse(match, ref expression, serviceProvider);
95         }
96
97         public class MarkupExpansionParser : MarkupExpressionParser, IExpressionParser<INode>
98         {
99             IElementNode node;
100
101             object IExpressionParser.Parse(string match, ref string remaining, IServiceProvider serviceProvider)
102             {
103                 return Parse(match, ref remaining, serviceProvider);
104             }
105
106             public INode Parse(string match, ref string remaining, IServiceProvider serviceProvider)
107             {
108                 var nsResolver = serviceProvider.GetService(typeof(IXmlNamespaceResolver)) as IXmlNamespaceResolver;
109                 if (nsResolver == null)
110                     throw new ArgumentException(nameof(nsResolver));
111                 IXmlLineInfo xmlLineInfo = null;
112                 var xmlLineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider;
113                 if (xmlLineInfoProvider != null)
114                     xmlLineInfo = xmlLineInfoProvider.XmlLineInfo;
115
116                 var split = match.Split(':');
117                 if (split.Length > 2)
118                     throw new ArgumentException(nameof(split.Length));
119
120                 string prefix; //, name;
121                 if (split.Length == 2)
122                 {
123                     prefix = split[0];
124                     //                                  name = split [1];
125                 }
126                 else
127                 {
128                     prefix = "";
129                     //                                  name = split [0];
130                 }
131
132                 Type type;
133                 var typeResolver = serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlTypeResolver;
134                 if (typeResolver == null)
135                     type = null;
136                 // Add Binding and StaticResource support, The ordinal code can't find BindingExtension for Binding
137                 //else if (match == "Binding")
138                 //{
139                 //    type = typeof(BindingExtension);
140                 //}
141                 //else if (match == "StaticResource")
142                 //{
143                 //    type = typeof(StaticResourceExtension);
144                 //}
145                 else
146                 {
147                     //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.
148                     if (!typeResolver.TryResolve(match + "Extension", out type) && !typeResolver.TryResolve(match, out type))
149                     {
150                         var lineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider;
151                         var lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
152                         throw new XamlParseException(String.Format("MarkupExtension not found for {0}", match), lineInfo);
153                     }
154                 }
155
156                 var namespaceuri = nsResolver.LookupNamespace(prefix) ?? "";
157                 var xmltype = new XmlType(namespaceuri, type?.Name, null);
158
159                 if (type == null)
160                     throw new NotSupportedException();
161
162                 node = xmlLineInfo == null
163                     ? new ElementNode(xmltype, null, nsResolver)
164                     : new ElementNode(xmltype, null, nsResolver, xmlLineInfo.LineNumber, xmlLineInfo.LinePosition);
165
166                 if (remaining.StartsWith("}", StringComparison.Ordinal))
167                 {
168                     remaining = remaining.Substring(1);
169                     return node;
170                 }
171
172                 char next;
173                 string piece;
174                 while ((piece = GetNextPiece(ref remaining, out next)) != null)
175                     HandleProperty(piece, serviceProvider, ref remaining, next != '=');
176
177                 return node;
178             }
179
180             protected override void SetPropertyValue(string prop, string strValue, object value, IServiceProvider serviceProvider)
181             {
182                 var nsResolver = serviceProvider.GetService(typeof(IXmlNamespaceResolver)) as IXmlNamespaceResolver;
183
184                 var childnode = value as INode ?? new ValueNode(strValue, nsResolver);
185                 childnode.Parent = node;
186                 if (prop != null)
187                 {
188                     var name = new XmlName(node.NamespaceURI, prop);
189                     node.Properties[name] = childnode;
190                 }
191                 else //ContentProperty
192                     node.CollectionItems.Add(childnode);
193             }
194         }
195     }
196 }