copied mono-api-diff.cs from mono-2-2 branch so new patch can be applied and history...
[mono.git] / mcs / class / System.Data / System.Data / CustomDataClassGenerator.cs
1 //
2 // Mono.Data.CustomDataClassGenerator
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // (C)2004 Novell Inc.
8 //
9 // API notes are the bottom of the source.
10 //
11 // This class is standalone testable (even under MS.NET) when compiled with
12 // -d:DATACLASS_GENERATOR_STANDALONE .
13 //
14
15 //
16 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
17 //
18 // Permission is hereby granted, free of charge, to any person obtaining
19 // a copy of this software and associated documentation files (the
20 // "Software"), to deal in the Software without restriction, including
21 // without limitation the rights to use, copy, modify, merge, publish,
22 // distribute, sublicense, and/or sell copies of the Software, and to
23 // permit persons to whom the Software is furnished to do so, subject to
24 // the following conditions:
25 // 
26 // The above copyright notice and this permission notice shall be
27 // included in all copies or substantial portions of the Software.
28 // 
29 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 //
37 using System;
38 using System.Xml;
39 using System.Data;
40 using System.Data.Common;
41 using System.Collections;
42 using System.CodeDom;
43 using System.Globalization;
44 using System.Text;
45 using System.CodeDom.Compiler;
46 using System.ComponentModel;
47 using System.Runtime.Serialization;
48 using System.Xml.Schema;
49 using System.Xml.Serialization;
50 using System.Reflection;
51
52 // only for Driver
53 using Microsoft.CSharp;
54 using System.IO;
55
56 namespace System.Data
57 {
58
59 #if DATACLASS_GENERATOR_STANDALONE
60         public class Driver
61         {
62                 public static void Main (string [] args)
63                 {
64                         try {
65                                 if (args.Length < 1) {
66                                         Console.WriteLine ("mono dsgentest.exe filename");
67                                         return;
68                                 }
69
70                                 DataSet ds = new DataSet ();
71                                 ds.ReadXml (args [0]);
72                                 ICodeGenerator gen = new CSharpCodeProvider ().CreateGenerator ();
73
74                                 CodeNamespace cns = new CodeNamespace ("MyNamespace");
75                                 TextWriter tw = new StreamWriter (Path.ChangeExtension (args [0], ".ms.cs"), false, Encoding.Default);
76                                 TypedDataSetGenerator.Generate (ds, cns, gen);
77                                 gen.GenerateCodeFromNamespace (cns, tw, null);
78                                 tw.Close ();
79
80                                 cns = new CodeNamespace ("MyNamespace");
81                                 tw = new StreamWriter (Path.ChangeExtension (args [0], ".mono.cs"), false, Encoding.Default);
82                                 CustomDataClassGenerator.CreateDataSetClasses (ds, cns, gen, null);
83                                 gen.GenerateCodeFromNamespace (cns, tw, null);
84                                 tw.Close ();
85                         } catch (Exception ex) {
86                                 Console.WriteLine (ex);
87                         }
88                 }
89         }
90 #endif
91
92 #if DATACLASS_GENERATOR_STANDALONE
93         public class CustomDataClassGenerator
94 #else
95         internal class CustomDataClassGenerator
96 #endif
97         {
98                 public static void CreateDataSetClasses (DataSet ds,
99                         CodeNamespace cns, ICodeGenerator gen,
100                         ClassGeneratorOptions options)
101                 {
102                         new Generator (ds, cns, gen, options).Run ();
103                 }
104
105 #if NET_2_0
106                 public static void CreateDataSetClasses (DataSet ds,
107                         CodeNamespace cns, CodeDomProvider codeProvider,
108                         ClassGeneratorOptions options)
109                 {
110                         new Generator (ds, cns, codeProvider, options).Run ();
111                 }
112
113                 public static void CreateDataSetClasses (DataSet ds, 
114                                                          CodeCompileUnit cunit, 
115                                                          CodeNamespace cns, 
116                                                          CodeDomProvider codeProvider, 
117                                                          ClassGeneratorOptions options)
118                 {
119                         new Generator (ds, cunit, cns, codeProvider, options).Run ();
120                 }
121 #endif
122                 public static string MakeSafeName (string name, ICodeGenerator codeGen)
123                 {
124                         if (name == null || codeGen == null)
125                                 throw new NullReferenceException ();
126
127                         name = codeGen.CreateValidIdentifier (name);
128
129                         return MakeSafeNameInternal (name);
130                 }
131                 
132 #if NET_2_0
133                 public static string MakeSafeName (string name, CodeDomProvider provider)
134                 {
135                         if (name == null || provider == null)
136                                 throw new NullReferenceException ();
137
138                         name = provider.CreateValidIdentifier (name);
139
140                         return MakeSafeNameInternal (name);
141                 }
142 #endif
143                 
144                 public static string MakeSafeNameInternal (string name)
145                 {
146                         if (name.Length == 0)
147                                 return "_";
148
149                         StringBuilder sb = null;
150                         if (!Char.IsLetter (name, 0) && name [0] != '_') {
151                                 sb = new StringBuilder ();
152                                 sb.Append ('_');
153                         }
154
155                         int start = 0;
156                         for (int i = 0; i < name.Length; i++) {
157                                 if (!Char.IsLetterOrDigit (name, i)) {
158                                         if (sb == null)
159                                                 sb = new StringBuilder ();
160                                         sb.Append (name, start, i - start);
161                                         sb.Append ('_');
162                                         start = i + 1;
163                                 }
164                         }
165
166                         if (sb != null) {
167                                 sb.Append (name, start, name.Length - start);
168                                 return sb.ToString ();
169                         }
170                         else
171                                 return name;
172                 }
173         }
174
175 #if DATACLASS_GENERATOR_STANDALONE
176         public delegate string CodeNamingMethod (string source, ICodeGenerator gen);
177 #else
178         internal delegate string CodeNamingMethod (string source, ICodeGenerator gen);
179 #endif
180
181 #if DATACLASS_GENERATOR_STANDALONE
182         public delegate string CodeDomNamingMethod (string source, CodeDomProvider provider);
183 #else
184         internal delegate string CodeDomNamingMethod (string source, CodeDomProvider provider);
185 #endif  
186         
187 #if DATACLASS_GENERATOR_STANDALONE
188         public class ClassICodeGeneratorOptions : ClassGeneratorOptions
189 #else
190         internal class ClassICodeGeneratorOptions : ClassGeneratorOptions
191 #endif
192         {
193                 ICodeGenerator gen;
194                 
195                 public CodeNamingMethod CreateDataSetName;
196                 public CodeNamingMethod CreateTableTypeName;
197                 public CodeNamingMethod CreateTableMemberName;
198                 public CodeNamingMethod CreateTableColumnName;
199                 public CodeNamingMethod CreateColumnName;
200                 public CodeNamingMethod CreateRowName;
201                 public CodeNamingMethod CreateRelationName;
202                 public CodeNamingMethod CreateTableDelegateName;
203                 public CodeNamingMethod CreateEventArgsName;
204                 public CodeNamingMethod CreateTableAdapterNSName;
205                 public CodeNamingMethod CreateTableAdapterName;
206
207                 public ClassICodeGeneratorOptions (ICodeGenerator codeGen)
208                 {
209                         this.gen = codeGen;
210                 }
211                 
212                 internal override string DataSetName (string source)
213                 {
214                         if (CreateDataSetName != null)
215                                 return CreateDataSetName (source, gen);
216                         else
217                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
218                 }
219
220                 internal override string TableTypeName (string source)
221                 {
222                         if (CreateTableTypeName != null)
223                                 return CreateTableTypeName (source, gen);
224                         else
225                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "DataTable";
226                 }
227
228                 internal override string TableMemberName (string source)
229                 {
230                         if (CreateTableMemberName != null)
231                                 return CreateTableMemberName (source, gen);
232                         else
233                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
234                 }
235
236                 internal override string TableColName (string source)
237                 {
238                         if (CreateTableColumnName != null)
239                                 return CreateTableColumnName (source, gen);
240                         else
241                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
242                 }
243
244                 internal override string TableDelegateName (string source)
245                 {
246                         if (CreateTableDelegateName != null)
247                                 return CreateTableDelegateName (source, gen);
248                         else
249                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "RowChangedEventHandler";
250                 }
251
252                 internal override string EventArgsName (string source)
253                 {
254                         if (CreateEventArgsName != null)
255                                 return CreateEventArgsName (source, gen);
256                         else
257                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "RowChangedEventArgs";
258                 }
259
260                 internal override string ColumnName (string source)
261                 {
262                         if (CreateColumnName != null)
263                                 return CreateColumnName (source, gen);
264                         else
265                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
266                 }
267
268                 internal override string RowName (string source)
269                 {
270                         if (CreateRowName != null)
271                                 return CreateRowName (source, gen);
272                         else
273                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "Row";
274                 }
275
276                 internal override string RelationName (string source)
277                 {
278                         if (CreateRelationName != null)
279                                 return CreateRelationName (source, gen);
280                         else
281                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "Relation";
282                 }
283
284                 internal override string TableAdapterNSName (string source)
285                 {
286                         if (CreateTableAdapterNSName != null)
287                                 return CreateTableAdapterNSName (source, gen);
288                         else
289                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "TableAdapters";
290                 }
291                 
292                 internal override string TableAdapterName (string source)
293                 {
294                         if (CreateTableAdapterName != null)
295                                 return CreateTableAdapterName (source, gen);
296                         else
297                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
298                 }
299         }
300         
301 #if NET_2_0
302 #if DATACLASS_GENERATOR_STANDALONE
303         public class ClassCodeDomProviderOptions : ClassGeneratorOptions
304 #else
305         internal class ClassCodeDomProviderOptions : ClassGeneratorOptions
306 #endif
307         {
308                 CodeDomProvider provider;
309                 
310                 public CodeDomNamingMethod CreateDataSetName;
311                 public CodeDomNamingMethod CreateTableTypeName;
312                 public CodeDomNamingMethod CreateTableMemberName;
313                 public CodeDomNamingMethod CreateTableColumnName;
314                 public CodeDomNamingMethod CreateColumnName;
315                 public CodeDomNamingMethod CreateRowName;
316                 public CodeDomNamingMethod CreateRelationName;
317                 public CodeDomNamingMethod CreateTableDelegateName;
318                 public CodeDomNamingMethod CreateEventArgsName;                 
319                 public CodeDomNamingMethod CreateTableAdapterNSName;
320                 public CodeDomNamingMethod CreateTableAdapterName;
321                 
322                 public ClassCodeDomProviderOptions (CodeDomProvider codeProvider)
323                 {
324                         this.provider = codeProvider;
325                 }
326                 
327                 internal override string DataSetName (string source)
328                 {
329                         if (CreateDataSetName != null)
330                                 return CreateDataSetName (source, provider);
331                         else
332                                 return CustomDataClassGenerator.MakeSafeName (source, provider);
333                 }
334
335                 internal override string TableTypeName (string source)
336                 {
337                         if (CreateTableTypeName != null)
338                                 return CreateTableTypeName (source, provider);
339                         else
340                                 return CustomDataClassGenerator.MakeSafeName (source, provider) + "DataTable";
341                 }
342
343                 internal override string TableMemberName (string source)
344                 {
345                         if (CreateTableMemberName != null)
346                                 return CreateTableMemberName (source, provider);
347                         else
348                                 return CustomDataClassGenerator.MakeSafeName (source, provider);
349                 }
350
351                 internal override string TableColName (string source)
352                 {
353                         if (CreateTableColumnName != null)
354                                 return CreateTableColumnName (source, provider);
355                         else
356                                 return CustomDataClassGenerator.MakeSafeName (source, provider);
357                 }
358
359                 internal override string TableDelegateName (string source)
360                 {
361                         if (CreateTableDelegateName != null)
362                                 return CreateTableDelegateName (source, provider);
363                         else
364                                 return CustomDataClassGenerator.MakeSafeName (source, provider) + "RowChangedEventHandler";
365                 }
366
367                 internal override string EventArgsName (string source)
368                 {
369                         if (CreateEventArgsName != null)
370                                 return CreateEventArgsName (source, provider);
371                         else
372                                 return CustomDataClassGenerator.MakeSafeName (source, provider) + "RowChangedEventArgs";
373                 }
374
375                 internal override string ColumnName (string source)
376                 {
377                         if (CreateColumnName != null)
378                                 return CreateColumnName (source, provider);
379                         else
380                                 return CustomDataClassGenerator.MakeSafeName (source, provider);
381                 }
382
383                 internal override string RowName (string source)
384                 {
385                         if (CreateRowName != null)
386                                 return CreateRowName (source, provider);
387                         else
388                                 return CustomDataClassGenerator.MakeSafeName (source, provider) + "Row";
389                 }
390
391                 internal override string RelationName (string source)
392                 {
393                         if (CreateRelationName != null)
394                                 return CreateRelationName (source, provider);
395                         else
396                                 return CustomDataClassGenerator.MakeSafeName (source, provider) + "Relation";
397                 }
398
399                 internal override string TableAdapterNSName (string source)
400                 {
401                         if (CreateTableAdapterNSName != null)
402                                 return CreateTableAdapterNSName (source, provider);
403                         else
404                                 return CustomDataClassGenerator.MakeSafeName (source, provider) + "TableAdapters";
405                 }
406
407                 internal override string TableAdapterName (string source)
408                 {
409                         if (CreateTableAdapterName != null)
410                                 return CreateTableAdapterName (source, provider);
411                         else
412                                 return CustomDataClassGenerator.MakeSafeName (source, provider);
413                 }               
414         }
415 #endif  // NET_2_0
416         
417 #if DATACLASS_GENERATOR_STANDALONE
418         public abstract class ClassGeneratorOptions
419 #else
420         internal abstract class ClassGeneratorOptions
421 #endif
422         {
423                 public bool MakeClassesInsideDataSet = true; // default = MS compatible
424                 
425                 internal abstract string DataSetName (string source);
426                 internal abstract string TableTypeName (string source);
427                 internal abstract string TableMemberName (string source);
428                 internal abstract string TableColName (string source);
429                 internal abstract string TableDelegateName (string source);
430                 internal abstract string EventArgsName (string source);
431                 internal abstract string ColumnName (string source);
432                 internal abstract string RowName (string source);
433                 internal abstract string RelationName (string source);
434                 internal abstract string TableAdapterNSName (string source);
435                 internal abstract string TableAdapterName (string source);
436         }
437
438         internal class Generator
439         {
440 //              static ClassGeneratorOptions DefaultOptions = new ClassGeneratorOptions ();
441
442                 DataSet ds;
443                 CodeNamespace cns;
444                 ClassGeneratorOptions opts;
445                 CodeCompileUnit cunit;
446
447                 CodeTypeDeclaration dsType;
448
449                 public Generator (DataSet ds, CodeNamespace cns, ICodeGenerator codeGen, ClassGeneratorOptions options)
450                 {
451                         this.ds = ds;
452                         this.cns = cns;
453                         this.opts = options;
454                         this.cunit = null;
455                         if (opts == null)
456                                 opts = new ClassICodeGeneratorOptions (codeGen);
457                 }
458 #if NET_2_0
459                 public Generator (DataSet ds, CodeNamespace cns, CodeDomProvider codeProvider, 
460                                   ClassGeneratorOptions options)
461                 {
462                         this.ds = ds;
463                         this.cns = cns;
464                         this.opts = options;
465                         this.cunit = null;
466                         if (opts == null)
467                                 opts = new ClassCodeDomProviderOptions (codeProvider);                  
468                 }
469
470                 public Generator (DataSet ds, CodeCompileUnit cunit, CodeNamespace cns, 
471                                   CodeDomProvider codeProvider, ClassGeneratorOptions options)
472                 {
473                         this.ds = ds;
474                         this.cns = cns;
475                         this.opts = options;
476                         this.cunit = cunit;
477                         if (opts == null)
478                                 opts = new ClassCodeDomProviderOptions (codeProvider);
479                 }
480 #endif
481                 public void Run ()
482                 {
483                         // using decls
484                         cns.Imports.Add (new CodeNamespaceImport ("System"));
485                         cns.Imports.Add (new CodeNamespaceImport ("System.Collections"));
486                         cns.Imports.Add (new CodeNamespaceImport ("System.ComponentModel"));
487                         cns.Imports.Add (new CodeNamespaceImport ("System.Data"));
488                         cns.Imports.Add (new CodeNamespaceImport ("System.Runtime.Serialization"));
489                         cns.Imports.Add (new CodeNamespaceImport ("System.Xml"));
490
491
492                         CodeTypeDeclaration dsType = GenerateDataSetType ();
493                         cns.Types.Add (dsType);
494
495                         foreach (DataTable dt in ds.Tables) {
496                                 // 1. table types ([foo]DataTable)
497                                 // 2. row types ([foo]Row)
498                                 // 3. delegates ([foo]RowChangedEventHandler)
499                                 // 4. eventargs ([foo]RowChangeEventArgs)
500
501                                 CodeTypeDeclaration dtType = GenerateDataTableType (dt);
502
503                                 CodeTypeDeclaration dtRow = GenerateDataRowType (dt);
504
505                                 CodeTypeDelegate dtDelegate = new CodeTypeDelegate (opts.TableDelegateName (dt.TableName));
506                                 dtDelegate.Parameters.Add (Param (typeof (object), "o"));
507                                 dtDelegate.Parameters.Add (Param (opts.EventArgsName (dt.TableName), "e"));
508
509                                 CodeTypeDeclaration dtEventType = GenerateEventType (dt);
510
511                                 // Add types to either DataSet or CodeNamespace
512                                 if (opts.MakeClassesInsideDataSet) {
513                                         dsType.Members.Add (dtType);
514                                         dsType.Members.Add (dtRow);
515                                         dsType.Members.Add (dtDelegate);
516                                         dsType.Members.Add (dtEventType);
517                                 }
518                                 else {
519                                         cns.Types.Add (dtType);
520                                         cns.Types.Add (dtRow);
521                                         cns.Types.Add (dtDelegate);
522                                         cns.Types.Add (dtEventType);
523                                 }
524                         }
525
526 #if NET_2_0
527                         if (cunit == null)
528                                 return;
529                         
530                         TableAdapterSchemaInfo adapterInfo = ds.TableAdapterSchemaData;
531                         if (adapterInfo != null) {
532                                 // #325464 debugging
533                                 //Console.WriteLine (opts.TableAdapterNSName(opts.DataSetName (ds.DataSetName)));
534                                 CodeNamespace cnsTA = new CodeNamespace (opts.TableAdapterNSName(opts.DataSetName (ds.DataSetName)));
535                                 CodeTypeDeclaration dtAdapter = GenerateTableAdapterType (adapterInfo);
536                                 cnsTA.Types.Add (dtAdapter);
537                                 cunit.Namespaces.Add (cnsTA);
538                         }
539 #endif
540                 }
541                 
542                 private CodeThisReferenceExpression This ()
543                 {
544                         return new CodeThisReferenceExpression ();
545                 }
546
547                 private CodeBaseReferenceExpression Base ()
548                 {
549                         return new CodeBaseReferenceExpression ();
550                 }
551
552                 private CodePrimitiveExpression Const (object value)
553                 {
554                         return new CodePrimitiveExpression (value);
555                 }
556
557                 private CodeTypeReference TypeRef (Type t)
558                 {
559                         return new CodeTypeReference (t);
560                 }
561
562                 private CodeTypeReference TypeRef (string name)
563                 {
564                         return new CodeTypeReference (name);
565                 }
566
567                 private CodeTypeReference TypeRefArray (Type t, int dimension)
568                 {
569                         return new CodeTypeReference (TypeRef (t), dimension);
570                 }
571
572                 private CodeTypeReference TypeRefArray (string name, int dimension)
573                 {
574                         return new CodeTypeReference (TypeRef (name), dimension);
575                 }
576                 
577                 private CodeParameterDeclarationExpression Param (string t, string name)
578                 {
579                         return new CodeParameterDeclarationExpression (t, name);
580                 }
581
582                 private CodeParameterDeclarationExpression Param (Type t, string name)
583                 {
584                         return new CodeParameterDeclarationExpression (t, name);
585                 }
586
587                 private CodeParameterDeclarationExpression Param (CodeTypeReference t, string name)
588                 {
589                         return new CodeParameterDeclarationExpression (t, name);
590                 }
591
592                 private CodeArgumentReferenceExpression ParamRef (string name)
593                 {
594                         return new CodeArgumentReferenceExpression (name);
595                 }
596
597                 private CodeCastExpression Cast (string t, CodeExpression exp)
598                 {
599                         return new CodeCastExpression (t, exp);
600                 }
601
602                 private CodeCastExpression Cast (Type t, CodeExpression exp)
603                 {
604                         return new CodeCastExpression (t, exp);
605                 }
606
607                 private CodeCastExpression Cast (CodeTypeReference t, CodeExpression exp)
608                 {
609                         return new CodeCastExpression (t, exp);
610                 }
611
612                 private CodeExpression New (Type t, params CodeExpression [] parameters)
613                 {
614                         return new CodeObjectCreateExpression (t, parameters);
615                 }
616
617                 private CodeExpression New (string t, params CodeExpression [] parameters)
618                 {
619                         return new CodeObjectCreateExpression (TypeRef (t), parameters);
620                 }
621
622                 private CodeExpression NewArray (Type t, params CodeExpression [] parameters)
623                 {
624                         return new CodeArrayCreateExpression (t, parameters);
625                 }
626
627                 private CodeExpression NewArray (Type t, int size )
628                 {
629                         return new CodeArrayCreateExpression (t, size);
630                 }
631
632                 private CodeVariableReferenceExpression Local (string name)
633                 {
634                         return new CodeVariableReferenceExpression (name);
635                 }
636
637                 private CodeFieldReferenceExpression FieldRef (string name)
638                 {
639                         return new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), name);
640                 }
641
642                 private CodeFieldReferenceExpression FieldRef (CodeExpression exp, string name)
643                 {
644                         return new CodeFieldReferenceExpression (exp, name);
645                 }
646
647                 private CodePropertyReferenceExpression PropRef (string name)
648                 {
649                         return new CodePropertyReferenceExpression (new CodeThisReferenceExpression (), name);
650                 }
651
652                 private CodePropertyReferenceExpression PropRef (CodeExpression target, string name)
653                 {
654                         return new CodePropertyReferenceExpression (target, name);
655                 }
656
657                 private CodeIndexerExpression IndexerRef (CodeExpression target, CodeExpression parameters)
658                 {
659                         return new CodeIndexerExpression (target, parameters);
660                 }
661
662                 private CodeIndexerExpression IndexerRef (CodeExpression param)
663                 {
664                         return new CodeIndexerExpression (new CodeThisReferenceExpression (), param);
665                 }
666
667                 private CodeEventReferenceExpression EventRef (string name)
668                 {
669                         return new CodeEventReferenceExpression (new CodeThisReferenceExpression (), name);
670                 }
671
672                 private CodeEventReferenceExpression EventRef (CodeExpression target, string name)
673                 {
674                         return new CodeEventReferenceExpression (target, name);
675                 }
676
677                 private CodeMethodInvokeExpression MethodInvoke (string name, params CodeExpression [] parameters)
678                 {
679                         return new CodeMethodInvokeExpression (new CodeThisReferenceExpression (), name, parameters);
680                 }
681
682                 private CodeMethodInvokeExpression MethodInvoke (CodeExpression target, string name, params CodeExpression [] parameters)
683                 {
684                         return new CodeMethodInvokeExpression (target, name, parameters);
685                 }
686
687                 private CodeBinaryOperatorExpression EqualsValue (CodeExpression exp1, CodeExpression exp2)
688                 {
689                         return new CodeBinaryOperatorExpression (exp1, CodeBinaryOperatorType.ValueEquality, exp2);
690                 }
691
692                 // note that this is "Identity" equality comparison
693                 private CodeBinaryOperatorExpression Equals (CodeExpression exp1, CodeExpression exp2)
694                 {
695                         return new CodeBinaryOperatorExpression (exp1, CodeBinaryOperatorType.IdentityEquality, exp2);
696                 }
697
698                 private CodeBinaryOperatorExpression Inequals (CodeExpression exp1, CodeExpression exp2)
699                 {
700                         return new CodeBinaryOperatorExpression (exp1, CodeBinaryOperatorType.IdentityInequality, exp2);
701                 }
702
703                 private CodeBinaryOperatorExpression GreaterThan (CodeExpression exp1, CodeExpression exp2)
704                 {
705                         return new CodeBinaryOperatorExpression (exp1, CodeBinaryOperatorType.GreaterThan, exp2);
706                 }
707
708                 private CodeBinaryOperatorExpression LessThan (CodeExpression exp1, CodeExpression exp2)
709                 {
710                         return new CodeBinaryOperatorExpression (exp1, CodeBinaryOperatorType.LessThan, exp2);
711                 }
712
713                 private CodeBinaryOperatorExpression Compute (CodeExpression exp1, CodeExpression exp2, CodeBinaryOperatorType ops)
714                 {
715                         if (ops >= CodeBinaryOperatorType.Add && ops < CodeBinaryOperatorType.Assign)
716                                 return new CodeBinaryOperatorExpression (exp1, ops, exp2);
717                         else
718                                 return null;
719                 }
720
721                 private CodeBinaryOperatorExpression BitOps (CodeExpression exp1, CodeExpression exp2, CodeBinaryOperatorType ops)
722                 {
723                         if (ops >= CodeBinaryOperatorType.BitwiseOr && ops <= CodeBinaryOperatorType.BitwiseAnd)
724                                 return new CodeBinaryOperatorExpression (exp1, ops, exp2);
725                         else
726                                 return null;
727                 }
728                 
729                 private CodeBinaryOperatorExpression BooleanOps (CodeExpression exp1, CodeExpression exp2, CodeBinaryOperatorType ops)
730                 {
731                         if (ops >= CodeBinaryOperatorType.BooleanOr && ops <= CodeBinaryOperatorType.BooleanAnd)
732                                 return new CodeBinaryOperatorExpression (exp1, ops, exp2);
733                         else
734                                 return null;
735                 }
736
737                 private CodeTypeReferenceExpression TypeRefExp (Type t)
738                 {
739                         return new CodeTypeReferenceExpression (t);
740                 }
741
742                 private CodeTypeOfExpression TypeOfRef (string name)
743                 {
744                         return new CodeTypeOfExpression (TypeRef (name));
745                 }
746
747                 private CodeExpressionStatement Eval (CodeExpression exp)
748                 {
749                         return new CodeExpressionStatement (exp);
750                 }
751
752                 private CodeAssignStatement Let (CodeExpression exp, CodeExpression value)
753                 {
754                         return new CodeAssignStatement (exp, value);
755                 }
756
757                 private CodeMethodReturnStatement Return (CodeExpression exp)
758                 {
759                         return new CodeMethodReturnStatement (exp);
760                 }
761
762                 private CodeVariableDeclarationStatement VarDecl (Type t,
763                         string name, CodeExpression init)
764                 {
765                         return new CodeVariableDeclarationStatement (t, name, init);
766                 }
767
768                 private CodeVariableDeclarationStatement VarDecl (string t,
769                         string name, CodeExpression init)
770                 {
771                         return new CodeVariableDeclarationStatement (t, name, init);
772                 }
773
774                 private CodeCommentStatement Comment (string comment)
775                 {
776                         return new CodeCommentStatement (comment);
777                 }
778
779                 private CodeThrowExceptionStatement Throw (CodeExpression exp)
780                 {
781                         return new CodeThrowExceptionStatement (exp);
782                 }
783
784 #region DataSet class
785
786                 private CodeTypeDeclaration GenerateDataSetType ()
787                 {
788                         // Type
789                         dsType = new CodeTypeDeclaration (opts.DataSetName (ds.DataSetName));
790                         dsType.BaseTypes.Add (TypeRef (typeof (DataSet)));
791                         dsType.BaseTypes.Add (TypeRef (typeof (IXmlSerializable)));
792
793                         // .ctor()
794                         dsType.Members.Add (CreateDataSetDefaultCtor ());
795                         // runtime serialization .ctor()
796                         dsType.Members.Add (CreateDataSetSerializationCtor ());
797
798                         // Clone()
799                         dsType.Members.Add (CreateDataSetCloneMethod (dsType));
800
801 // FIXME: I keep these methods out of the generated source right now.
802 // It should be added after runtime serialization was implemented.
803 /*
804                         // ShouldSerializeTables()
805                         dsType.Members.Add (CreateDataSetShouldSerializeTables ());
806
807                         // ShouldSerializeRelations()
808                         dsType.Members.Add (CreateDataSetShouldSerializeRelations ());
809
810                         // ReadXmlSerializable()
811                         dsType.Members.Add (CreateDataSetReadXmlSerializable ());
812 */
813
814                         // GetSchemaSerializable()
815                         dsType.Members.Add (CreateDataSetGetSchemaSerializable ());
816
817                         dsType.Members.Add (CreateDataSetGetSchema ());
818                         dsType.Members.Add (CreateDataSetInitializeClass ());
819                         dsType.Members.Add (CreateDataSetInitializeFields ());
820                         dsType.Members.Add (CreateDataSetSchemaChanged ());
821
822                         // table class and members
823                         foreach (DataTable table in ds.Tables)
824                                 CreateDataSetTableMembers (dsType, table);
825                         // relation class and members
826                         foreach (DataRelation rel in ds.Relations)
827                                 CreateDataSetRelationMembers (dsType, rel);
828
829                         return dsType;
830                 }
831
832                 // Code:
833                 // public Foo ()
834                 // {
835                 //   InitializeClass();
836                 //   CollectionChangeEventHandler handler = new CollectionChangeEventHandler (SchemaChanged);
837                 //   Tables.CollectionChanged += handler;
838                 //   Relations.CollectionChanged += handler;
839                 // }
840                 private CodeConstructor CreateDataSetDefaultCtor ()
841                 {
842                         CodeConstructor ctor = new CodeConstructor ();
843                         ctor.Attributes = MemberAttributes.Public;
844                         // Code: InitializeClass().
845                         ctor.Statements.Add (Eval (MethodInvoke ("InitializeClass")));
846
847                         // Code: CollectionChangedEventHandler handler = new CollectionChangeEventHandler (SchemeChanged);
848                         CodeVariableDeclarationStatement stmt2 = 
849                                 VarDecl (
850                                         typeof (CollectionChangeEventHandler), 
851                                         "handler", 
852                                         New (
853                                                 typeof (CollectionChangeEventHandler), 
854                                                 new CodeDelegateCreateExpression (
855                                                         new CodeTypeReference (typeof (CollectionChangeEventHandler)),
856                                                         new CodeThisReferenceExpression (), 
857                                                         "SchemaChanged")));
858
859                         ctor.Statements.Add (stmt2);
860
861                         // Code: Tables.CollectionChanged += handler;
862                         ctor.Statements.Add (
863                                 new CodeAttachEventStatement (
864                                         EventRef (
865                                                 PropRef ("Tables"), 
866                                                 "CollectionChanged"),
867                                         Local ("handler")));
868
869                         // Code: Relations.CollectionChanged += handler;
870                         ctor.Statements.Add (
871                                 new CodeAttachEventStatement (
872                                         EventRef (
873                                                 PropRef ("Relations"), 
874                                                 "CollectionChanged"), 
875                                         Local ("handler")));
876
877                         return ctor;
878                 }
879
880                 // TODO: implement
881
882                 // Code:
883                 // protected Foo (SerializationInfo info, StreamingContext ctx)
884                 // {
885                 //   throw new NotImplementedException ();
886                 // }
887                 private CodeConstructor CreateDataSetSerializationCtor ()
888                 {
889                         CodeConstructor ctor = new CodeConstructor ();
890                         ctor.Attributes = MemberAttributes.Family;
891                         ctor.Parameters.Add (Param (typeof (SerializationInfo), "info"));
892                         ctor.Parameters.Add (Param (typeof (StreamingContext), "ctx"));
893
894                         // Code: 
895                         //  // TODO: implement
896                         //  throw new NotImplementedException ();
897                         ctor.Statements.Add (Comment ("TODO: implement"));
898                         ctor.Statements.Add (Throw (New (typeof (NotImplementedException))));
899
900                         return ctor;
901                 }
902
903                 // Code:
904                 //  public override DataSet Clone()
905                 //  {
906                 //    [foo] set = ([foo]) base.Clone ();
907                 //    set.InitializeFields ();
908                 //    return set;
909                 //  }
910                 private CodeMemberMethod CreateDataSetCloneMethod (CodeTypeDeclaration dsType)
911                 {
912                         CodeMemberMethod m = new CodeMemberMethod ();
913                         m.ReturnType = TypeRef (typeof (DataSet));
914                         m.Attributes = MemberAttributes.Public | MemberAttributes.Override;
915                         m.Name = "Clone";
916                         // Code: [foo] set = ([foo]) base.Clone ();
917                         CodeVariableReferenceExpression set = Local ("set");
918                         m.Statements.Add (VarDecl (
919                                         dsType.Name,
920                                         "set", 
921                                         Cast (
922                                                 dsType.Name,
923                                                 MethodInvoke (Base (), "Clone"))));
924                         m.Statements.Add (Eval (MethodInvoke (set, "InitializeFields")));
925                         m.Statements.Add (Return (set));
926                         return m;
927                 }
928
929                 // Code:
930                 // protected override bool ShouldSerializeTables ()
931                 // {
932                 //   return true; // it should be false
933                 // }
934                 /*
935                 private CodeMemberMethod CreateDataSetShouldSerializeTables ()
936                 {
937                         CodeMemberMethod m = new CodeMemberMethod ();
938                         m.Name = "ShouldSerializeTables";
939                         m.ReturnType = TypeRef (typeof (bool));
940                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
941                         // FIXME: set "false" after serialization .ctor() implementation
942                         m.Statements.Add (Return (Const (true)));
943                         return m;
944                 }
945                 */
946                 // Code:
947                 // protected override bool ShouldSerializeRelations ()
948                 // {
949                 //   return true; // it should be false
950                 // }
951                 
952                 /*
953                 private CodeMemberMethod CreateDataSetShouldSerializeRelations ()
954                 {
955                         CodeMemberMethod m = new CodeMemberMethod ();
956                         m.Name = "ShouldSerializeRelations";
957                         m.ReturnType = TypeRef (typeof (bool));
958                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
959                         // FIXME: set "false" after serialization .ctor() implementation
960                         m.Statements.Add (Return (Const (true)));
961                         return m;
962                 }
963                 */
964
965                 // Code:
966                 // protected override void ReadXmlSerializable()
967                 // {
968                 //   // TODO: implement
969                 //   throw new NotImplementedException ();
970                 // }
971                 /*
972                 private CodeMemberMethod CreateDataSetReadXmlSerializable ()
973                 {
974                         CodeMemberMethod method = new CodeMemberMethod ();
975                         method.Name = "ReadXmlSerializable";
976                         method.Attributes = MemberAttributes.Family | MemberAttributes.Override;
977                         method.Parameters.Add (Param (TypeRef (typeof (XmlReader)), "reader"));
978                         // TODO: implemnet
979                         method.Statements.Add (Comment ("TODO: implement"));
980                         // Hey, how can I specify the constructor to invoke chained ctor with an empty parameter list!?
981                         method.Statements.Add (Throw (New (typeof (NotImplementedException))));
982                         return method;
983                 }
984                 */
985
986                 private CodeMemberMethod CreateDataSetGetSchema ()
987                 {
988                         CodeMemberMethod m = new CodeMemberMethod ();
989                         m.PrivateImplementationType = TypeRef (typeof (IXmlSerializable));
990                         m.Name = "GetSchema";
991                         m.ReturnType = TypeRef (typeof (XmlSchema));
992                         m.Statements.Add (Return (MethodInvoke ("GetSchemaSerializable")));
993
994                         return m;
995                 }
996
997                 private CodeMemberMethod CreateDataSetGetSchemaSerializable ()
998                 {
999                         CodeMemberMethod m = new CodeMemberMethod ();
1000                         m.Attributes = MemberAttributes.Family | 
1001                                 MemberAttributes.Override;
1002                         m.Name = "GetSchemaSerializable";
1003                         m.ReturnType = TypeRef (typeof (XmlSchema));
1004
1005                         m.Statements.Add (VarDecl (typeof (StringWriter), "sw",
1006                                 New (typeof (StringWriter))));
1007                         m.Statements.Add (Eval (MethodInvoke ("WriteXmlSchema", Local ("sw"))));
1008                         m.Statements.Add (Return (MethodInvoke (
1009                                 TypeRefExp (typeof (XmlSchema)),
1010                                 "Read",
1011                                 New (typeof (XmlTextReader),
1012                                         New (typeof (StringReader),
1013                                                 MethodInvoke (Local ("sw"),
1014                                                         "ToString"))),
1015                                 Const (null))));
1016
1017                         return m;
1018                 }
1019
1020                 private CodeMemberMethod CreateDataSetInitializeClass ()
1021                 {
1022                         CodeMemberMethod m = new CodeMemberMethod ();
1023                         m.Name = "InitializeClass";
1024                         m.Attributes = MemberAttributes.Assembly;
1025
1026                         // dataset properties
1027                         m.Statements.Add (Let (PropRef ("DataSetName"), Const (ds.DataSetName)));
1028                         m.Statements.Add (Let (PropRef ("Prefix"), Const (ds.Prefix)));
1029                         m.Statements.Add (Let (PropRef ("Namespace"), Const (ds.Namespace)));
1030                         m.Statements.Add (Let (PropRef ("Locale"), New (typeof (CultureInfo), Const (ds.Locale.Name))));
1031                         m.Statements.Add (Let (PropRef ("CaseSensitive"), Const (ds.CaseSensitive)));
1032                         m.Statements.Add (Let (PropRef ("EnforceConstraints"), Const (ds.EnforceConstraints)));
1033
1034                         // table
1035                         foreach (DataTable dt in ds.Tables) {
1036                                 string tableFieldName = "__table" + opts.TableMemberName (dt.TableName);
1037                                 string tableTypeName = opts.TableTypeName (dt.TableName);
1038                                 m.Statements.Add (Let (FieldRef (tableFieldName), New (tableTypeName)));
1039                                 m.Statements.Add (Eval (MethodInvoke (PropRef ("Tables"), "Add", FieldRef (tableFieldName))));
1040                         }
1041
1042                         bool fkcExists = false;
1043                         bool ucExists = false;
1044                         // First the UniqueConstraints
1045                         foreach (DataTable dt in ds.Tables) {
1046                                 string tname = "__table" + opts.TableMemberName (dt.TableName);
1047                                 foreach (Constraint c in dt.Constraints) {
1048                                         UniqueConstraint uc = c as UniqueConstraint;
1049                                         if (uc != null) {
1050                                                 if (!ucExists) {
1051                                                         m.Statements.Add (VarDecl (typeof (UniqueConstraint), "uc", null));
1052                                                         ucExists = true;
1053                                                 }
1054                                                 CreateUniqueKeyStatements (m, uc, tname);
1055                                         }
1056                                 }
1057                         }
1058                         // Then the ForeignKeyConstraints
1059                         foreach (DataTable dt in ds.Tables) {
1060                                 string tname = "__table" + opts.TableMemberName (dt.TableName);
1061                                 foreach (Constraint c in dt.Constraints) {
1062                                         ForeignKeyConstraint fkc = c as ForeignKeyConstraint;
1063                                         if (fkc != null) {
1064                                                 if (!fkcExists) {
1065                                                         m.Statements.Add (VarDecl (typeof (ForeignKeyConstraint), "fkc", null));
1066                                                         fkcExists = true;
1067                                                 }
1068                                                 string rtname = "__table" + opts.TableMemberName (fkc.RelatedTable.TableName);
1069                                                 CreateForeignKeyStatements (m, fkc, tname, rtname);
1070                                         }
1071                                 }
1072                         }
1073                         // What if other cases? dunno. Just ignore ;-)
1074                         foreach (DataRelation rel in ds.Relations) {
1075                                 string relName = opts.RelationName (rel.RelationName);
1076                                 ArrayList pcols = new ArrayList ();
1077                                 foreach (DataColumn pcol in rel.ParentColumns)
1078                                         pcols.Add (IndexerRef (PropRef (FieldRef ("__table" + opts.TableMemberName (rel.ParentTable.TableName)), "Columns"), Const (pcol.ColumnName)));
1079
1080                                 ArrayList ccols = new ArrayList ();
1081                                 foreach (DataColumn ccol in rel.ChildColumns)
1082                                         ccols.Add (IndexerRef (PropRef (FieldRef ("__table" + opts.TableMemberName (rel.ChildTable.TableName)), "Columns"), Const (ccol.ColumnName)));
1083
1084                                 // relation field
1085                                 string fieldName = "__relation" + relName;
1086                                 m.Statements.Add (Let (FieldRef (fieldName), New (typeof (DataRelation),
1087                                         Const (rel.RelationName),
1088                                         NewArray (typeof (DataColumn), pcols.ToArray (typeof (CodeExpression)) as CodeExpression []),
1089                                         NewArray (typeof (DataColumn), ccols.ToArray (typeof (CodeExpression)) as CodeExpression []),
1090                                         Const (false)
1091                                         )));
1092                                 m.Statements.Add (Let (PropRef (FieldRef (fieldName), "Nested"), Const (rel.Nested)));
1093                                 m.Statements.Add (MethodInvoke (PropRef ("Relations"), "Add", FieldRef (fieldName)));
1094                         }
1095
1096                         return m;
1097                 }
1098
1099                 private void CreateUniqueKeyStatements (CodeMemberMethod m, UniqueConstraint uc, string tableField)
1100                 {
1101                         ArrayList al = new ArrayList ();
1102                         foreach (DataColumn col in uc.Columns)
1103                                 al.Add (IndexerRef (PropRef (FieldRef (tableField), "Columns"), Const (col.ColumnName)));
1104
1105                         m.Statements.Add (Let (Local ("uc"), New (
1106                                 typeof (UniqueConstraint),
1107                                 Const (uc.ConstraintName),
1108                                 NewArray (
1109                                         typeof (DataColumn),
1110                                         al.ToArray (typeof (CodeExpression)) as CodeExpression []),
1111                                 Const (uc.IsPrimaryKey))));
1112                         m.Statements.Add (MethodInvoke (PropRef (FieldRef (tableField), "Constraints"), "Add", Local ("uc")));
1113                 }
1114
1115                 private void CreateForeignKeyStatements (CodeMemberMethod m,ForeignKeyConstraint fkc, string tableField, string rtableField)
1116                 {
1117                         ArrayList pcols = new ArrayList ();
1118                         foreach (DataColumn col in fkc.RelatedColumns)
1119                                 pcols.Add (IndexerRef (PropRef (FieldRef (rtableField), "Columns"), Const (col.ColumnName)));
1120
1121                         ArrayList ccols = new ArrayList ();
1122                         foreach (DataColumn col in fkc.Columns)
1123                                 ccols.Add (IndexerRef (PropRef (FieldRef (tableField), "Columns"), Const (col.ColumnName)));
1124
1125                         m.Statements.Add (Let (Local ("fkc"), New (
1126                                 typeof (ForeignKeyConstraint),
1127                                 Const (fkc.ConstraintName),
1128                                 NewArray (
1129                                         typeof (DataColumn),
1130                                         pcols.ToArray (typeof (CodeExpression)) as CodeExpression []),
1131                                 NewArray (
1132                                         typeof (DataColumn),
1133                                         ccols.ToArray (typeof (CodeExpression)) as CodeExpression []))));
1134
1135                         m.Statements.Add (Let (
1136                                 PropRef (Local ("fkc"), "AcceptRejectRule"),
1137                                 FieldRef (TypeRefExp (typeof (AcceptRejectRule)), Enum.GetName (typeof (AcceptRejectRule), fkc.AcceptRejectRule))));
1138                         m.Statements.Add (Let (
1139                                 PropRef (Local ("fkc"), "DeleteRule"),
1140                                 FieldRef (TypeRefExp (typeof (Rule)), Enum.GetName (typeof (Rule), fkc.DeleteRule))));
1141                         m.Statements.Add (Let (
1142                                 PropRef (Local ("fkc"), "UpdateRule"),
1143                                 FieldRef (TypeRefExp (typeof (Rule)), Enum.GetName (typeof (Rule), fkc.UpdateRule))));
1144
1145                         m.Statements.Add (MethodInvoke (PropRef (FieldRef (tableField), "Constraints"), "Add", Local ("fkc")));
1146                 }
1147
1148                 private CodeMemberMethod CreateDataSetInitializeFields ()
1149                 {
1150                         CodeMemberMethod m = new CodeMemberMethod ();
1151                         m.Attributes = MemberAttributes.Assembly;
1152                         m.Name = "InitializeFields";
1153
1154                         foreach (DataTable dt in ds.Tables)
1155                                 m.Statements.Add (Eval (MethodInvoke (FieldRef ("__table" + opts.TableMemberName (dt.TableName)), "InitializeFields")));
1156
1157                         foreach (DataRelation rel in ds.Relations)
1158                                 m.Statements.Add (Let (FieldRef ("__relation" + opts.RelationName (rel.RelationName)), IndexerRef (PropRef ("Relations"), Const (rel.RelationName))));
1159
1160                         return m;
1161                 }
1162
1163                 private CodeMemberMethod CreateDataSetSchemaChanged ()
1164                 {
1165                         CodeMemberMethod m = new CodeMemberMethod ();
1166                         m.Name = "SchemaChanged";
1167                         m.Parameters.Add (Param (typeof (object), "sender"));
1168                         m.Parameters.Add (Param (typeof (CollectionChangeEventArgs), "e"));
1169
1170                         m.Statements.Add (
1171                                 new CodeConditionStatement (
1172                                         EqualsValue (
1173                                                 PropRef (ParamRef ("e"), "Action"),
1174                                                 FieldRef (TypeRefExp (typeof (CollectionChangeAction)), "Remove")),
1175                                         new CodeStatement [] { Eval (MethodInvoke ("InitializeFields")) },
1176                                         new CodeStatement [] {}));
1177                         return m;
1178                 }
1179
1180                 private void CreateDataSetTableMembers (CodeTypeDeclaration dsType, DataTable table)
1181                 {
1182                         string tableTypeName = opts.TableTypeName (table.TableName);
1183                         string tableVarName = opts.TableMemberName (table.TableName);
1184
1185                         CodeMemberField privTable = new CodeMemberField ();
1186                         privTable.Type = TypeRef (tableTypeName);
1187                         privTable.Name = "__table" + tableVarName;
1188                         dsType.Members.Add (privTable);
1189
1190                         CodeMemberProperty pubTable = new CodeMemberProperty ();
1191                         pubTable.Type = TypeRef (tableTypeName);
1192                         pubTable.Attributes = MemberAttributes.Public;
1193                         pubTable.Name = tableVarName == table.TableName ? "_"+tableVarName : tableVarName;
1194                         pubTable.HasSet = false;
1195                         // Code: return __table[foo];
1196                         pubTable.GetStatements.Add (Return (FieldRef ("__table" + tableVarName)));
1197
1198                         dsType.Members.Add (pubTable);
1199
1200                 }
1201
1202                 private void CreateDataSetRelationMembers (CodeTypeDeclaration dsType, DataRelation relation)
1203                 {
1204                         string relName = opts.RelationName (relation.RelationName);
1205                         string fieldName = "__relation" + relName;
1206
1207                         CodeMemberField field = new CodeMemberField ();
1208                         field.Type = TypeRef (typeof (DataRelation));
1209                         field.Name = fieldName;
1210                         dsType.Members.Add (field);
1211
1212                         // This is not supported in MS.NET
1213                         CodeMemberProperty prop = new CodeMemberProperty ();
1214                         prop.Type = TypeRef (typeof (DataRelation));
1215                         prop.Attributes = MemberAttributes.Public;
1216                         prop.Name = relName;
1217                         prop.HasSet = false;
1218                         // Code: return __relation[foo_bar];
1219                         prop.GetStatements.Add (Return (FieldRef (fieldName)));
1220                         dsType.Members.Add (prop);
1221                 }
1222
1223 #endregion
1224
1225
1226
1227 #region DataTable class
1228
1229                 private CodeTypeDeclaration GenerateDataTableType (DataTable dt)
1230                 {
1231                         CodeTypeDeclaration t = new CodeTypeDeclaration ();
1232                         t.Name = opts.TableTypeName (dt.TableName);
1233                         t.BaseTypes.Add (TypeRef (typeof (DataTable)));
1234                         t.BaseTypes.Add (TypeRef (typeof (IEnumerable)));
1235
1236                         t.Members.Add (CreateTableCtor1 (dt));
1237                         t.Members.Add (CreateTableCtor2 (dt));
1238
1239                         t.Members.Add (CreateTableCount (dt));
1240                         t.Members.Add (CreateTableIndexer (dt));
1241
1242                         t.Members.Add (CreateTableInitializeClass (dt));
1243                         t.Members.Add (CreateTableInitializeFields (dt));
1244
1245                         t.Members.Add (CreateTableGetEnumerator (dt));
1246                         t.Members.Add (CreateTableClone (dt));
1247                         t.Members.Add (CreateTableCreateInstance (dt));
1248
1249                         t.Members.Add (CreateTableAddRow1 (dt));
1250                         t.Members.Add (CreateTableAddRow2 (dt));
1251                         t.Members.Add (CreateTableNewRow (dt));
1252                         t.Members.Add (CreateTableNewRowFromBuilder (dt));
1253                         t.Members.Add (CreateTableRemoveRow (dt));
1254                         t.Members.Add (CreateTableGetRowType (dt));
1255
1256                         t.Members.Add (CreateTableEventStarter (dt, "Changing"));
1257                         t.Members.Add (CreateTableEventStarter (dt, "Changed"));
1258                         t.Members.Add (CreateTableEventStarter (dt, "Deleting"));
1259                         t.Members.Add (CreateTableEventStarter (dt, "Deleted"));
1260
1261                         // events
1262                         t.Members.Add (CreateTableEvent (dt, "RowChanging"));
1263                         t.Members.Add (CreateTableEvent (dt, "RowChanged"));
1264                         t.Members.Add (CreateTableEvent (dt, "RowDeleting"));
1265                         t.Members.Add (CreateTableEvent (dt, "RowDeleted"));
1266
1267                         // column members
1268                         foreach (DataColumn col in dt.Columns) {
1269                                 t.Members.Add (CreateTableColumnField (dt, col));
1270                                 t.Members.Add (CreateTableColumnProperty (dt, col));
1271                         }
1272
1273                         return t;
1274                 }
1275
1276                 // Code:
1277                 //  internal [foo]DataTable () : base ("[foo]")
1278                 //  {
1279                 //    InitializeClass ();
1280                 //  }
1281                 private CodeConstructor CreateTableCtor1 (DataTable dt)
1282                 {
1283                         CodeConstructor c = new CodeConstructor ();
1284                         c.Attributes = MemberAttributes.Assembly;
1285                         c.BaseConstructorArgs.Add (Const (dt.TableName));
1286                         c.Statements.Add (Eval (MethodInvoke ("InitializeClass")));
1287                         c.Statements.Add (Eval (MethodInvoke ("InitializeFields")));
1288                         return c;
1289                 }
1290
1291                 // Code:
1292                 //  internal [foo]DataTable (DataTable table) : base (table.TableName)
1293                 //  {
1294                 //    // TODO: implement
1295                 //    throw new NotImplementedException ();
1296                 //  }
1297                 private CodeConstructor CreateTableCtor2 (DataTable dt)
1298                 {
1299                         CodeConstructor c = new CodeConstructor ();
1300                         c.Attributes = MemberAttributes.Assembly;
1301                         c.Parameters.Add (Param (typeof (DataTable), GetRowTableFieldName (dt)));
1302                         c.BaseConstructorArgs.Add (PropRef (ParamRef (GetRowTableFieldName (dt)), "TableName"));
1303                         // TODO: implement
1304                         c.Statements.Add (Comment ("TODO: implement"));
1305                         c.Statements.Add (Throw (New (typeof (NotImplementedException))));
1306                         return c;
1307                 }
1308
1309                 private CodeMemberMethod CreateTableInitializeClass (DataTable dt)
1310                 {
1311                         CodeMemberMethod m = new CodeMemberMethod ();
1312                         m.Name = "InitializeClass";
1313                         foreach (DataColumn col in dt.Columns) {
1314                                 m.Statements.Add (Eval (MethodInvoke (
1315                                         PropRef ("Columns"),
1316                                         "Add",
1317                                         New (typeof (DataColumn),
1318                                                 Const (col.ColumnName),
1319                                                 new CodeTypeOfExpression (col.DataType)
1320                                                 ))));
1321                         }
1322                         return m;
1323                 }
1324
1325                 private CodeMemberMethod CreateTableInitializeFields (DataTable dt)
1326                 {
1327                         CodeMemberMethod m = new CodeMemberMethod ();
1328                         m.Name = "InitializeFields";
1329                         m.Attributes = MemberAttributes.Assembly;
1330
1331                         string colRef;
1332                         foreach (DataColumn col in dt.Columns) {
1333                                 colRef = String.Format("__column{0}", opts.TableColName (col.ColumnName));
1334
1335                                 m.Statements.Add (Let (FieldRef (colRef), IndexerRef (PropRef ("Columns"), Const (col.ColumnName))));
1336                                 if (!col.AllowDBNull)
1337                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "AllowDBNull"), Const (col.AllowDBNull)));
1338                                 if (col.DefaultValue != null && col.DefaultValue.GetType() != typeof(System.DBNull))
1339                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "DefaultValue"), Const (col.DefaultValue)));
1340                                 if (col.AutoIncrement)
1341                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "AutoIncrement"), Const (col.AutoIncrement)));
1342                                 if (col.AutoIncrementSeed != 0)
1343                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "AutoIncrementSeed"), Const (col.AutoIncrementSeed)));
1344                                 if (col.AutoIncrementStep != 1)
1345                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "AutoIncrementStep"), Const (col.AutoIncrementStep)));
1346                                 if (col.ReadOnly)
1347                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "ReadOnly"), Const (col.ReadOnly)));
1348                         }
1349                         return m;
1350                 }
1351
1352                 private CodeMemberMethod CreateTableClone (DataTable dt)
1353                 {
1354                         CodeMemberMethod m = new CodeMemberMethod ();
1355                         m.Name = "Clone";
1356                         m.Attributes = MemberAttributes.Public | MemberAttributes.Override;
1357                         m.ReturnType = TypeRef (typeof (DataTable));
1358                         string typeName = opts.TableTypeName (dt.TableName);
1359                         m.Statements.Add (
1360                                 VarDecl (typeName, "t", Cast (typeName, MethodInvoke (Base (), "Clone"))));
1361                         m.Statements.Add (Eval (MethodInvoke (Local ("t"), "InitializeFields")));
1362                         m.Statements.Add (Return (Local ("t")));
1363                         return m;
1364                 }
1365
1366                 private CodeMemberMethod CreateTableGetEnumerator (DataTable dt)
1367                 {
1368                         CodeMemberMethod m = new CodeMemberMethod ();
1369                         m.Name = "GetEnumerator";
1370                         m.Attributes = MemberAttributes.Public;
1371                         m.ReturnType = TypeRef (typeof (IEnumerator));
1372                         m.Statements.Add (Return (MethodInvoke (PropRef ("Rows"), "GetEnumerator")));
1373                         m.ImplementationTypes.Add (TypeRef (typeof (IEnumerable)));
1374                         return m;
1375                 }
1376
1377                 private CodeMemberMethod CreateTableCreateInstance (DataTable dt)
1378                 {
1379                         CodeMemberMethod m = new CodeMemberMethod ();
1380                         m.Name = "CreateInstance";
1381                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1382                         m.ReturnType = TypeRef (typeof (DataTable));
1383                         m.Statements.Add (Return (New (opts.TableTypeName (dt.TableName))));
1384                         return m;
1385                 }
1386
1387                 private CodeMemberField CreateTableColumnField (DataTable dt, DataColumn col)
1388                 {
1389                         CodeMemberField f = new CodeMemberField ();
1390                         f.Name = "__column" + opts.ColumnName (col.ColumnName);
1391                         f.Type = TypeRef (typeof (DataColumn));
1392                         return f;
1393                 }
1394
1395                 private CodeMemberProperty CreateTableColumnProperty (DataTable dt, DataColumn col)
1396                 {
1397                         string name = opts.ColumnName (col.ColumnName);
1398                         CodeMemberProperty p = new CodeMemberProperty ();
1399                         p.Name = name + "Column";
1400                         p.Attributes = MemberAttributes.Assembly;
1401                         p.Type = TypeRef (typeof (DataColumn));
1402                         p.HasSet = false;
1403                         p.GetStatements.Add (Return (FieldRef ("__column" + name)));
1404                         return p;
1405                 }
1406
1407                 private CodeMemberProperty CreateTableCount (DataTable dt)
1408                 {
1409                         CodeMemberProperty p = new CodeMemberProperty ();
1410                         p.Name = "Count";
1411                         p.Attributes = MemberAttributes.Public;
1412                         p.Type = TypeRef (typeof (int));
1413                         p.HasSet = false;
1414                         p.GetStatements.Add (Return (PropRef (PropRef ("Rows"), "Count")));
1415                         return p;
1416                 }
1417
1418                 private CodeMemberProperty CreateTableIndexer (DataTable dt)
1419                 {
1420                         string rowName = opts.RowName (dt.TableName);
1421                         CodeMemberProperty ix = new CodeMemberProperty ();
1422                         ix.Name = "Item"; // indexer
1423                         ix.Attributes = MemberAttributes.Public;
1424                         ix.Type = TypeRef (rowName);
1425                         ix.Parameters.Add (Param (typeof (int), "i"));
1426                         ix.HasSet = false;
1427                         ix.GetStatements.Add (Return (Cast (rowName, IndexerRef (PropRef ("Rows"), ParamRef ("i")))));
1428                         return ix;
1429                 }
1430
1431                 private CodeMemberMethod CreateTableAddRow1 (DataTable dt)
1432                 {
1433                         CodeMemberMethod m = new CodeMemberMethod ();
1434                         string rowType = opts.RowName (dt.TableName);
1435                         m.Name = "Add" + rowType;
1436                         m.Attributes = MemberAttributes.Public;
1437                         m.Parameters.Add (Param (TypeRef (rowType), "row"));
1438                         m.Statements.Add (Eval (MethodInvoke (PropRef ("Rows"), "Add", ParamRef ("row"))));
1439                         return m;
1440                 }
1441
1442                 private CodeMemberMethod CreateTableAddRow2 (DataTable dt)
1443                 {
1444                         CodeMemberMethod m = new CodeMemberMethod ();
1445                         string rowType = opts.RowName (dt.TableName);
1446                         m.Name = "Add" + rowType;
1447                         m.ReturnType = TypeRef (rowType);
1448                         m.Attributes = MemberAttributes.Public;
1449
1450                         m.Statements.Add (VarDecl (rowType, "row", MethodInvoke ("New" + rowType)));
1451
1452                         foreach (DataColumn col in dt.Columns) {
1453                                 if (col.ColumnMapping == MappingType.Hidden) {
1454                                         foreach (DataRelation r in dt.DataSet.Relations) {
1455                                                 if (r.ChildTable == dt) {
1456                                                         // parameter
1457                                                         string paramType = opts.RowName (r.ParentTable.TableName);
1458                                                         string paramName = paramType;
1459                                                         m.Parameters.Add (Param (paramType, paramName));
1460                                                         // CODE: SetParentRow (fooRow, DataSet.Relations ["foo_bar"]);
1461                                                         m.Statements.Add (Eval (MethodInvoke (Local ("row"), "SetParentRow", ParamRef (paramName), IndexerRef (PropRef (PropRef ("DataSet"), "Relations"), Const (r.RelationName)))));
1462                                                         break;
1463                                                 }
1464                                         }
1465                                 }
1466                                 else {
1467                                         // parameter
1468                                         string paramName = opts.ColumnName (col.ColumnName);
1469                                         m.Parameters.Add (Param (col.DataType, paramName));
1470                                         // row ["foo"] = foo;
1471                                         m.Statements.Add (Let (IndexerRef (Local ("row"), Const (paramName)), ParamRef (paramName)));
1472                                 }
1473                         }
1474
1475                         // Rows.Add (row);
1476                         m.Statements.Add (MethodInvoke (PropRef ("Rows"), "Add", Local ("row")));
1477                         m.Statements.Add (Return (Local ("row")));
1478
1479                         return m;
1480                 }
1481
1482                 private CodeMemberMethod CreateTableNewRow (DataTable dt)
1483                 {
1484                         CodeMemberMethod m = new CodeMemberMethod ();
1485                         string rowType = opts.RowName (dt.TableName);
1486                         m.Name = "New" + rowType;
1487                         m.ReturnType = TypeRef (rowType);
1488                         m.Attributes = MemberAttributes.Public;
1489                         m.Statements.Add (Return (Cast (rowType, MethodInvoke ("NewRow"))));
1490                         return m;
1491                 }
1492
1493                 private CodeMemberMethod CreateTableNewRowFromBuilder (DataTable dt)
1494                 {
1495                         CodeMemberMethod m = new CodeMemberMethod ();
1496                         m.Name = "NewRowFromBuilder";
1497                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1498                         m.ReturnType = TypeRef (typeof (DataRow));
1499                         m.Parameters.Add (Param (typeof (DataRowBuilder), "builder"));
1500                         m.Statements.Add (Return (New (opts.RowName (dt.TableName), ParamRef ("builder"))));
1501                         return m;
1502                 }
1503
1504                 private CodeMemberMethod CreateTableRemoveRow (DataTable dt)
1505                 {
1506                         CodeMemberMethod m = new CodeMemberMethod ();
1507                         string rowType = opts.RowName (dt.TableName);
1508                         m.Name = "Remove" + rowType;
1509                         m.Attributes = MemberAttributes.Public;
1510                         m.Parameters.Add (Param (TypeRef (rowType), "row"));
1511                         m.Statements.Add (Eval (MethodInvoke (PropRef ("Rows"), "Remove", ParamRef ("row"))));
1512                         return m;
1513                 }
1514
1515                 private CodeMemberMethod CreateTableGetRowType (DataTable dt)
1516                 {
1517                         CodeMemberMethod m = new CodeMemberMethod ();
1518                         m.Name = "GetRowType";
1519                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1520                         m.ReturnType = TypeRef (typeof (Type));
1521                         m.Statements.Add (Return (new CodeTypeOfExpression (opts.RowName (dt.TableName))));
1522                         return m;
1523                 }
1524
1525                 private CodeMemberMethod CreateTableEventStarter (DataTable dt, string type)
1526                 {
1527                         CodeMemberMethod m = new CodeMemberMethod ();
1528                         m.Name = "OnRow" + type;
1529                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1530                         m.Parameters.Add (Param (typeof (DataRowChangeEventArgs), "e"));
1531
1532                         m.Statements.Add (Eval (MethodInvoke (
1533                                         Base (),
1534                                         m.Name,
1535                                         ParamRef ("e"))));
1536                         string eventName = opts.TableMemberName (dt.TableName) + "Row" + type;
1537                         CodeStatement trueStmt = Eval (
1538                                 new CodeDelegateInvokeExpression(
1539                                         new CodeEventReferenceExpression (This (), eventName),
1540                                         This (), 
1541                                         New (
1542                                                 opts.EventArgsName (dt.TableName),
1543                                                 Cast (opts.RowName (dt.TableName), PropRef (ParamRef ("e"), "Row")),
1544                                                 PropRef (ParamRef ("e"), "Action"))));
1545
1546                         m.Statements.Add (
1547                                 new CodeConditionStatement (
1548                                         Inequals (EventRef (eventName), Const (null)),
1549                                         new CodeStatement [] {trueStmt},
1550                                         new CodeStatement [] {}));
1551
1552                         return m;
1553                 }
1554
1555                 private CodeMemberEvent CreateTableEvent (DataTable dt, string nameSuffix)
1556                 {
1557                         CodeMemberEvent cme = new CodeMemberEvent ();
1558                         cme.Attributes = MemberAttributes.Public;
1559                         cme.Name = opts.TableMemberName (dt.TableName) + nameSuffix;
1560                         cme.Type = TypeRef (opts.TableDelegateName (dt.TableName));
1561                         return cme;
1562                 }
1563
1564 #endregion
1565
1566
1567
1568 #region Row class
1569
1570                 public CodeTypeDeclaration GenerateDataRowType (DataTable dt)
1571                 {
1572                         CodeTypeDeclaration t = new CodeTypeDeclaration ();
1573                         t.Name = opts.RowName (dt.TableName);
1574                         t.BaseTypes.Add (TypeRef (typeof (DataRow)));
1575
1576                         t.Members.Add (CreateRowCtor (dt));
1577
1578                         t.Members.Add (CreateRowTableField (dt));
1579
1580                         foreach (DataColumn col in dt.Columns) {
1581                                 if (col.ColumnMapping != MappingType.Hidden) {
1582                                         t.Members.Add (CreateRowColumnProperty (dt, col));
1583                                         t.Members.Add (CreateRowColumnIsNull (dt, col));
1584                                         t.Members.Add (CreateRowColumnSetNull (dt, col));
1585                                 }
1586                         }
1587
1588                         foreach (DataRelation rel in dt.ParentRelations)
1589                                 t.Members.Add (CreateRowParentRowProperty (dt, rel));
1590                         foreach (DataRelation rel in dt.ChildRelations)
1591                                 t.Members.Add (CreateRowGetChildRows (dt, rel));
1592
1593                         return t;
1594                 }
1595
1596                 private CodeConstructor CreateRowCtor (DataTable dt)
1597                 {
1598                         CodeConstructor c = new CodeConstructor ();
1599                         c.Attributes = MemberAttributes.Assembly;
1600                         c.Parameters.Add (Param (typeof (DataRowBuilder), "builder"));
1601                         c.BaseConstructorArgs.Add (ParamRef ("builder"));
1602                         c.Statements.Add (Let (FieldRef (GetRowTableFieldName (dt)), Cast (
1603                                 opts.TableTypeName (dt.TableName),
1604                                 PropRef ("Table"))));
1605                         return c;
1606                 }
1607                 
1608                 private string GetRowTableFieldName (DataTable dt)
1609                 {
1610                         return "table" + dt.TableName;
1611                 }
1612                 private CodeMemberField CreateRowTableField (DataTable dt)
1613                 {
1614                         CodeMemberField f = new CodeMemberField ();
1615                         f.Name = GetRowTableFieldName (dt);
1616                         f.Type = TypeRef (opts.TableTypeName (dt.TableName));
1617                         return f;
1618                 }
1619
1620                 private CodeMemberProperty CreateRowColumnProperty (DataTable dt, DataColumn col)
1621                 {
1622                         CodeMemberProperty p = new CodeMemberProperty ();
1623                         p.Name = opts.ColumnName (col.ColumnName);
1624                         p.Type = TypeRef (col.DataType);
1625                         p.Attributes = MemberAttributes.Public;
1626
1627                         // This part should be better than MS code output.
1628                         // Code:
1629                         //  object ret = this [col];
1630                         //  if (ret == DBNull.Value)
1631                         //    throw new StrongTypingException ()
1632                         //  else
1633                         //    return (type) ret;
1634                         p.GetStatements.Add (VarDecl (typeof (object), "ret",
1635                                 IndexerRef (PropRef 
1636                                         (PropRef (GetRowTableFieldName (dt)), 
1637                                         opts.TableColName (col.ColumnName) + "Column"))));
1638                         p.GetStatements.Add (new CodeConditionStatement (
1639                                 Equals (
1640                                         Local ("ret"),
1641                                         PropRef (TypeRefExp (typeof (DBNull)), "Value")),
1642                                 new CodeStatement [] {
1643                                         Throw (New (typeof (StrongTypingException), Const ("Cannot get strong typed value since it is DB null."), Const (null))) },
1644                                 new CodeStatement [] {
1645                                         Return (Cast (col.DataType, Local ("ret"))) }));
1646
1647                         p.SetStatements.Add (Let (IndexerRef (PropRef (PropRef (GetRowTableFieldName (dt)), opts.TableColName (col.ColumnName) + "Column")), new CodePropertySetValueReferenceExpression ()));
1648
1649                         return p;
1650                 }
1651
1652                 private CodeMemberMethod CreateRowColumnIsNull (DataTable dt, DataColumn col)
1653                 {
1654                         CodeMemberMethod m = new CodeMemberMethod ();
1655                         m.Name = "Is" + opts.ColumnName (col.ColumnName) + "Null";
1656                         m.Attributes = MemberAttributes.Public;
1657                         m.ReturnType = TypeRef (typeof (bool));
1658                         m.Statements.Add (Return (MethodInvoke (
1659                                 "IsNull",
1660                                 // table[foo].[bar]Column
1661                                 PropRef (
1662                                         PropRef (GetRowTableFieldName (dt)), 
1663                                         opts.TableColName (col.ColumnName) + "Column"))));
1664                         return m;
1665                 }
1666
1667                 private CodeMemberMethod CreateRowColumnSetNull (DataTable dt, DataColumn col)
1668                 {
1669                         CodeMemberMethod m = new CodeMemberMethod ();
1670                         m.Name = "Set" + opts.ColumnName (col.ColumnName) + "Null";
1671                         m.Attributes = MemberAttributes.Public;
1672                         m.Statements.Add (Let (IndexerRef (
1673                                 PropRef (
1674                                         PropRef (GetRowTableFieldName (dt)), 
1675                                         opts.TableColName (col.ColumnName) + "Column")),
1676                                 PropRef (TypeRefExp (typeof (DBNull)), "Value")));
1677
1678                         return m;
1679                 }
1680
1681                 private CodeMemberProperty CreateRowParentRowProperty (DataTable dt, DataRelation rel)
1682                 {
1683                         CodeMemberProperty p = new CodeMemberProperty ();
1684                         p.Name = opts.TableMemberName (rel.ParentTable.TableName) + "Row" +
1685                                 (rel.ParentTable.TableName == rel.ChildTable.TableName ? "Parent" : String.Empty);
1686                         p.Attributes = MemberAttributes.Public;
1687                         p.Type = TypeRef (opts.RowName (rel.ParentTable.TableName));
1688                         p.GetStatements.Add (Return (Cast (p.Type, MethodInvoke (
1689                                 "GetParentRow",
1690                                 IndexerRef (
1691                                         PropRef (
1692                                                 PropRef (
1693                                                         PropRef ("Table"),
1694                                                         "DataSet"),
1695                                                 "Relations"),
1696                                         Const (rel.RelationName))))));
1697                         p.SetStatements.Add (Eval (MethodInvoke (
1698                                 "SetParentRow",
1699                                 new CodePropertySetValueReferenceExpression (),
1700                                 IndexerRef (
1701                                         PropRef (
1702                                                 PropRef (
1703                                                         PropRef ("Table"),
1704                                                         "DataSet"),
1705                                                 "Relations"),
1706                                         Const (rel.RelationName)))));
1707
1708                         return p;
1709                 }
1710
1711                 private CodeMemberMethod CreateRowGetChildRows (DataTable dt, DataRelation rel)
1712                 {
1713                         CodeMemberMethod m = new CodeMemberMethod ();
1714                         m.Name = "Get" + opts.TableMemberName (rel.ChildTable.TableName) + "Rows";
1715                         m.Attributes = MemberAttributes.Public;
1716                         m.ReturnType = new CodeTypeReference (opts.RowName (rel.ChildTable.TableName), 1);
1717                         m.Statements.Add (Return (Cast (m.ReturnType, MethodInvoke (
1718                                 "GetChildRows",
1719                                 IndexerRef (
1720                                         PropRef (
1721                                                 PropRef (
1722                                                         PropRef ("Table"),
1723                                                         "DataSet"),
1724                                                 "Relations"),
1725                                         Const (rel.RelationName))))));
1726                         return m;
1727                 }
1728
1729 #endregion
1730
1731
1732 #region Event class
1733
1734                 // Code:
1735                 //  public class [foo]ChangeEventArgs : EventArgs
1736                 //  {
1737                 //    private [foo]Row eventRow;
1738                 //    private DataRowAction eventAction;
1739                 //    (.ctor())
1740                 //    (Row)
1741                 //    (Action)
1742                 //  }
1743                 private CodeTypeDeclaration GenerateEventType (DataTable dt)
1744                 {
1745                         CodeTypeDeclaration t = new CodeTypeDeclaration ();
1746                         t.Name = opts.EventArgsName (dt.TableName);
1747                         t.BaseTypes.Add (TypeRef (typeof (EventArgs)));
1748                         t.Attributes = MemberAttributes.Public;
1749
1750                         t.Members.Add (
1751                                 new CodeMemberField (
1752                                         TypeRef (opts.RowName (dt.TableName)),
1753                                         "eventRow"));
1754                         t.Members.Add (
1755                                 new CodeMemberField (
1756                                         TypeRef (typeof (DataRowAction)), "eventAction"));
1757                         t.Members.Add (CreateEventCtor (dt));
1758
1759                         t.Members.Add (CreateEventRow (dt));
1760
1761                         t.Members.Add (CreateEventAction (dt));
1762
1763                         return t;
1764                 }
1765
1766                 // Code:
1767                 //  public [foo]RowChangeEventArgs ([foo]Row r, DataRowAction a)
1768                 //  {
1769                 //    eventRow = r;
1770                 //    eventAction = a;
1771                 //  }
1772                 private CodeConstructor CreateEventCtor (DataTable dt)
1773                 {
1774                         CodeConstructor c = new CodeConstructor ();
1775                         c.Attributes = MemberAttributes.Public;
1776                         c.Parameters.Add (Param (TypeRef (opts.RowName (dt.TableName)), "r"));
1777                         c.Parameters.Add (Param (TypeRef (typeof (DataRowAction)), "a"));
1778                         c.Statements.Add (Let (FieldRef ("eventRow"), ParamRef ("r")));
1779                         c.Statements.Add (Let (FieldRef ("eventAction"), ParamRef ("a")));
1780
1781                         return c;
1782                 }
1783
1784                 // Code:
1785                 //  public [foo]Row Row {
1786                 //   get { return eventRow; }
1787                 // }
1788                 private CodeMemberProperty CreateEventRow (DataTable dt)
1789                 {
1790                         CodeMemberProperty p = new CodeMemberProperty ();
1791                         p.Name = "Row";
1792                         p.Attributes = MemberAttributes.Public | MemberAttributes.Final;
1793                         p.Type = TypeRef (opts.RowName (dt.TableName));
1794                         p.HasSet = false;
1795                         p.GetStatements.Add (Return (FieldRef ("eventRow")));
1796                         return p;
1797                 }
1798
1799                 // Code:
1800                 //  public DataRowAction Action {
1801                 //   get { return eventAction; }
1802                 // }
1803                 private CodeMemberProperty CreateEventAction (DataTable dt)
1804                 {
1805                         CodeMemberProperty p = new CodeMemberProperty ();
1806                         p.Name = "Action";
1807                         p.Attributes = MemberAttributes.Public | MemberAttributes.Final;
1808                         p.Type = TypeRef (typeof (DataRowAction));
1809                         p.HasSet = false;
1810                         p.GetStatements.Add (Return (FieldRef ("eventAction")));
1811                         return p;
1812                 }
1813
1814 #endregion
1815
1816 #if NET_2_0
1817 #region Table Adapter class
1818                 
1819                 private CodeTypeDeclaration GenerateTableAdapterType (TableAdapterSchemaInfo taInfo)
1820                 {
1821                         string qualifiedBaseClassName;
1822                         Type type = null;
1823                         int fIndex = -1;
1824                         
1825                         CodeTypeDeclaration t = new CodeTypeDeclaration ();
1826                         t.Name = opts.TableAdapterName (taInfo.Name);
1827                         t.BaseTypes.Add (TypeRef (taInfo.BaseClass));
1828                 
1829                         t.Members.Add (CreateTableAdapterDefaultCtor ());
1830
1831                         // table adapter fields/properties
1832                         CreateDBAdapterFieldAndProperty (t, taInfo.Adapter);
1833                         CreateDBConnectionFieldAndProperty (t, taInfo.Connection);
1834                         
1835                         DbCommand cmd = null;
1836                         if (taInfo.Commands.Count > 0)
1837                                 cmd = ((DbCommandInfo)taInfo.Commands[0]).Command;
1838                         else
1839                                 cmd = taInfo.Provider.CreateCommand ();
1840                         CreateDBCommandCollectionFieldAndProperty (t, cmd);
1841                         CreateAdapterClearBeforeFillFieldAndProperty (t);
1842
1843                         CreateAdapterInitializeMethod (t, taInfo);
1844                         CreateConnectionInitializeMethod (t, taInfo);
1845                         CreateCommandCollectionInitializeMethod (t, taInfo);
1846
1847                         CreateDbSourceMethods (t, taInfo);
1848                         if (taInfo.ShortCommands)
1849                                 CreateShortCommandMethods (t, taInfo);
1850                         
1851                         return t;
1852                 }
1853                 
1854                 private CodeConstructor CreateTableAdapterDefaultCtor ()
1855                 {
1856                         CodeConstructor ctor = new CodeConstructor ();
1857                         ctor.Attributes = MemberAttributes.Public;
1858                         ctor.Statements.Add (Let (PropRef ("ClearBeforeFill"), Const (true)));
1859                         
1860                         return ctor;
1861                 }       
1862
1863                 private void CreateDBAdapterFieldAndProperty (CodeTypeDeclaration t, DbDataAdapter adapter)
1864                 {
1865                         CodeExpression expr;
1866                         CodeStatement setStmt;
1867                         CodeStatement stmt;
1868                         CodeMemberField f = new CodeMemberField ();
1869                         f.Name = "_adapter";
1870                         f.Type = TypeRef (adapter.GetType ());
1871                         t.Members.Add (f);
1872                         
1873                         CodeMemberProperty p = new CodeMemberProperty ();
1874                         p.Name = "Adapter";
1875                         p.Attributes = MemberAttributes.Private;
1876                         p.Type = f.Type;
1877                         p.HasSet = false;
1878
1879                         expr = FieldRef ("_adapter");
1880                         setStmt = Eval (MethodInvoke ("InitAdapter"));
1881                         stmt = new CodeConditionStatement (Equals (expr, Const (null)),
1882                                                            new CodeStatement [] {setStmt},
1883                                                            new CodeStatement [] {});
1884                         p.GetStatements.Add (stmt);
1885                         p.GetStatements.Add (Return (expr));
1886                         t.Members.Add (p);
1887                 }
1888                 
1889                 private void CreateDBConnectionFieldAndProperty (CodeTypeDeclaration t, DbConnection conn)
1890                 {
1891                         CodeExpression expr;
1892                         CodeStatement setStmt;
1893                         CodeStatement stmt;
1894                         CodeMemberField f = new CodeMemberField ();
1895                         f.Name = "_connection";
1896                         f.Type = TypeRef (conn.GetType ());
1897                         t.Members.Add (f);
1898
1899                         CodeMemberProperty p = new CodeMemberProperty ();
1900                         p.Name = "Connection";
1901                         p.Attributes = MemberAttributes.Assembly;
1902                         p.Type = f.Type;
1903
1904                         expr = FieldRef ("_connection");
1905                         setStmt = Eval (MethodInvoke ("InitConnection"));
1906                         stmt = new CodeConditionStatement (Equals (expr, Const (null)),
1907                                                            new CodeStatement [] {setStmt},
1908                                                            new CodeStatement [] {});
1909                         p.GetStatements.Add (stmt);
1910                         p.GetStatements.Add (Return (expr));
1911                         p.SetStatements.Add (Let (expr, new CodePropertySetValueReferenceExpression()));
1912
1913                         // update connection in Insert/Delete/Update commands of adapter
1914                                                 
1915                         // insert command
1916                         string cmdStr = "InsertCommand";
1917                         string connStr = "Connection";
1918                         setStmt = null;
1919                         stmt = null;
1920                         expr = null;
1921
1922                         expr = PropRef (PropRef ("Adapter"), cmdStr);
1923                         setStmt = Let (PropRef (expr, connStr), new CodePropertySetValueReferenceExpression());
1924                         stmt = new CodeConditionStatement (Inequals (expr, Const (null)),
1925                                                            new CodeStatement [] {setStmt},
1926                                                            new CodeStatement [] {});                    
1927                         p.SetStatements.Add (stmt);
1928
1929                         // delete command
1930                         setStmt = null;
1931                         stmt = null;
1932                         expr = null;
1933                         
1934                         cmdStr = "DeleteCommand";
1935                         expr = PropRef (PropRef ("Adapter"), cmdStr);
1936                         setStmt = Let (PropRef (expr, connStr), new CodePropertySetValueReferenceExpression());
1937                         stmt = new CodeConditionStatement (Inequals (expr, Const (null)),
1938                                                            new CodeStatement [] {setStmt}, new CodeStatement [] {});
1939                         p.SetStatements.Add (stmt);
1940
1941                         // update command
1942                         setStmt = null;
1943                         stmt = null;
1944
1945                         cmdStr = "UpdateCommand";
1946                         expr = PropRef (PropRef ("Adapter"), cmdStr);                   
1947                         setStmt = Let (PropRef (expr, connStr), new CodePropertySetValueReferenceExpression());
1948                         stmt = new CodeConditionStatement (Inequals (expr, Const (null)),
1949                                                            new CodeStatement [] {setStmt}, new CodeStatement [] {});
1950                         p.SetStatements.Add (stmt);
1951
1952                         // iterate through command collection and update it
1953                         setStmt = null;
1954                         expr = null;
1955                         stmt = null;
1956                         setStmt = VarDecl (typeof (int), "i", Const (0));
1957                         expr = LessThan (Local ("i"), PropRef (PropRef ("CommandCollection"), "Length"));
1958                         stmt = Let (Local ("i"), Compute (Local ("i"), Const (1), CodeBinaryOperatorType.Add));
1959                         
1960                         // statements to execute in the loop
1961                         CodeExpression expr1 = IndexerRef (PropRef ("CommandCollection"), Local ("i"));
1962                         CodeStatement setStmt1 = Let (PropRef (expr1, "Connection"), new CodePropertySetValueReferenceExpression());
1963                         CodeStatement stmt1 = new CodeConditionStatement (Inequals (expr1, Const (null)),
1964                                                            new CodeStatement [] {setStmt1}, new CodeStatement [] {});
1965                         CodeIterationStatement forLoop = new CodeIterationStatement (setStmt, expr, stmt,
1966                                                                                      new CodeStatement[] {stmt1});
1967                         p.SetStatements.Add (forLoop);                                          
1968                         t.Members.Add (p);
1969                 }
1970
1971                 private void CreateDBCommandCollectionFieldAndProperty (CodeTypeDeclaration t, DbCommand cmd)
1972                 {
1973                         CodeExpression expr;
1974                         CodeStatement setStmt;
1975                         CodeStatement stmt;
1976                         CodeMemberField f = new CodeMemberField ();
1977                         f.Name = "_commandCollection";
1978                         f.Type = TypeRefArray (cmd.GetType (), 1);
1979                         t.Members.Add (f);
1980                         
1981                         CodeMemberProperty p = new CodeMemberProperty ();
1982                         p.Name = "CommandCollection";
1983                         p.Attributes = MemberAttributes.Family;
1984                         p.Type = f.Type;
1985                         p.HasSet = false;
1986
1987                         expr = FieldRef ("_commandCollection");
1988                         setStmt = Eval (MethodInvoke ("InitCommandCollection"));
1989                         stmt = new CodeConditionStatement (Equals (expr, Const (null)),
1990                                                            new CodeStatement [] {setStmt},
1991                                                            new CodeStatement [] {});
1992                         p.GetStatements.Add (stmt);
1993                         p.GetStatements.Add (Return (expr));
1994                         t.Members.Add (p);
1995                 }
1996
1997                 private void CreateAdapterClearBeforeFillFieldAndProperty (CodeTypeDeclaration t)
1998                 {
1999                         CodeMemberField f = new CodeMemberField ();
2000                         f.Name = "_clearBeforeFill";
2001                         f.Type = TypeRef (typeof (bool));
2002                         t.Members.Add (f);
2003                         
2004                         CodeMemberProperty p = new CodeMemberProperty ();
2005                         p.Name = "ClearBeforeFill";
2006                         p.Attributes = MemberAttributes.Public;
2007                         p.Type = f.Type;
2008                         p.SetStatements.Add (Let (FieldRef ("_clearBeforeFill"), 
2009                                                   new CodePropertySetValueReferenceExpression()));
2010                         p.GetStatements.Add (Return (FieldRef ("_clearBeforeFill")));
2011                         t.Members.Add (p);
2012                 }
2013
2014                 private void CreateAdapterInitializeMethod (CodeTypeDeclaration t, TableAdapterSchemaInfo taInfo)
2015                 {
2016                         CodeMemberMethod m = new CodeMemberMethod ();
2017                         m.Name = "InitAdapter";
2018                         m.Attributes = MemberAttributes.Private;
2019                         
2020                         // code statements
2021                         CodeExpression expr;
2022                         CodeStatement stmt;
2023                         
2024                         // initialize adapter
2025                         expr = FieldRef ("_adapter");
2026                         stmt = Let (expr, New (taInfo.Adapter.GetType ()));
2027                         m.Statements.Add (stmt);
2028                         
2029                         // populate tableMapping
2030                         stmt = VarDecl (typeof (DataTableMapping), "tableMapping", null);
2031                         m.Statements.Add (stmt);
2032                         foreach (DataTableMapping tblMap in taInfo.Adapter.TableMappings) {
2033                                 expr = Local ("tableMapping");
2034                                 stmt = Let (expr, New (tblMap.GetType ()));
2035                                 m.Statements.Add (stmt);
2036                                 
2037                                 stmt = Let (PropRef (expr, "SourceTable"), Const (tblMap.SourceTable));
2038                                 m.Statements.Add (stmt);
2039                                 
2040                                 stmt = Let (PropRef (expr, "DataSetTable"), Const (tblMap.DataSetTable));
2041                                 m.Statements.Add (stmt);
2042                                 
2043                                 foreach (DataColumnMapping colMap in tblMap.ColumnMappings) { 
2044                                         stmt = Eval (MethodInvoke (PropRef (expr, "ColumnMappings"), "Add", 
2045                                                                    new CodeExpression [] {Const (colMap.SourceColumn), Const (colMap.DataSetColumn)}));
2046                                         m.Statements.Add (stmt);
2047                                 }
2048                                 expr = PropRef (FieldRef ("_adapter"), "TableMappings");
2049                                 stmt = Eval (MethodInvoke (expr, "Add", Local ("tableMapping")));
2050                                 m.Statements.Add (stmt);
2051                         }
2052                         // Generate code for adapter's deletecommand
2053                         expr = PropRef (FieldRef ("_adapter"), "DeleteCommand");
2054                         DbCommand cmd = taInfo.Adapter.DeleteCommand;
2055                         AddDbCommandStatements (m, expr, cmd);
2056
2057                         // Generate code for adapter's insertcommand
2058                         expr = PropRef (FieldRef ("_adapter"), "InsertCommand");
2059                         cmd = taInfo.Adapter.InsertCommand;
2060                         AddDbCommandStatements (m, expr, cmd);
2061
2062                         // Generate code for adapter's updatecommand
2063                         expr = PropRef (FieldRef ("_adapter"), "UpdateCommand");
2064                         cmd = taInfo.Adapter.UpdateCommand;
2065                         AddDbCommandStatements (m, expr, cmd);
2066
2067                         t.Members.Add (m);
2068                 }
2069                 
2070                 private void AddDbCommandStatements (CodeMemberMethod m, 
2071                                                      CodeExpression expr, 
2072                                                      DbCommand cmd)
2073                 {
2074                         if (cmd == null)
2075                                 return;
2076                         
2077                         CodeExpression expr1;
2078                         CodeStatement stmt = Let (expr, New (cmd.GetType ()));
2079                         m.Statements.Add (stmt);
2080                         
2081                         stmt = Let (PropRef (expr,"Connection"), PropRef ("Connection"));
2082                         m.Statements.Add (stmt);
2083                         stmt = Let (PropRef (expr, "CommandText"), Const (cmd.CommandText));
2084                         m.Statements.Add (stmt);
2085                         expr1 = PropRef (Local(typeof (CommandType).FullName), cmd.CommandType.ToString ());
2086                         stmt = Let (PropRef (expr, "CommandType"), expr1);
2087                         m.Statements.Add (stmt);
2088                         
2089                         expr1 = PropRef (expr, "Parameters");
2090                         foreach (DbParameter param in cmd.Parameters) {
2091                                 AddDbParameterStatements (m, expr1, param);
2092                         }
2093                 }
2094                 
2095                 private void AddDbParameterStatements (CodeMemberMethod m, 
2096                                                        CodeExpression expr, 
2097                                                        DbParameter param)
2098                 {
2099                         object dbType = param.FrameworkDbType;
2100                         string srcColumn = null;
2101                         
2102                         if (param.SourceColumn != String.Empty)
2103                                 srcColumn = param.SourceColumn;
2104                         
2105                         CodeExpression[] args = new CodeExpression[] {
2106                                 Const (param.ParameterName),
2107                                 PropRef (Local(dbType.GetType().FullName), dbType.ToString ()), 
2108                                 Const (param.Size),
2109                                 PropRef(Local(typeof (ParameterDirection).FullName), param.Direction.ToString ()),
2110                                 Const (param.IsNullable),
2111                                 Const (((IDbDataParameter)param).Precision),
2112                                 Const (((IDbDataParameter)param).Scale),
2113                                 Const (srcColumn),
2114                                 PropRef (Local (typeof (DataRowVersion).FullName), param.SourceVersion.ToString ()),
2115                                 /* Const (param.SourceColumnNullMapping), */ // TODO: Investigate with other providers
2116                                 Const (param.Value)
2117                         };
2118                         m.Statements.Add (Eval (MethodInvoke (expr, "Add", New (param.GetType (), args))));
2119                 }
2120                 private void CreateConnectionInitializeMethod (CodeTypeDeclaration t, 
2121                                                                TableAdapterSchemaInfo taInfo)
2122                 {
2123                         CodeMemberMethod m = new CodeMemberMethod ();
2124                         m.Name = "InitConnection";
2125                         m.Attributes = MemberAttributes.Private;
2126                         
2127                         // code statements
2128                         CodeExpression expr, expr1;
2129                         CodeStatement stmt;
2130                         
2131                         // initialize connection
2132                         expr = FieldRef ("_connection");
2133                         stmt = Let (expr, New (taInfo.Connection.GetType ()));
2134                         m.Statements.Add (stmt);
2135                         
2136                         // assign connection string
2137                         expr = PropRef (FieldRef ("_connection"), "ConnectionString");
2138                         expr1 = IndexerRef (PropRef (Local (typeof (System.Configuration.ConfigurationManager).ToString()), "ConnectionStrings"), 
2139                                             Const (taInfo.ConnectionString));
2140                         stmt = Let (expr, PropRef (expr1, "ConnectionString"));
2141                         m.Statements.Add (stmt);
2142                         
2143                         t.Members.Add (m);
2144                 }
2145                 
2146                 private void CreateCommandCollectionInitializeMethod (CodeTypeDeclaration t, 
2147                                                                       TableAdapterSchemaInfo taInfo)
2148                 {
2149                         //string tmp = null;
2150                         Type type;
2151                         CodeMemberMethod m = new CodeMemberMethod ();
2152                         m.Name = "InitCommandCollection";
2153                         m.Attributes = MemberAttributes.Private;
2154                         
2155                         // code statements
2156                         CodeExpression expr, expr1;
2157                         CodeStatement stmt;
2158                         
2159                         type = ((DbCommandInfo)taInfo.Commands[0]).Command.GetType();
2160                         
2161                         // initialize connection
2162                         expr = FieldRef ("_commandCollection");
2163                         stmt = Let (expr, NewArray (type, taInfo.Commands.Count));
2164                         m.Statements.Add (stmt);
2165                         
2166                         // loop through the collection and generate the code
2167                         for (int idx = 0; idx < taInfo.Commands.Count; idx++) {
2168                                 DbCommand cmd = ((DbCommandInfo)taInfo.Commands[idx]).Command;
2169                                 // Allocate
2170                                 expr1 = IndexerRef (expr, Const (idx));
2171                                 stmt = Let (expr1, New (type));
2172                                 m.Statements.Add (stmt);
2173                                 
2174                                 // Initialize cmd members
2175                                 stmt = Let (PropRef (expr1, "Connection"), PropRef ("Connection"));
2176                                 m.Statements.Add (stmt);
2177                                 stmt = Let (PropRef (expr1, "CommandText"), Const (cmd.CommandText));
2178                                 m.Statements.Add (stmt);
2179                                 stmt = Let (PropRef (expr1, "CommandType"), 
2180                                             PropRef (Local(typeof (CommandType).FullName), cmd.CommandType.ToString ()));
2181                                 m.Statements.Add (stmt);
2182                                 expr1 = PropRef (expr1, "Parameters");
2183                                 foreach (DbParameter param in cmd.Parameters) {
2184                                         AddDbParameterStatements (m, expr1, param);
2185                                 }
2186                         }               
2187                         t.Members.Add (m);
2188                 }
2189                 
2190                 private void CreateDbSourceMethods (CodeTypeDeclaration t, 
2191                                                     TableAdapterSchemaInfo taInfo)
2192                 {
2193                         string tmp = null;
2194                         CodeMemberMethod m = null;
2195                         CodeExpression expr, expr1, expr2;
2196                         CodeStatement stmt;
2197                         string tmpScalarVal = null;
2198                         
2199                         expr = PropRef (PropRef ("Adapter"), "SelectCommand");
2200                         // loop through the collection and generate the code
2201                         for (int idx = 0; idx < taInfo.Commands.Count; idx++) {
2202                                 DbCommandInfo cmdInfo = (DbCommandInfo)taInfo.Commands[idx];
2203                                 
2204                                 foreach (DbSourceMethodInfo mInfo in cmdInfo.Methods) {
2205                                         //Console.WriteLine ("Generating code for {0} method", mInfo.Name);
2206                                         
2207                                         // TODO: Add support for Fill methods
2208                                         if (mInfo.MethodType == GenerateMethodsType.Fill)
2209                                                 continue;
2210                                         
2211                                         m = new CodeMemberMethod ();
2212                                         m.Name = mInfo.Name;
2213                                         
2214                                         stmt = Let (expr, IndexerRef (PropRef ("CommandCollection"), Const (idx)));
2215                                         m.Statements.Add (stmt);
2216                                         
2217                                         switch ((MemberAttributes) Enum.Parse (typeof (MemberAttributes), mInfo.Modifier)) {
2218                                                 case MemberAttributes.Public:
2219                                                         m.Attributes = MemberAttributes.Public;
2220                                                         break;
2221
2222                                                 case MemberAttributes.Private:
2223                                                         m.Attributes = MemberAttributes.Private;
2224                                                         break;
2225                                                 
2226                                                 case MemberAttributes.Assembly:
2227                                                         m.Attributes = MemberAttributes.Assembly;
2228                                                         break;
2229                                                 
2230                                                 case MemberAttributes.Family:
2231                                                         m.Attributes = MemberAttributes.Family;
2232                                                         break;
2233                                         }
2234                                         //Console.WriteLine ("QueryType: {0}", mInfo.QueryType);
2235                                         QueryType qType = (QueryType) Enum.Parse (typeof (QueryType), mInfo.QueryType);
2236                                         switch (qType) {
2237                                                 case QueryType.Scalar:
2238                                                 case QueryType.NoData:
2239                                                         // executes non query and returns status
2240                                                         m.ReturnType = TypeRef (typeof (int));
2241                                                         AddGeneratedMethodParametersAndStatements (m, expr, cmdInfo.Command);
2242                                                 
2243                                                         // store connection state
2244                                                         tmp = typeof (System.Data.ConnectionState).FullName;
2245                                                         expr1 = PropRef (Local ("command"), "Connection");
2246                                                         expr2 = PropRef (PropRef (Local ("System"), "Data"), "ConnectionState");
2247                                                         stmt = VarDecl (tmp, "previousConnectionState", PropRef (expr1, "State"));
2248                                                         m.Statements.Add (stmt);
2249                                                         
2250                                                         // Open connection, if its not already
2251                                                         CodeExpression expr3 = BitOps (PropRef (expr1, "State"), PropRef (expr2, "Open"),
2252                                                                                    CodeBinaryOperatorType.BitwiseAnd);
2253                                                         stmt = new CodeConditionStatement (Inequals (expr3, PropRef (expr2, "Open")), 
2254                                                                                                           new CodeStatement[] {Eval (MethodInvoke (expr1, "Open", 
2255                                                                                                                                                                         new CodeExpression[] {}))},
2256                                                                                                           new CodeStatement[] {});
2257                                                         m.Statements.Add (stmt);
2258                                                 
2259                                                         // declare return variable and execute query
2260                                                         CodeTryCatchFinallyStatement try1 = new CodeTryCatchFinallyStatement ();
2261                                                 
2262                                                         if (qType == QueryType.NoData) {
2263                                                                 m.Statements.Add (VarDecl (typeof (int), "returnValue", null));
2264                                                                 expr3 = MethodInvoke (Local ("command"), "ExecuteNonQuery", new CodeExpression[] {});
2265                                                         } else {
2266                                                                 tmpScalarVal = mInfo.ScalarCallRetval.Substring (0, mInfo.ScalarCallRetval.IndexOf (','));
2267                                                                 m.Statements.Add (VarDecl (TypeRef (tmpScalarVal).BaseType, "returnValue", null));
2268                                                                 expr3 = MethodInvoke (Local ("command"), "ExecuteScalar", new CodeExpression[] {});
2269                                                         }
2270                                                 
2271                                                         // Execute query
2272                                                         try1.TryStatements.Add (Let (Local ("returnValue"), expr3));
2273                                                         
2274                                                         // fill finally block
2275                                                         stmt = new CodeConditionStatement (Equals (Local ("previousConnectionState"), PropRef (expr2, "Closed")), 
2276                                                                                                                                 new CodeStatement[] {Eval (MethodInvoke (expr1, "Close", 
2277                                                                                                                                                                         new CodeExpression[] {}))},
2278                                                                                                                                 new CodeStatement[] {});
2279                                                         try1.FinallyStatements.Add (stmt);
2280                                                         m.Statements.Add (try1);
2281                                                 
2282                                                         // return the value
2283                                                         if (qType == QueryType.NoData) {
2284                                                                 m.Statements.Add (Return (Local ("returnValue")));
2285                                                         } else {
2286                                                                 expr2 = Equals (Local ("returnValue"), Const (null));
2287                                                                 expr3 = Equals (MethodInvoke (Local ("returnValue"), "GetType", new CodeExpression[] {}), 
2288                                                                                 TypeOfRef ("System.DBNull"));
2289                                                                 stmt = new CodeConditionStatement (BooleanOps (expr2, expr3, CodeBinaryOperatorType.BooleanOr), 
2290                                                                                                         new CodeStatement[] {Return (Const (null))},
2291                                                                                                                                         new CodeStatement[] {Return (Cast (tmpScalarVal, Local ("returnValue")))});
2292                                                                 m.Statements.Add (stmt);
2293                                                         }
2294                                                 
2295                                                         break;
2296
2297                                                 case QueryType.Rowset:
2298                                                         // returns DataTable
2299                                                         // TODO: Handle multiple DataTables
2300                                                         tmp = opts.DataSetName (ds.DataSetName) + "." + opts.TableTypeName (ds.Tables[0].TableName);
2301                                                         m.ReturnType = TypeRef (tmp);
2302
2303                                                         AddGeneratedMethodParametersAndStatements (m, expr, cmdInfo.Command);
2304                                                         stmt = VarDecl (tmp, "dataTable", New (tmp));
2305                                                         m.Statements.Add (stmt);
2306
2307                                                         // fill datatable
2308                                                         expr = PropRef ("Adapter");
2309                                                         stmt = Eval (MethodInvoke (expr, "Fill", Local ("dataTable")));
2310                                                         m.Statements.Add (stmt);
2311
2312                                                         // return statement
2313                                                         m.Statements.Add (Return (Local ("dataTable")));
2314                                                         break;
2315                                         }
2316                                         t.Members.Add (m);
2317                                 }                       
2318                         }
2319                 }
2320                 
2321                 private void AddGeneratedMethodParametersAndStatements (CodeMemberMethod m, 
2322                                                                         CodeExpression expr,
2323                                                                         DbCommand cmd)
2324                 {
2325                         CodeStatement stmt;
2326                         CodeExpression expr1;
2327                         int idx = 0;
2328                         string tmp;
2329                         DbType dbType = DbType.DateTime;
2330                         foreach (DbParameter param in cmd.Parameters) {
2331                                 if (param.Direction != ParameterDirection.ReturnValue) {
2332                                         if (param.ParameterName[0] == '@')
2333                                                 tmp = param.ParameterName.Substring (1);
2334                                         else
2335                                                 tmp = param.ParameterName;
2336                                         if (param.SystemType != null)
2337                                                 m.Parameters.Add (Param (TypeRef(param.SystemType), tmp));
2338                                         expr1 = IndexerRef (PropRef (expr, "Parameters"), Const (idx));
2339                                         stmt = Let (expr1, ParamRef (tmp));
2340                                         m.Statements.Add (stmt);
2341                                 }
2342                                 idx++;
2343                         }
2344                 }
2345                 
2346                 private void CreateShortCommandMethods (CodeTypeDeclaration t, TableAdapterSchemaInfo taInfo)
2347                 {
2348                         
2349                 }
2350                 
2351 #endregion
2352 #endif  //NET_2_0
2353
2354         }
2355         
2356 }
2357
2358
2359 /* =========================================================
2360
2361
2362 MonoDataSetGenerator API notes
2363
2364
2365 ** generator API:
2366         CreateDataSetClasses (
2367                 DataSet ds,
2368                 CodeNamespace cns,
2369                 ICodeGenerator gen,
2370                 GeneratorOptions options)
2371
2372 ** classes:
2373
2374 *** Code naming method delegate
2375
2376         public delegate string CodeNamingMethod (string sourceName);
2377
2378         It is used in CodeGeneratorOptions (describled immediately below).
2379
2380
2381
2382 *** Generator Options
2383
2384         public bool MakeClassesInsideDataSet
2385                 indicates whether classes and delegates other than DataSet
2386                 itself are "contained" in the DataSet class or not.
2387
2388         public CodeNamingMethod CreateDataSetName;
2389         public CodeNamingMethod CreateTableTypeName;
2390         public CodeNamingMethod CreateTableMemberName;
2391         public CodeNamingMethod CreateColumnName;
2392         public CodeNamingMethod CreateRowName;
2393         public CodeNamingMethod CreateRelationName;
2394         public CodeNamingMethod CreateTableDelegateName;
2395         public CodeNamingMethod CreateEventArgsName;
2396                 Custom methods each of that returns type or member name.
2397
2398                 By default, they are set as to useTypedDataSetGenerator.
2399                 CreateIdName() with modifications listed as below:
2400
2401                 DataSetName: as is
2402                 TableTypeName: "DataTable" suffix
2403                 TableMemberName: as is
2404                 ColumnName: as is
2405                 RowName: "Row" suffix
2406                 RelationName: (TBD; maybe had better have another delegate type)
2407                 DelegateName: "RowChangedEventHandler" suffix
2408                 EventArgsName: "RowChangedEventArgs" suffix
2409
2410 ** Auto Generated classes
2411
2412 1. Custom DataSet class 
2413
2414         class name = dataset name, encoded by options.CreateDataSetName().
2415
2416 *** .ctor
2417
2418         public default .ctor()
2419                 "initialize" class.
2420                 set custom delegate on Tables.CollectionChanged
2421                 set custom delegate on Relations.CollectionChanged
2422
2423         runtime serialization .ctor()
2424                 TBD
2425
2426 *** public members
2427
2428         data tables: [foo]DataTable foo { return this.table[foo]; }
2429
2430         Clone()
2431                 init variables on new dataset.
2432
2433 *** protected members
2434
2435         ShouldSerializeTables()
2436                 returns false, while default DataSet returns true.
2437         ShouldSerializeRelations()
2438                 returns false, while default DataSet returns true.
2439
2440         ReadXmlSerializable() ... similar to runtime serialization
2441                 TBD
2442
2443         GetSchemaSerializable()
2444                 Write its schema to temporary MemoryStream
2445                 Read XML schema from the stream
2446
2447 *** internal members
2448
2449         "init variables"
2450                 set member fields (tables, relations)
2451                 call members' "init variables"
2452
2453         "init class"
2454                 set DataSetName, Prefix, Namespace, Locale, CaseSensitive, EnforceConstraints
2455                 for each table
2456                         allocate table[foo] 
2457                         Tables.Add() 
2458                         create FKC: new FKC([rel], new DataColumn [] {table[foo].[keyColumnName]Column}, new DataColumn [] {table[child].[childColName]Column}
2459                 fill Rule properties.
2460                 allocate relation[rel] and fill Nested, then Relations.Add()
2461
2462 *** private members
2463
2464         data tables: [foo]DataTable table[foo];
2465
2466         data relations: DataRelation relation[rel];
2467
2468         ShouldSerialize[foo]
2469
2470
2471
2472 2. Custom DataTable classes for each DataTable
2473
2474         This class is created under the dataset.
2475
2476 *** internal members
2477
2478         .ctor() : base("[foo]")
2479                 initialize class
2480
2481         .ctor(DataTable)
2482                 wtf?
2483
2484         DataColumn [bar]Column { return column[bar]; }
2485
2486         "init variables"()
2487                 fill each column fields
2488
2489 *** public members
2490
2491         int Count { rowcount }
2492
2493         this [int index] { row [i]; }
2494
2495         event [foo]RowChangedEventHandler [foo]RowChanged
2496         event [foo]RowChangedEventHandler [foo]RowChanging
2497         event [foo]RowChangedEventHandler [foo]RowDeleted
2498         event [foo]RowChangedEventHandler [foo]RowDeleting
2499
2500         void Add[foo]Row ([foo]Row row) { Rows.Add (row); }
2501
2502         [foo]Row Add[foo]Row ([columnType] [columnName])
2503                 create new [foo]row.
2504                 set members
2505                 Rows.Add ()
2506                 // where
2507                 //      non-relation-children are just created as column type
2508                 //      relation-children are typeof fooRow[]
2509
2510         GetEnumerator() { Rows.GetEnumerator (); }
2511
2512         override DataTable Clone()
2513                 "init variables"
2514
2515         [foo]Row New[foo]Row()
2516
2517         void Remove[foo]Row([foo]Row)
2518
2519         //for each ChildRelations
2520         [bar]Row [] Get[foo_bar]Rows ()
2521
2522 *** protected members
2523
2524         override DataTable CreateInstance() { return new }
2525
2526         override DataRow NewRowFromBuilder(DataRowBuilder)
2527
2528         override Type GetRowType()
2529
2530         override void OnRowChanged(DataRowChangedEventArgs)
2531                 base.()
2532                 check this event [foo]RowChanged.
2533
2534         override void OnRowChanging(DataRowChangedEventArgs)
2535         override void OnRowDeleted(DataRowChangedEventArgs)
2536         override void OnRowDeleting(DataRowChangedEventArgs)
2537         ... as well
2538
2539 *** private members
2540
2541         "initialize class"
2542                 for each columns {
2543                         column[bar] = new DataColumn (...);
2544                         Columns.Add()
2545                 }
2546
2547         DataColumn [bar]Column
2548
2549 3. Custom DataRow classses
2550
2551 *** public members
2552
2553         for simple members:
2554
2555                 [bar_type] [bar] {
2556                         get { try { } catch { throw StrongTypingException(); }
2557                         set { this [[foo]Table.[bar]Column] = value; }
2558
2559                 bool Is[bar]Null ()
2560                         IsNull ([foo]Table.[bar]Column);
2561
2562                 void Set[bar]Null ()
2563
2564         if the table is parent of some relations
2565
2566                 public [child]Row [] Get[child]Rows()
2567
2568 *** internal members
2569
2570         .ctor(DataRowBuilder) : base.()
2571                 table[foo] = Table;
2572
2573 *** private members
2574
2575         [foo]DataTable table[foo]
2576
2577
2578 4. Custom DataRowChangeEvent classes
2579
2580 *** private members
2581
2582         [foo]Row eventRow
2583         DataRowAction eventAction
2584
2585 *** public members
2586
2587         .ctor([foo]Row row, DataRowAction action)
2588
2589         [foo]Row Row
2590
2591         DataRowAction Action
2592
2593
2594
2595 5. public Table RowChangedEventHandler delegates
2596
2597         [foo]RowChangedEventHandler(object, [foo]RowChangedEvent e)
2598
2599
2600 ======================================================== */