[corlib] Update ValueTuple implementation
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / Microsoft.Tools.Common / Microsoft / Activities / Presentation / Xaml / ActivityTemplateFactoryBuilderWriter.cs
1 // <copyright>
2 //   Copyright (c) Microsoft Corporation.  All rights reserved.
3 // </copyright>
4
5 namespace Microsoft.Activities.Presentation.Xaml
6 {
7     using System;
8     using System.Activities.Presentation.Toolbox;
9     using System.Xaml;
10
11     // ActivityTemplateFactoryBuilderWriter is a XamlWriter that support <ActivityTemplateFactory x:Class ... 
12     //
13     // Think of this class (and any other XamlWriter) as a XAML node stream editor
14     // XAML node are *not* objects, they are represented as method calls. For example, when WriteStartObject is called, a StartObject node is send to this writer.
15     // The writer will then edit the stream and send the nodes to the underlying stream (by calling the methods on the underlying writer)
16     // 
17     // The editing algorithm goes as follow:
18     //
19     // The system starts as the InitialState. There are five states in total: (InitialState, BufferingState, BufferingNameState, BufferingTargetTypeState, BypassState)
20     // If the very first StartObject node is ActivityTemplateFactory, then start buffering by going to the buffering state, otherwise simply go to the ByPassState.
21     // 
22     // In the buffering state, the nodes are buffered in a XamlNodeQueue, until we see the Implementation Node.
23     // When we reach the Implementation node, we will flush all the nodes transformed to the underlyingWriter, we will also switch to the ByPass state.
24     // 
25     // During the buffering, it is possible that we encounter the Name/TargetType node - the name node cannot enter the buffer because editing is required, we will use a separate state to track that.
26     internal sealed class ActivityTemplateFactoryBuilderWriter : XamlWriter
27     {
28         private XamlSchemaContext schemaContext;
29         private XamlWriter underlyingWriter;
30         private XamlType activityTemplateFactoryType;
31         private XamlMember activityTemplateFactoryImplementationMember;
32         private XamlMember activityTemplateFactoryBuilderImplementationMember;
33         private XamlMember activityTemplateFactoryBuilderNameMember;
34         private XamlMember activityTemplateFactoryBuilderTargetTypeMember;
35
36         // Buffering of nodes before starting the Implementation node 
37         private ActivityTemplateFactoryBuilderWriterStates currentState = ActivityTemplateFactoryBuilderWriterStates.InitialState;
38         private XamlNodeQueue queuedNodes;
39         private string className;
40         private string targetType;
41         private bool xamlLanguageNamespaceWritten = false;
42
43         public ActivityTemplateFactoryBuilderWriter(XamlWriter underlyingWriter, XamlSchemaContext schemaContext)
44         {
45             this.schemaContext = schemaContext;
46             this.underlyingWriter = underlyingWriter;
47         }
48
49         private enum ActivityTemplateFactoryBuilderWriterStates
50         {
51             InitialState,
52             BufferingState,
53             BufferingNameState,
54             BufferingTargetTypeState,
55             BypassState,
56         }
57
58         public override XamlSchemaContext SchemaContext
59         {
60             get { return this.schemaContext; }
61         }
62
63         private XamlType ActivityTemplateFactoryType
64         {
65             get
66             {
67                 if (this.activityTemplateFactoryType == null)
68                 {
69                     this.activityTemplateFactoryType = new XamlType(typeof(ActivityTemplateFactory), this.schemaContext);
70                 }
71
72                 return this.activityTemplateFactoryType;
73             }
74         }
75
76         private XamlMember ActivityTemplateFactoryImplementationMember
77         {
78             get
79             {
80                 if (this.activityTemplateFactoryImplementationMember == null)
81                 {
82                     this.activityTemplateFactoryImplementationMember = ActivityTemplateFactoryBuilderXamlMembers.ActivityTemplateFactoryImplementationMemberForWriter(this.schemaContext);
83                 }
84
85                 return this.activityTemplateFactoryImplementationMember;
86             }
87         }
88
89         private XamlMember ActivityTemplateFactoryBuilderImplementationMember
90         {
91             get
92             {
93                 if (this.activityTemplateFactoryBuilderImplementationMember == null)
94                 {
95                     this.activityTemplateFactoryBuilderImplementationMember = ActivityTemplateFactoryBuilderXamlMembers.ActivityTemplateFactoryBuilderImplementationMember(this.schemaContext);
96                 }
97
98                 return this.activityTemplateFactoryBuilderImplementationMember;
99             }
100         }
101
102         private XamlMember ActivityTemplateFactoryBuilderNameMember
103         {
104             get
105             {
106                 if (this.activityTemplateFactoryBuilderNameMember == null)
107                 {
108                     this.activityTemplateFactoryBuilderNameMember = ActivityTemplateFactoryBuilderXamlMembers.ActivityTemplateFactoryBuilderNameMember(this.schemaContext);
109                 }
110
111                 return this.activityTemplateFactoryBuilderNameMember;
112             }
113         }
114
115         private XamlMember ActivityTemplateFactoryBuilderTargetTypeMember
116         {
117             get
118             {
119                 if (this.activityTemplateFactoryBuilderTargetTypeMember == null)
120                 {
121                     this.activityTemplateFactoryBuilderTargetTypeMember = ActivityTemplateFactoryBuilderXamlMembers.ActivityTemplateFactoryBuilderTargetTypeMember(this.schemaContext);
122                 }
123
124                 return this.activityTemplateFactoryBuilderTargetTypeMember;
125             }
126         }
127
128         public override void WriteNamespace(NamespaceDeclaration namespaceDeclaration)
129         {
130             if (namespaceDeclaration.Prefix == "x")
131             {
132                 this.xamlLanguageNamespaceWritten = true;
133             }
134
135             this.underlyingWriter.WriteNamespace(namespaceDeclaration);
136         }
137
138         public override void WriteStartObject(XamlType type)
139         {
140             switch (this.currentState)
141             {
142                 case ActivityTemplateFactoryBuilderWriterStates.InitialState:
143                     if (type.Equals(new XamlType(typeof(ActivityTemplateFactoryBuilder), this.schemaContext)))
144                     {
145                         this.queuedNodes = new XamlNodeQueue(this.schemaContext);
146                         this.currentState = ActivityTemplateFactoryBuilderWriterStates.BufferingState;
147                     }
148                     else
149                     {
150                         this.currentState = ActivityTemplateFactoryBuilderWriterStates.BypassState;
151                         this.underlyingWriter.WriteStartObject(type);
152                     }
153
154                     break;
155                 case ActivityTemplateFactoryBuilderWriterStates.BypassState:
156                     this.underlyingWriter.WriteStartObject(type);
157                     break;
158                 default:
159                     SharedFx.Assert(
160                         this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingState
161                         || this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingNameState
162                         || this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingTargetTypeState,
163                         "These are the only possible ActivityTemplateFactoryBuilderWriterStates.");
164                     SharedFx.Assert("It is impossible to start any object during the buffering state.");
165                     break;
166             }
167         }
168
169         public override void WriteEndObject()
170         {
171             switch (this.currentState)
172             {
173                 case ActivityTemplateFactoryBuilderWriterStates.InitialState:
174                     SharedFx.Assert("It is impossible to end an object during InitialState");
175                     break;
176                 case ActivityTemplateFactoryBuilderWriterStates.BufferingState:
177                     this.queuedNodes.Writer.WriteEndObject();
178                     break;
179                 case ActivityTemplateFactoryBuilderWriterStates.BypassState:
180                     this.underlyingWriter.WriteEndObject();
181                     break;
182                 default:
183                     SharedFx.Assert(
184                         this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingNameState 
185                         || this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingTargetTypeState,
186                         "These are the only possible ActivityTemplateFactoryBuilderWriterStates.");
187                     SharedFx.Assert("It is impossible to end an object when we are buffering the name / targetType.");
188                     break;
189             }
190         }
191
192         public override void WriteGetObject()
193         {
194             switch (this.currentState)
195             {
196                 case ActivityTemplateFactoryBuilderWriterStates.InitialState:
197                     SharedFx.Assert("It is impossible to end an object during InitialState");
198                     break;
199                 case ActivityTemplateFactoryBuilderWriterStates.BufferingState:
200                     this.queuedNodes.Writer.WriteGetObject();
201                     break;
202                 case ActivityTemplateFactoryBuilderWriterStates.BypassState:
203                     this.underlyingWriter.WriteGetObject();
204                     break;
205                 default:
206                     SharedFx.Assert(
207                         this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingNameState 
208                         || this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingTargetTypeState, 
209                         "These are the only possible ActivityTemplateFactoryBuilderWriterStates.");
210                     SharedFx.Assert("It is impossible to get an object when we are buffering the name / targetType.");
211                     break;
212             }
213         }
214
215         public override void WriteStartMember(XamlMember xamlMember)
216         {
217             switch (this.currentState)
218             {
219                 case ActivityTemplateFactoryBuilderWriterStates.InitialState:
220                     SharedFx.Assert("It is impossible to start a member during InitialState");
221                     break;
222                 case ActivityTemplateFactoryBuilderWriterStates.BufferingState:
223                     if (xamlMember == this.ActivityTemplateFactoryBuilderImplementationMember)
224                     {
225                         xamlMember = this.ActivityTemplateFactoryImplementationMember;
226
227                         if (!this.xamlLanguageNamespaceWritten)
228                         {
229                             // Required namespace for XAML x:Class 
230                             this.underlyingWriter.WriteNamespace(new NamespaceDeclaration("http://schemas.microsoft.com/winfx/2006/xaml", "x"));
231                         }
232
233                         this.underlyingWriter.WriteStartObject(this.ActivityTemplateFactoryType);
234                         this.underlyingWriter.WriteStartMember(XamlLanguage.Class);
235                         this.underlyingWriter.WriteValue(this.className);
236                         this.underlyingWriter.WriteEndMember();
237                         this.underlyingWriter.WriteStartMember(XamlLanguage.TypeArguments);
238                         this.underlyingWriter.WriteValue(this.targetType);
239                         this.underlyingWriter.WriteEndMember();
240                         this.Transform(this.queuedNodes.Reader, this.underlyingWriter);
241                         this.underlyingWriter.WriteStartMember(xamlMember);
242                         this.currentState = ActivityTemplateFactoryBuilderWriterStates.BypassState;
243                     }
244
245                     if (xamlMember == this.ActivityTemplateFactoryBuilderNameMember)
246                     {
247                         this.currentState = ActivityTemplateFactoryBuilderWriterStates.BufferingNameState;
248                     }
249                     else if (xamlMember == this.ActivityTemplateFactoryBuilderTargetTypeMember)
250                     {
251                         this.currentState = ActivityTemplateFactoryBuilderWriterStates.BufferingTargetTypeState;
252                     }
253                     else
254                     {
255                         this.queuedNodes.Writer.WriteStartMember(xamlMember);
256                     }
257
258                     break;
259                 case ActivityTemplateFactoryBuilderWriterStates.BypassState:
260                     this.underlyingWriter.WriteStartMember(xamlMember);
261                     break;
262                 default:
263                     SharedFx.Assert(
264                         this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingNameState 
265                         || this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingTargetTypeState, 
266                         "These are the only possible ActivityTemplateFactoryBuilderWriterStates.");
267                     SharedFx.Assert("It is impossible to get an object when we are buffering the name / targetType.");
268                     break;
269             }
270         }
271
272         public override void WriteEndMember()
273         {
274             switch (this.currentState)
275             {
276                 case ActivityTemplateFactoryBuilderWriterStates.InitialState:
277                     SharedFx.Assert("It is impossible to end a member during InitialState");
278                     break;
279                 case ActivityTemplateFactoryBuilderWriterStates.BufferingState:
280                     this.queuedNodes.Writer.WriteEndMember();
281                     break;
282                 case ActivityTemplateFactoryBuilderWriterStates.BypassState:
283                     this.underlyingWriter.WriteEndMember();
284                     break;
285                 default:
286                     SharedFx.Assert(
287                         this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingNameState 
288                         || this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingTargetTypeState, 
289                         "These are the only possible ActivityTemplateFactoryBuilderWriterStates.");
290
291                     // Intentionally skipped the end member of Name / TargetType node
292                     this.currentState = ActivityTemplateFactoryBuilderWriterStates.BufferingState;
293                     break;
294             }
295         }
296
297         public override void WriteValue(object value)
298         {
299             switch (this.currentState)
300             {
301                 case ActivityTemplateFactoryBuilderWriterStates.InitialState:
302                     SharedFx.Assert("It is impossible to write a value during InitialState");
303                     break;
304                 case ActivityTemplateFactoryBuilderWriterStates.BufferingState:
305                     this.queuedNodes.Writer.WriteValue(value);
306                     break;
307                 case ActivityTemplateFactoryBuilderWriterStates.BufferingNameState:
308                     this.className = (string)value;
309                     break;
310                 case ActivityTemplateFactoryBuilderWriterStates.BufferingTargetTypeState:
311                     this.targetType = (string)value;
312                     break;
313                 default:
314                     SharedFx.Assert(
315                         this.currentState == ActivityTemplateFactoryBuilderWriterStates.BypassState, 
316                         "This is the only possible ActivityTemplateFactoryBuilderWriterStates");
317                     this.underlyingWriter.WriteValue(value);
318                     break;
319             }
320         }
321
322         private void Transform(XamlReader reader, XamlWriter myWriter)
323         {
324             while (!reader.IsEof)
325             {
326                 reader.Read();
327                 myWriter.WriteNode(reader);
328             }
329         }
330     }
331 }