importing messaging-2008 branch to trunk [continued]
[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.Collections;
41 using System.CodeDom;
42 using System.Globalization;
43 using System.Text;
44 using System.CodeDom.Compiler;
45 using System.ComponentModel;
46 using System.Runtime.Serialization;
47 using System.Xml.Schema;
48 using System.Xml.Serialization;
49
50 // only for Driver
51 using Microsoft.CSharp;
52 using System.IO;
53
54 namespace System.Data
55 {
56
57 #if DATACLASS_GENERATOR_STANDALONE
58         public class Driver
59         {
60                 public static void Main (string [] args)
61                 {
62                         try {
63                                 if (args.Length < 1) {
64                                         Console.WriteLine ("mono dsgentest.exe filename");
65                                         return;
66                                 }
67
68                                 DataSet ds = new DataSet ();
69                                 ds.ReadXml (args [0]);
70                                 ICodeGenerator gen = new CSharpCodeProvider ().CreateGenerator ();
71
72                                 CodeNamespace cns = new CodeNamespace ("MyNamespace");
73                                 TextWriter tw = new StreamWriter (Path.ChangeExtension (args [0], ".ms.cs"), false, Encoding.Default);
74                                 TypedDataSetGenerator.Generate (ds, cns, gen);
75                                 gen.GenerateCodeFromNamespace (cns, tw, null);
76                                 tw.Close ();
77
78                                 cns = new CodeNamespace ("MyNamespace");
79                                 tw = new StreamWriter (Path.ChangeExtension (args [0], ".mono.cs"), false, Encoding.Default);
80                                 CustomDataClassGenerator.CreateDataSetClasses (ds, cns, gen, null);
81                                 gen.GenerateCodeFromNamespace (cns, tw, null);
82                                 tw.Close ();
83                         } catch (Exception ex) {
84                                 Console.WriteLine (ex);
85                         }
86                 }
87         }
88 #endif
89
90 #if DATACLASS_GENERATOR_STANDALONE
91         public class CustomDataClassGenerator
92 #else
93         internal class CustomDataClassGenerator
94 #endif
95         {
96                 public static void CreateDataSetClasses (DataSet ds,
97                         CodeNamespace cns, ICodeGenerator gen,
98                         ClassGeneratorOptions options)
99                 {
100                         new Generator (ds, cns, gen, options).Run ();
101                 }
102
103                 public static string MakeSafeName (string name, ICodeGenerator codeGen)
104                 {
105                         if (name == null || codeGen == null)
106                                 throw new NullReferenceException ();
107
108                         name = codeGen.CreateValidIdentifier (name);
109
110                         if (name.Length == 0)
111                                 return "_";
112
113                         StringBuilder sb = null;
114                         if (!Char.IsLetter (name, 0) && name [0] != '_') {
115                                 sb = new StringBuilder ();
116                                 sb.Append ('_');
117                         }
118
119                         int start = 0;
120                         for (int i = 0; i < name.Length; i++) {
121                                 if (!Char.IsLetterOrDigit (name, i)) {
122                                         if (sb == null)
123                                                 sb = new StringBuilder ();
124                                         sb.Append (name, start, i - start);
125                                         sb.Append ('_');
126                                         start = i + 1;
127                                 }
128                         }
129
130                         if (sb != null) {
131                                 sb.Append (name, start, name.Length - start);
132                                 return sb.ToString ();
133                         }
134                         else
135                                 return name;
136                 }
137         }
138
139 #if DATACLASS_GENERATOR_STANDALONE
140         public delegate string CodeNamingMethod (string source, ICodeGenerator gen);
141 #else
142         internal delegate string CodeNamingMethod (string source, ICodeGenerator gen);
143 #endif
144
145 #if DATACLASS_GENERATOR_STANDALONE
146         public class ClassGeneratorOptions
147 #else
148         internal class ClassGeneratorOptions
149 #endif
150         {
151                 public bool MakeClassesInsideDataSet = true; // default = MS compatible
152
153                 public CodeNamingMethod CreateDataSetName;
154                 public CodeNamingMethod CreateTableTypeName;
155                 public CodeNamingMethod CreateTableMemberName;
156                 public CodeNamingMethod CreateTableColumnName;
157                 public CodeNamingMethod CreateColumnName;
158                 public CodeNamingMethod CreateRowName;
159                 public CodeNamingMethod CreateRelationName;
160                 public CodeNamingMethod CreateTableDelegateName;
161                 public CodeNamingMethod CreateEventArgsName;
162
163                 internal string DataSetName (string source, ICodeGenerator gen)
164                 {
165                         if (CreateDataSetName != null)
166                                 return CreateDataSetName (source, gen);
167                         else
168                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
169                 }
170
171                 internal string TableTypeName (string source, ICodeGenerator gen)
172                 {
173                         if (CreateTableTypeName != null)
174                                 return CreateTableTypeName (source, gen);
175                         else
176                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "DataTable";
177                 }
178
179                 internal string TableMemberName (string source, ICodeGenerator gen)
180                 {
181                         if (CreateTableMemberName != null)
182                                 return CreateTableMemberName (source, gen);
183                         else
184                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
185                 }
186
187                 internal string TableColName (string source, ICodeGenerator gen)
188                 {
189                         if (CreateTableColumnName != null)
190                                 return CreateTableColumnName (source, gen);
191                         else
192                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
193                 }
194
195                 internal string TableDelegateName (string source, ICodeGenerator gen)
196                 {
197                         if (CreateTableDelegateName != null)
198                                 return CreateTableDelegateName (source, gen);
199                         else
200                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "RowChangedEventHandler";
201                 }
202
203                 internal string EventArgsName (string source, ICodeGenerator gen)
204                 {
205                         if (CreateEventArgsName != null)
206                                 return CreateEventArgsName (source, gen);
207                         else
208                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "RowChangedEventArgs";
209                 }
210
211                 internal string ColumnName (string source, ICodeGenerator gen)
212                 {
213                         if (CreateColumnName != null)
214                                 return CreateColumnName (source, gen);
215                         else
216                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
217                 }
218
219                 internal string RowName (string source, ICodeGenerator gen)
220                 {
221                         if (CreateRowName != null)
222                                 return CreateRowName (source, gen);
223                         else
224                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "Row";
225                 }
226
227                 internal string RelationName (string source, ICodeGenerator gen)
228                 {
229                         if (CreateRelationName != null)
230                                 return CreateRelationName (source, gen);
231                         else
232                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "Relation";
233                 }
234         }
235
236         internal class Generator
237         {
238                 static ClassGeneratorOptions DefaultOptions = new ClassGeneratorOptions ();
239
240                 DataSet ds;
241                 CodeNamespace cns;
242                 ClassGeneratorOptions opts;
243                 ICodeGenerator gen;
244
245                 CodeTypeDeclaration dsType;
246
247                 public Generator (DataSet ds, CodeNamespace cns, ICodeGenerator gen, ClassGeneratorOptions options)
248                 {
249                         this.ds = ds;
250                         this.cns = cns;
251                         this.gen = gen;
252                         this.opts = options;
253
254                         if (opts == null)
255                                 opts = DefaultOptions;
256                 }
257
258                 public void Run ()
259                 {
260                         // using decls
261                         cns.Imports.Add (new CodeNamespaceImport ("System"));
262                         cns.Imports.Add (new CodeNamespaceImport ("System.Collections"));
263                         cns.Imports.Add (new CodeNamespaceImport ("System.ComponentModel"));
264                         cns.Imports.Add (new CodeNamespaceImport ("System.Data"));
265                         cns.Imports.Add (new CodeNamespaceImport ("System.Runtime.Serialization"));
266                         cns.Imports.Add (new CodeNamespaceImport ("System.Xml"));
267
268
269                         CodeTypeDeclaration dsType = GenerateDataSetType ();
270                         cns.Types.Add (dsType);
271                         foreach (DataTable dt in ds.Tables) {
272                                 // 1. table types ([foo]DataTable)
273                                 // 2. row types ([foo]Row)
274                                 // 3. delegates ([foo]RowChangedEventHandler)
275                                 // 4. eventargs ([foo]RowChangeEventArgs)
276
277                                 CodeTypeDeclaration dtType = GenerateDataTableType (dt);
278
279                                 CodeTypeDeclaration dtRow = GenerateDataRowType (dt);
280
281                                 CodeTypeDelegate dtDelegate = new CodeTypeDelegate (opts.TableDelegateName (dt.TableName, gen));
282                                 dtDelegate.Parameters.Add (Param (typeof (object), "o"));
283                                 dtDelegate.Parameters.Add (Param (opts.EventArgsName (dt.TableName, gen), "e"));
284
285                                 CodeTypeDeclaration dtEventType = GenerateEventType (dt);
286
287                                 // Add types to either DataSet or CodeNamespace
288                                 if (opts.MakeClassesInsideDataSet) {
289                                         dsType.Members.Add (dtType);
290                                         dsType.Members.Add (dtRow);
291                                         dsType.Members.Add (dtDelegate);
292                                         dsType.Members.Add (dtEventType);
293                                 }
294                                 else {
295                                         cns.Types.Add (dtType);
296                                         cns.Types.Add (dtRow);
297                                         cns.Types.Add (dtDelegate);
298                                         cns.Types.Add (dtEventType);
299                                 }
300                         }
301                 }
302
303                 private CodeThisReferenceExpression This ()
304                 {
305                         return new CodeThisReferenceExpression ();
306                 }
307
308                 private CodeBaseReferenceExpression Base ()
309                 {
310                         return new CodeBaseReferenceExpression ();
311                 }
312
313                 private CodePrimitiveExpression Const (object value)
314                 {
315                         return new CodePrimitiveExpression (value);
316                 }
317
318                 private CodeTypeReference TypeRef (Type t)
319                 {
320                         return new CodeTypeReference (t);
321                 }
322
323                 private CodeTypeReference TypeRef (string name)
324                 {
325                         return new CodeTypeReference (name);
326                 }
327
328                 private CodeParameterDeclarationExpression Param (string t, string name)
329                 {
330                         return new CodeParameterDeclarationExpression (t, name);
331                 }
332
333                 private CodeParameterDeclarationExpression Param (Type t, string name)
334                 {
335                         return new CodeParameterDeclarationExpression (t, name);
336                 }
337
338                 private CodeParameterDeclarationExpression Param (CodeTypeReference t, string name)
339                 {
340                         return new CodeParameterDeclarationExpression (t, name);
341                 }
342
343                 private CodeArgumentReferenceExpression ParamRef (string name)
344                 {
345                         return new CodeArgumentReferenceExpression (name);
346                 }
347
348                 private CodeCastExpression Cast (string t, CodeExpression exp)
349                 {
350                         return new CodeCastExpression (t, exp);
351                 }
352
353                 private CodeCastExpression Cast (Type t, CodeExpression exp)
354                 {
355                         return new CodeCastExpression (t, exp);
356                 }
357
358                 private CodeCastExpression Cast (CodeTypeReference t, CodeExpression exp)
359                 {
360                         return new CodeCastExpression (t, exp);
361                 }
362
363                 private CodeExpression New (Type t, params CodeExpression [] parameters)
364                 {
365                         return new CodeObjectCreateExpression (t, parameters);
366                 }
367
368                 private CodeExpression New (string t, params CodeExpression [] parameters)
369                 {
370                         return new CodeObjectCreateExpression (TypeRef (t), parameters);
371                 }
372
373                 private CodeExpression NewArray (Type t, params CodeExpression [] parameters)
374                 {
375                         return new CodeArrayCreateExpression (t, parameters);
376                 }
377
378                 private CodeVariableReferenceExpression Local (string name)
379                 {
380                         return new CodeVariableReferenceExpression (name);
381                 }
382
383                 private CodeFieldReferenceExpression FieldRef (string name)
384                 {
385                         return new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), name);
386                 }
387
388                 private CodeFieldReferenceExpression FieldRef (CodeExpression exp, string name)
389                 {
390                         return new CodeFieldReferenceExpression (exp, name);
391                 }
392
393                 private CodePropertyReferenceExpression PropRef (string name)
394                 {
395                         return new CodePropertyReferenceExpression (new CodeThisReferenceExpression (), name);
396                 }
397
398                 private CodePropertyReferenceExpression PropRef (CodeExpression target, string name)
399                 {
400                         return new CodePropertyReferenceExpression (target, name);
401                 }
402
403                 private CodeIndexerExpression IndexerRef (CodeExpression target, CodeExpression parameters)
404                 {
405                         return new CodeIndexerExpression (target, parameters);
406                 }
407
408                 private CodeIndexerExpression IndexerRef (CodeExpression param)
409                 {
410                         return new CodeIndexerExpression (new CodeThisReferenceExpression (), param);
411                 }
412
413                 private CodeEventReferenceExpression EventRef (string name)
414                 {
415                         return new CodeEventReferenceExpression (new CodeThisReferenceExpression (), name);
416                 }
417
418                 private CodeEventReferenceExpression EventRef (CodeExpression target, string name)
419                 {
420                         return new CodeEventReferenceExpression (target, name);
421                 }
422
423                 private CodeMethodInvokeExpression MethodInvoke (string name, params CodeExpression [] parameters)
424                 {
425                         return new CodeMethodInvokeExpression (new CodeThisReferenceExpression (), name, parameters);
426                 }
427
428                 private CodeMethodInvokeExpression MethodInvoke (CodeExpression target, string name, params CodeExpression [] parameters)
429                 {
430                         return new CodeMethodInvokeExpression (target, name, parameters);
431                 }
432
433                 private CodeBinaryOperatorExpression EqualsValue (CodeExpression exp1, CodeExpression exp2)
434                 {
435                         return new CodeBinaryOperatorExpression (exp1, CodeBinaryOperatorType.ValueEquality, exp2);
436                 }
437
438                 // note that this is "Identity" equality comparison
439                 private CodeBinaryOperatorExpression Equals (CodeExpression exp1, CodeExpression exp2)
440                 {
441                         return new CodeBinaryOperatorExpression (exp1, CodeBinaryOperatorType.IdentityEquality, exp2);
442                 }
443
444                 private CodeBinaryOperatorExpression Inequals (CodeExpression exp1, CodeExpression exp2)
445                 {
446                         return new CodeBinaryOperatorExpression (exp1, CodeBinaryOperatorType.IdentityInequality, exp2);
447                 }
448
449                 private CodeTypeReferenceExpression TypeRefExp (Type t)
450                 {
451                         return new CodeTypeReferenceExpression (t);
452                 }
453
454
455                 private CodeExpressionStatement Eval (CodeExpression exp)
456                 {
457                         return new CodeExpressionStatement (exp);
458                 }
459
460                 private CodeAssignStatement Let (CodeExpression exp, CodeExpression value)
461                 {
462                         return new CodeAssignStatement (exp, value);
463                 }
464
465                 private CodeMethodReturnStatement Return (CodeExpression exp)
466                 {
467                         return new CodeMethodReturnStatement (exp);
468                 }
469
470                 private CodeVariableDeclarationStatement VarDecl (Type t,
471                         string name, CodeExpression init)
472                 {
473                         return new CodeVariableDeclarationStatement (t, name, init);
474                 }
475
476                 private CodeVariableDeclarationStatement VarDecl (string t,
477                         string name, CodeExpression init)
478                 {
479                         return new CodeVariableDeclarationStatement (t, name, init);
480                 }
481
482                 private CodeCommentStatement Comment (string comment)
483                 {
484                         return new CodeCommentStatement (comment);
485                 }
486
487                 private CodeThrowExceptionStatement Throw (CodeExpression exp)
488                 {
489                         return new CodeThrowExceptionStatement (exp);
490                 }
491
492 #region DataSet class
493
494                 private CodeTypeDeclaration GenerateDataSetType ()
495                 {
496                         // Type
497                         dsType = new CodeTypeDeclaration (opts.DataSetName (ds.DataSetName, gen));
498                         dsType.BaseTypes.Add (TypeRef (typeof (DataSet)));
499                         dsType.BaseTypes.Add (TypeRef (typeof (IXmlSerializable)));
500
501                         // .ctor()
502                         dsType.Members.Add (CreateDataSetDefaultCtor ());
503                         // runtime serialization .ctor()
504                         dsType.Members.Add (CreateDataSetSerializationCtor ());
505
506                         // Clone()
507                         dsType.Members.Add (CreateDataSetCloneMethod (dsType));
508
509 // FIXME: I keep these methods out of the generated source right now.
510 // It should be added after runtime serialization was implemented.
511 /*
512                         // ShouldSerializeTables()
513                         dsType.Members.Add (CreateDataSetShouldSerializeTables ());
514
515                         // ShouldSerializeRelations()
516                         dsType.Members.Add (CreateDataSetShouldSerializeRelations ());
517
518                         // ReadXmlSerializable()
519                         dsType.Members.Add (CreateDataSetReadXmlSerializable ());
520 */
521
522                         // GetSchemaSerializable()
523                         dsType.Members.Add (CreateDataSetGetSchemaSerializable ());
524
525                         dsType.Members.Add (CreateDataSetGetSchema ());
526                         dsType.Members.Add (CreateDataSetInitializeClass ());
527                         dsType.Members.Add (CreateDataSetInitializeFields ());
528                         dsType.Members.Add (CreateDataSetSchemaChanged ());
529
530                         // table class and members
531                         foreach (DataTable table in ds.Tables)
532                                 CreateDataSetTableMembers (dsType, table);
533                         // relation class and members
534                         foreach (DataRelation rel in ds.Relations)
535                                 CreateDataSetRelationMembers (dsType, rel);
536
537                         return dsType;
538                 }
539
540                 // Code:
541                 // public Foo ()
542                 // {
543                 //   InitializeClass();
544                 //   CollectionChangeEventHandler handler = new CollectionChangeEventHandler (SchemaChanged);
545                 //   Tables.CollectionChanged += handler;
546                 //   Relations.CollectionChanged += handler;
547                 // }
548                 private CodeConstructor CreateDataSetDefaultCtor ()
549                 {
550                         CodeConstructor ctor = new CodeConstructor ();
551                         ctor.Attributes = MemberAttributes.Public;
552                         // Code: InitializeClass().
553                         ctor.Statements.Add (Eval (MethodInvoke ("InitializeClass")));
554
555                         // Code: CollectionChangedEventHandler handler = new CollectionChangeEventHandler (SchemeChanged);
556                         CodeVariableDeclarationStatement stmt2 = 
557                                 VarDecl (
558                                         typeof (CollectionChangeEventHandler), 
559                                         "handler", 
560                                         New (
561                                                 typeof (CollectionChangeEventHandler), 
562                                                 new CodeDelegateCreateExpression (
563                                                         new CodeTypeReference (typeof (CollectionChangeEventHandler)),
564                                                         new CodeThisReferenceExpression (), 
565                                                         "SchemaChanged")));
566
567                         ctor.Statements.Add (stmt2);
568
569                         // Code: Tables.CollectionChanged += handler;
570                         ctor.Statements.Add (
571                                 new CodeAttachEventStatement (
572                                         EventRef (
573                                                 PropRef ("Tables"), 
574                                                 "CollectionChanged"),
575                                         Local ("handler")));
576
577                         // Code: Relations.CollectionChanged += handler;
578                         ctor.Statements.Add (
579                                 new CodeAttachEventStatement (
580                                         EventRef (
581                                                 PropRef ("Relations"), 
582                                                 "CollectionChanged"), 
583                                         Local ("handler")));
584
585                         return ctor;
586                 }
587
588                 // TODO: implement
589
590                 // Code:
591                 // protected Foo (SerializationInfo info, StreamingContext ctx)
592                 // {
593                 //   throw new NotImplementedException ();
594                 // }
595                 private CodeConstructor CreateDataSetSerializationCtor ()
596                 {
597                         CodeConstructor ctor = new CodeConstructor ();
598                         ctor.Attributes = MemberAttributes.Family;
599                         ctor.Parameters.Add (Param (typeof (SerializationInfo), "info"));
600                         ctor.Parameters.Add (Param (typeof (StreamingContext), "ctx"));
601
602                         // Code: 
603                         //  // TODO: implement
604                         //  throw new NotImplementedException ();
605                         ctor.Statements.Add (Comment ("TODO: implement"));
606                         ctor.Statements.Add (Throw (New (typeof (NotImplementedException))));
607
608                         return ctor;
609                 }
610
611                 // Code:
612                 //  public override DataSet Clone()
613                 //  {
614                 //    [foo] set = ([foo]) base.Clone ();
615                 //    set.InitializeFields ();
616                 //    return set;
617                 //  }
618                 private CodeMemberMethod CreateDataSetCloneMethod (CodeTypeDeclaration dsType)
619                 {
620                         CodeMemberMethod m = new CodeMemberMethod ();
621                         m.ReturnType = TypeRef (typeof (DataSet));
622                         m.Attributes = MemberAttributes.Public | MemberAttributes.Override;
623                         m.Name = "Clone";
624                         // Code: [foo] set = ([foo]) base.Clone ();
625                         CodeVariableReferenceExpression set = Local ("set");
626                         m.Statements.Add (VarDecl (
627                                         dsType.Name,
628                                         "set", 
629                                         Cast (
630                                                 dsType.Name,
631                                                 MethodInvoke (Base (), "Clone"))));
632                         m.Statements.Add (Eval (MethodInvoke (set, "InitializeFields")));
633                         m.Statements.Add (Return (set));
634                         return m;
635                 }
636
637                 // Code:
638                 // protected override bool ShouldSerializeTables ()
639                 // {
640                 //   return true; // it should be false
641                 // }
642                 /*
643                 private CodeMemberMethod CreateDataSetShouldSerializeTables ()
644                 {
645                         CodeMemberMethod m = new CodeMemberMethod ();
646                         m.Name = "ShouldSerializeTables";
647                         m.ReturnType = TypeRef (typeof (bool));
648                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
649                         // FIXME: set "false" after serialization .ctor() implementation
650                         m.Statements.Add (Return (Const (true)));
651                         return m;
652                 }
653                 */
654                 // Code:
655                 // protected override bool ShouldSerializeRelations ()
656                 // {
657                 //   return true; // it should be false
658                 // }
659                 
660                 /*
661                 private CodeMemberMethod CreateDataSetShouldSerializeRelations ()
662                 {
663                         CodeMemberMethod m = new CodeMemberMethod ();
664                         m.Name = "ShouldSerializeRelations";
665                         m.ReturnType = TypeRef (typeof (bool));
666                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
667                         // FIXME: set "false" after serialization .ctor() implementation
668                         m.Statements.Add (Return (Const (true)));
669                         return m;
670                 }
671                 */
672
673                 // Code:
674                 // protected override void ReadXmlSerializable()
675                 // {
676                 //   // TODO: implement
677                 //   throw new NotImplementedException ();
678                 // }
679                 /*
680                 private CodeMemberMethod CreateDataSetReadXmlSerializable ()
681                 {
682                         CodeMemberMethod method = new CodeMemberMethod ();
683                         method.Name = "ReadXmlSerializable";
684                         method.Attributes = MemberAttributes.Family | MemberAttributes.Override;
685                         method.Parameters.Add (Param (TypeRef (typeof (XmlReader)), "reader"));
686                         // TODO: implemnet
687                         method.Statements.Add (Comment ("TODO: implement"));
688                         // Hey, how can I specify the constructor to invoke chained ctor with an empty parameter list!?
689                         method.Statements.Add (Throw (New (typeof (NotImplementedException))));
690                         return method;
691                 }
692                 */
693
694                 private CodeMemberMethod CreateDataSetGetSchema ()
695                 {
696                         CodeMemberMethod m = new CodeMemberMethod ();
697                         m.PrivateImplementationType = TypeRef (typeof (IXmlSerializable));
698                         m.Name = "GetSchema";
699                         m.ReturnType = TypeRef (typeof (XmlSchema));
700                         m.Statements.Add (Return (MethodInvoke ("GetSchemaSerializable")));
701
702                         return m;
703                 }
704
705                 private CodeMemberMethod CreateDataSetGetSchemaSerializable ()
706                 {
707                         CodeMemberMethod m = new CodeMemberMethod ();
708                         m.Attributes = MemberAttributes.Family | 
709                                 MemberAttributes.Override;
710                         m.Name = "GetSchemaSerializable";
711                         m.ReturnType = TypeRef (typeof (XmlSchema));
712
713                         m.Statements.Add (VarDecl (typeof (StringWriter), "sw",
714                                 New (typeof (StringWriter))));
715                         m.Statements.Add (Eval (MethodInvoke ("WriteXmlSchema", Local ("sw"))));
716                         m.Statements.Add (Return (MethodInvoke (
717                                 TypeRefExp (typeof (XmlSchema)),
718                                 "Read",
719                                 New (typeof (XmlTextReader),
720                                         New (typeof (StringReader),
721                                                 MethodInvoke (Local ("sw"),
722                                                         "ToString"))),
723                                 Const (null))));
724
725                         return m;
726                 }
727
728                 private CodeMemberMethod CreateDataSetInitializeClass ()
729                 {
730                         CodeMemberMethod m = new CodeMemberMethod ();
731                         m.Name = "InitializeClass";
732                         m.Attributes = MemberAttributes.Assembly;
733
734                         // dataset properties
735                         m.Statements.Add (Let (PropRef ("DataSetName"), Const (ds.DataSetName)));
736                         m.Statements.Add (Let (PropRef ("Prefix"), Const (ds.Prefix)));
737                         m.Statements.Add (Let (PropRef ("Namespace"), Const (ds.Namespace)));
738                         m.Statements.Add (Let (PropRef ("Locale"), New (typeof (CultureInfo), Const (ds.Locale.Name))));
739                         m.Statements.Add (Let (PropRef ("CaseSensitive"), Const (ds.CaseSensitive)));
740                         m.Statements.Add (Let (PropRef ("EnforceConstraints"), Const (ds.EnforceConstraints)));
741
742                         // table
743                         foreach (DataTable dt in ds.Tables) {
744                                 string tableFieldName = "__table" + opts.TableMemberName (dt.TableName, gen);
745                                 string tableTypeName = opts.TableTypeName (dt.TableName, gen);
746                                 m.Statements.Add (Let (FieldRef (tableFieldName), New (tableTypeName)));
747                                 m.Statements.Add (Eval (MethodInvoke (PropRef ("Tables"), "Add", FieldRef (tableFieldName))));
748                         }
749
750                         bool fkcExists = false;
751                         bool ucExists = false;
752                         // First the UniqueConstraints
753                         foreach (DataTable dt in ds.Tables) {
754                                 string tname = "__table" + opts.TableMemberName (dt.TableName, gen);
755                                 foreach (Constraint c in dt.Constraints) {
756                                         UniqueConstraint uc = c as UniqueConstraint;
757                                         if (uc != null) {
758                                                 if (!ucExists) {
759                                                         m.Statements.Add (VarDecl (typeof (UniqueConstraint), "uc", null));
760                                                         ucExists = true;
761                                                 }
762                                                 CreateUniqueKeyStatements (m, uc, tname);
763                                         }
764                                 }
765                         }
766                         // Then the ForeignKeyConstraints
767                         foreach (DataTable dt in ds.Tables) {
768                                 string tname = "__table" + opts.TableMemberName (dt.TableName, gen);
769                                 foreach (Constraint c in dt.Constraints) {
770                                         ForeignKeyConstraint fkc = c as ForeignKeyConstraint;
771                                         if (fkc != null) {
772                                                 if (!fkcExists) {
773                                                         m.Statements.Add (VarDecl (typeof (ForeignKeyConstraint), "fkc", null));
774                                                         fkcExists = true;
775                                                 }
776                                                 string rtname = "__table" + opts.TableMemberName (fkc.RelatedTable.TableName, gen);
777                                                 CreateForeignKeyStatements (m, fkc, tname, rtname);
778                                         }
779                                 }
780                         }
781                         // What if other cases? dunno. Just ignore ;-)
782                         foreach (DataRelation rel in ds.Relations) {
783                                 string relName = opts.RelationName (rel.RelationName, gen);
784                                 ArrayList pcols = new ArrayList ();
785                                 foreach (DataColumn pcol in rel.ParentColumns)
786                                         pcols.Add (IndexerRef (PropRef (FieldRef ("__table" + opts.TableMemberName (rel.ParentTable.TableName, gen)), "Columns"), Const (pcol.ColumnName)));
787
788                                 ArrayList ccols = new ArrayList ();
789                                 foreach (DataColumn ccol in rel.ChildColumns)
790                                         ccols.Add (IndexerRef (PropRef (FieldRef ("__table" + opts.TableMemberName (rel.ChildTable.TableName, gen)), "Columns"), Const (ccol.ColumnName)));
791
792                                 // relation field
793                                 string fieldName = "__relation" + relName;
794                                 m.Statements.Add (Let (FieldRef (fieldName), New (typeof (DataRelation),
795                                         Const (rel.RelationName),
796                                         NewArray (typeof (DataColumn), pcols.ToArray (typeof (CodeExpression)) as CodeExpression []),
797                                         NewArray (typeof (DataColumn), ccols.ToArray (typeof (CodeExpression)) as CodeExpression []),
798                                         Const (false)
799                                         )));
800                                 m.Statements.Add (Let (PropRef (FieldRef (fieldName), "Nested"), Const (rel.Nested)));
801                                 m.Statements.Add (MethodInvoke (PropRef ("Relations"), "Add", FieldRef (fieldName)));
802                         }
803
804                         return m;
805                 }
806
807                 private void CreateUniqueKeyStatements (CodeMemberMethod m, UniqueConstraint uc, string tableField)
808                 {
809                         ArrayList al = new ArrayList ();
810                         foreach (DataColumn col in uc.Columns)
811                                 al.Add (IndexerRef (PropRef (FieldRef (tableField), "Columns"), Const (col.ColumnName)));
812
813                         m.Statements.Add (Let (Local ("uc"), New (
814                                 typeof (UniqueConstraint),
815                                 Const (uc.ConstraintName),
816                                 NewArray (
817                                         typeof (DataColumn),
818                                         al.ToArray (typeof (CodeExpression)) as CodeExpression []),
819                                 Const (uc.IsPrimaryKey))));
820                         m.Statements.Add (MethodInvoke (PropRef (FieldRef (tableField), "Constraints"), "Add", Local ("uc")));
821                 }
822
823                 private void CreateForeignKeyStatements (CodeMemberMethod m,ForeignKeyConstraint fkc, string tableField, string rtableField)
824                 {
825                         ArrayList pcols = new ArrayList ();
826                         foreach (DataColumn col in fkc.RelatedColumns)
827                                 pcols.Add (IndexerRef (PropRef (FieldRef (rtableField), "Columns"), Const (col.ColumnName)));
828
829                         ArrayList ccols = new ArrayList ();
830                         foreach (DataColumn col in fkc.Columns)
831                                 ccols.Add (IndexerRef (PropRef (FieldRef (tableField), "Columns"), Const (col.ColumnName)));
832
833                         m.Statements.Add (Let (Local ("fkc"), New (
834                                 typeof (ForeignKeyConstraint),
835                                 Const (fkc.ConstraintName),
836                                 NewArray (
837                                         typeof (DataColumn),
838                                         pcols.ToArray (typeof (CodeExpression)) as CodeExpression []),
839                                 NewArray (
840                                         typeof (DataColumn),
841                                         ccols.ToArray (typeof (CodeExpression)) as CodeExpression []))));
842
843                         m.Statements.Add (Let (
844                                 PropRef (Local ("fkc"), "AcceptRejectRule"),
845                                 FieldRef (TypeRefExp (typeof (AcceptRejectRule)), Enum.GetName (typeof (AcceptRejectRule), fkc.AcceptRejectRule))));
846                         m.Statements.Add (Let (
847                                 PropRef (Local ("fkc"), "DeleteRule"),
848                                 FieldRef (TypeRefExp (typeof (Rule)), Enum.GetName (typeof (Rule), fkc.DeleteRule))));
849                         m.Statements.Add (Let (
850                                 PropRef (Local ("fkc"), "UpdateRule"),
851                                 FieldRef (TypeRefExp (typeof (Rule)), Enum.GetName (typeof (Rule), fkc.UpdateRule))));
852
853                         m.Statements.Add (MethodInvoke (PropRef (FieldRef (tableField), "Constraints"), "Add", Local ("fkc")));
854                 }
855
856                 private CodeMemberMethod CreateDataSetInitializeFields ()
857                 {
858                         CodeMemberMethod m = new CodeMemberMethod ();
859                         m.Attributes = MemberAttributes.Assembly;
860                         m.Name = "InitializeFields";
861
862                         foreach (DataTable dt in ds.Tables)
863                                 m.Statements.Add (Eval (MethodInvoke (FieldRef ("__table" + opts.TableMemberName (dt.TableName, gen)), "InitializeFields")));
864
865                         foreach (DataRelation rel in ds.Relations)
866                                 m.Statements.Add (Let (FieldRef ("__relation" + opts.RelationName (rel.RelationName, gen)), IndexerRef (PropRef ("Relations"), Const (rel.RelationName))));
867
868                         return m;
869                 }
870
871                 private CodeMemberMethod CreateDataSetSchemaChanged ()
872                 {
873                         CodeMemberMethod m = new CodeMemberMethod ();
874                         m.Name = "SchemaChanged";
875                         m.Parameters.Add (Param (typeof (object), "sender"));
876                         m.Parameters.Add (Param (typeof (CollectionChangeEventArgs), "e"));
877
878                         m.Statements.Add (
879                                 new CodeConditionStatement (
880                                         EqualsValue (
881                                                 PropRef (ParamRef ("e"), "Action"),
882                                                 FieldRef (TypeRefExp (typeof (CollectionChangeAction)), "Remove")),
883                                         new CodeStatement [] { Eval (MethodInvoke ("InitializeFields")) },
884                                         new CodeStatement [] {}));
885                         return m;
886                 }
887
888                 private void CreateDataSetTableMembers (CodeTypeDeclaration dsType, DataTable table)
889                 {
890                         string tableTypeName = opts.TableTypeName (table.TableName, gen);
891                         string tableVarName = opts.TableMemberName (table.TableName, gen);
892
893                         CodeMemberField privTable = new CodeMemberField ();
894                         privTable.Type = TypeRef (tableTypeName);
895                         privTable.Name = "__table" + tableVarName;
896                         dsType.Members.Add (privTable);
897
898                         CodeMemberProperty pubTable = new CodeMemberProperty ();
899                         pubTable.Type = TypeRef (tableTypeName);
900                         pubTable.Attributes = MemberAttributes.Public;
901                         pubTable.Name = tableVarName;
902                         pubTable.HasSet = false;
903                         // Code: return __table[foo];
904                         pubTable.GetStatements.Add (Return (FieldRef ("__table" + tableVarName)));
905
906                         dsType.Members.Add (pubTable);
907
908                 }
909
910                 private void CreateDataSetRelationMembers (CodeTypeDeclaration dsType, DataRelation relation)
911                 {
912                         string relName = opts.RelationName (relation.RelationName, gen);
913                         string fieldName = "__relation" + relName;
914
915                         CodeMemberField field = new CodeMemberField ();
916                         field.Type = TypeRef (typeof (DataRelation));
917                         field.Name = fieldName;
918                         dsType.Members.Add (field);
919
920                         // This is not supported in MS.NET
921                         CodeMemberProperty prop = new CodeMemberProperty ();
922                         prop.Type = TypeRef (typeof (DataRelation));
923                         prop.Attributes = MemberAttributes.Public;
924                         prop.Name = relName;
925                         prop.HasSet = false;
926                         // Code: return __relation[foo_bar];
927                         prop.GetStatements.Add (Return (FieldRef (fieldName)));
928                         dsType.Members.Add (prop);
929                 }
930
931 #endregion
932
933
934
935 #region DataTable class
936
937                 private CodeTypeDeclaration GenerateDataTableType (DataTable dt)
938                 {
939                         CodeTypeDeclaration t = new CodeTypeDeclaration ();
940                         t.Name = opts.TableTypeName (dt.TableName, gen);
941                         t.BaseTypes.Add (TypeRef (typeof (DataTable)));
942                         t.BaseTypes.Add (TypeRef (typeof (IEnumerable)));
943
944                         t.Members.Add (CreateTableCtor1 (dt));
945                         t.Members.Add (CreateTableCtor2 (dt));
946
947                         t.Members.Add (CreateTableCount (dt));
948                         t.Members.Add (CreateTableIndexer (dt));
949
950                         t.Members.Add (CreateTableInitializeClass (dt));
951                         t.Members.Add (CreateTableInitializeFields (dt));
952
953                         t.Members.Add (CreateTableGetEnumerator (dt));
954                         t.Members.Add (CreateTableClone (dt));
955                         t.Members.Add (CreateTableCreateInstance (dt));
956
957                         t.Members.Add (CreateTableAddRow1 (dt));
958                         t.Members.Add (CreateTableAddRow2 (dt));
959                         t.Members.Add (CreateTableNewRow (dt));
960                         t.Members.Add (CreateTableNewRowFromBuilder (dt));
961                         t.Members.Add (CreateTableRemoveRow (dt));
962                         t.Members.Add (CreateTableGetRowType (dt));
963
964                         t.Members.Add (CreateTableEventStarter (dt, "Changing"));
965                         t.Members.Add (CreateTableEventStarter (dt, "Changed"));
966                         t.Members.Add (CreateTableEventStarter (dt, "Deleting"));
967                         t.Members.Add (CreateTableEventStarter (dt, "Deleted"));
968
969                         // events
970                         t.Members.Add (CreateTableEvent (dt, "RowChanging"));
971                         t.Members.Add (CreateTableEvent (dt, "RowChanged"));
972                         t.Members.Add (CreateTableEvent (dt, "RowDeleting"));
973                         t.Members.Add (CreateTableEvent (dt, "RowDeleted"));
974
975                         // column members
976                         foreach (DataColumn col in dt.Columns) {
977                                 t.Members.Add (CreateTableColumnField (dt, col));
978                                 t.Members.Add (CreateTableColumnProperty (dt, col));
979                         }
980
981                         return t;
982                 }
983
984                 // Code:
985                 //  internal [foo]DataTable () : base ("[foo]")
986                 //  {
987                 //    InitializeClass ();
988                 //  }
989                 private CodeConstructor CreateTableCtor1 (DataTable dt)
990                 {
991                         CodeConstructor c = new CodeConstructor ();
992                         c.Attributes = MemberAttributes.Assembly;
993                         c.BaseConstructorArgs.Add (Const (dt.TableName));
994                         c.Statements.Add (Eval (MethodInvoke ("InitializeClass")));
995                         c.Statements.Add (Eval (MethodInvoke ("InitializeFields")));
996                         return c;
997                 }
998
999                 // Code:
1000                 //  internal [foo]DataTable (DataTable table) : base (table.TableName)
1001                 //  {
1002                 //    // TODO: implement
1003                 //    throw new NotImplementedException ();
1004                 //  }
1005                 private CodeConstructor CreateTableCtor2 (DataTable dt)
1006                 {
1007                         CodeConstructor c = new CodeConstructor ();
1008                         c.Attributes = MemberAttributes.Assembly;
1009                         c.Parameters.Add (Param (typeof (DataTable), GetRowTableFieldName (dt)));
1010                         c.BaseConstructorArgs.Add (PropRef (ParamRef (GetRowTableFieldName (dt)), "TableName"));
1011                         // TODO: implement
1012                         c.Statements.Add (Comment ("TODO: implement"));
1013                         c.Statements.Add (Throw (New (typeof (NotImplementedException))));
1014                         return c;
1015                 }
1016
1017                 private CodeMemberMethod CreateTableInitializeClass (DataTable dt)
1018                 {
1019                         CodeMemberMethod m = new CodeMemberMethod ();
1020                         m.Name = "InitializeClass";
1021                         foreach (DataColumn col in dt.Columns) {
1022                                 m.Statements.Add (Eval (MethodInvoke (
1023                                         PropRef ("Columns"),
1024                                         "Add",
1025                                         New (typeof (DataColumn),
1026                                                 Const (col.ColumnName),
1027                                                 new CodeTypeOfExpression (col.DataType)
1028                                                 ))));
1029                         }
1030                         return m;
1031                 }
1032
1033                 private CodeMemberMethod CreateTableInitializeFields (DataTable dt)
1034                 {
1035                         CodeMemberMethod m = new CodeMemberMethod ();
1036                         m.Name = "InitializeFields";
1037                         m.Attributes = MemberAttributes.Assembly;
1038
1039                         string colRef;
1040                         foreach (DataColumn col in dt.Columns) {
1041                                 colRef = String.Format("__column{0}", opts.TableColName (col.ColumnName, gen));
1042
1043                                 m.Statements.Add (Let (FieldRef (colRef), IndexerRef (PropRef ("Columns"), Const (col.ColumnName))));
1044                                 if (!col.AllowDBNull)
1045                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "AllowDBNull"), Const (col.AllowDBNull)));
1046                                 if (col.DefaultValue != null && col.DefaultValue.GetType() != typeof(System.DBNull))
1047                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "DefaultValue"), Const (col.DefaultValue)));
1048                                 if (col.AutoIncrement)
1049                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "AutoIncrement"), Const (col.AutoIncrement)));
1050                                 if (col.AutoIncrementSeed != 0)
1051                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "AutoIncrementSeed"), Const (col.AutoIncrementSeed)));
1052                                 if (col.AutoIncrementStep != 1)
1053                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "AutoIncrementStep"), Const (col.AutoIncrementStep)));
1054                                 if (col.ReadOnly)
1055                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "ReadOnly"), Const (col.ReadOnly)));
1056                         }
1057                         return m;
1058                 }
1059
1060                 private CodeMemberMethod CreateTableClone (DataTable dt)
1061                 {
1062                         CodeMemberMethod m = new CodeMemberMethod ();
1063                         m.Name = "Clone";
1064                         m.Attributes = MemberAttributes.Public | MemberAttributes.Override;
1065                         m.ReturnType = TypeRef (typeof (DataTable));
1066                         string typeName = opts.TableTypeName (dt.TableName, gen);
1067                         m.Statements.Add (
1068                                 VarDecl (typeName, "t", Cast (typeName, MethodInvoke (Base (), "Clone"))));
1069                         m.Statements.Add (Eval (MethodInvoke (Local ("t"), "InitializeFields")));
1070                         m.Statements.Add (Return (Local ("t")));
1071                         return m;
1072                 }
1073
1074                 private CodeMemberMethod CreateTableGetEnumerator (DataTable dt)
1075                 {
1076                         CodeMemberMethod m = new CodeMemberMethod ();
1077                         m.Name = "GetEnumerator";
1078                         m.Attributes = MemberAttributes.Public;
1079                         m.ReturnType = TypeRef (typeof (IEnumerator));
1080                         m.Statements.Add (Return (MethodInvoke (PropRef ("Rows"), "GetEnumerator")));
1081                         m.ImplementationTypes.Add (TypeRef (typeof (IEnumerable)));
1082                         return m;
1083                 }
1084
1085                 private CodeMemberMethod CreateTableCreateInstance (DataTable dt)
1086                 {
1087                         CodeMemberMethod m = new CodeMemberMethod ();
1088                         m.Name = "CreateInstance";
1089                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1090                         m.ReturnType = TypeRef (typeof (DataTable));
1091                         m.Statements.Add (Return (New (opts.TableTypeName (dt.TableName, gen))));
1092                         return m;
1093                 }
1094
1095                 private CodeMemberField CreateTableColumnField (DataTable dt, DataColumn col)
1096                 {
1097                         CodeMemberField f = new CodeMemberField ();
1098                         f.Name = "__column" + opts.ColumnName (col.ColumnName, gen);
1099                         f.Type = TypeRef (typeof (DataColumn));
1100                         return f;
1101                 }
1102
1103                 private CodeMemberProperty CreateTableColumnProperty (DataTable dt, DataColumn col)
1104                 {
1105                         string name = opts.ColumnName (col.ColumnName, gen);
1106                         CodeMemberProperty p = new CodeMemberProperty ();
1107                         p.Name = name + "Column";
1108                         p.Attributes = MemberAttributes.Assembly;
1109                         p.Type = TypeRef (typeof (DataColumn));
1110                         p.HasSet = false;
1111                         p.GetStatements.Add (Return (FieldRef ("__column" + name)));
1112                         return p;
1113                 }
1114
1115                 private CodeMemberProperty CreateTableCount (DataTable dt)
1116                 {
1117                         CodeMemberProperty p = new CodeMemberProperty ();
1118                         p.Name = "Count";
1119                         p.Attributes = MemberAttributes.Public;
1120                         p.Type = TypeRef (typeof (int));
1121                         p.HasSet = false;
1122                         p.GetStatements.Add (Return (PropRef (PropRef ("Rows"), "Count")));
1123                         return p;
1124                 }
1125
1126                 private CodeMemberProperty CreateTableIndexer (DataTable dt)
1127                 {
1128                         string rowName = opts.RowName (dt.TableName, gen);
1129                         CodeMemberProperty ix = new CodeMemberProperty ();
1130                         ix.Name = "Item"; // indexer
1131                         ix.Attributes = MemberAttributes.Public;
1132                         ix.Type = TypeRef (rowName);
1133                         ix.Parameters.Add (Param (typeof (int), "i"));
1134                         ix.HasSet = false;
1135                         ix.GetStatements.Add (Return (Cast (rowName, IndexerRef (PropRef ("Rows"), ParamRef ("i")))));
1136                         return ix;
1137                 }
1138
1139                 private CodeMemberMethod CreateTableAddRow1 (DataTable dt)
1140                 {
1141                         CodeMemberMethod m = new CodeMemberMethod ();
1142                         string rowType = opts.RowName (dt.TableName, gen);
1143                         m.Name = "Add" + rowType;
1144                         m.Attributes = MemberAttributes.Public;
1145                         m.Parameters.Add (Param (TypeRef (rowType), "row"));
1146                         m.Statements.Add (Eval (MethodInvoke (PropRef ("Rows"), "Add", ParamRef ("row"))));
1147                         return m;
1148                 }
1149
1150                 private CodeMemberMethod CreateTableAddRow2 (DataTable dt)
1151                 {
1152                         CodeMemberMethod m = new CodeMemberMethod ();
1153                         string rowType = opts.RowName (dt.TableName, gen);
1154                         m.Name = "Add" + rowType;
1155                         m.ReturnType = TypeRef (rowType);
1156                         m.Attributes = MemberAttributes.Public;
1157
1158                         m.Statements.Add (VarDecl (rowType, "row", MethodInvoke ("New" + rowType)));
1159
1160                         foreach (DataColumn col in dt.Columns) {
1161                                 if (col.ColumnMapping == MappingType.Hidden) {
1162                                         foreach (DataRelation r in dt.DataSet.Relations) {
1163                                                 if (r.ChildTable == dt) {
1164                                                         // parameter
1165                                                         string paramType = opts.RowName (r.ParentTable.TableName, gen);
1166                                                         string paramName = paramType;
1167                                                         m.Parameters.Add (Param (paramType, paramName));
1168                                                         // CODE: SetParentRow (fooRow, DataSet.Relations ["foo_bar"]);
1169                                                         m.Statements.Add (Eval (MethodInvoke (Local ("row"), "SetParentRow", ParamRef (paramName), IndexerRef (PropRef (PropRef ("DataSet"), "Relations"), Const (r.RelationName)))));
1170                                                         break;
1171                                                 }
1172                                         }
1173                                 }
1174                                 else {
1175                                         // parameter
1176                                         string paramName = opts.ColumnName (col.ColumnName, gen);
1177                                         m.Parameters.Add (Param (col.DataType, paramName));
1178                                         // row ["foo"] = foo;
1179                                         m.Statements.Add (Let (IndexerRef (Local ("row"), Const (paramName)), ParamRef (paramName)));
1180                                 }
1181                         }
1182
1183                         // Rows.Add (row);
1184                         m.Statements.Add (MethodInvoke (PropRef ("Rows"), "Add", Local ("row")));
1185                         m.Statements.Add (Return (Local ("row")));
1186
1187                         return m;
1188                 }
1189
1190                 private CodeMemberMethod CreateTableNewRow (DataTable dt)
1191                 {
1192                         CodeMemberMethod m = new CodeMemberMethod ();
1193                         string rowType = opts.RowName (dt.TableName, gen);
1194                         m.Name = "New" + rowType;
1195                         m.ReturnType = TypeRef (rowType);
1196                         m.Attributes = MemberAttributes.Public;
1197                         m.Statements.Add (Return (Cast (rowType, MethodInvoke ("NewRow"))));
1198                         return m;
1199                 }
1200
1201                 private CodeMemberMethod CreateTableNewRowFromBuilder (DataTable dt)
1202                 {
1203                         CodeMemberMethod m = new CodeMemberMethod ();
1204                         m.Name = "NewRowFromBuilder";
1205                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1206                         m.ReturnType = TypeRef (typeof (DataRow));
1207                         m.Parameters.Add (Param (typeof (DataRowBuilder), "builder"));
1208                         m.Statements.Add (Return (New (opts.RowName (dt.TableName, gen), ParamRef ("builder"))));
1209                         return m;
1210                 }
1211
1212                 private CodeMemberMethod CreateTableRemoveRow (DataTable dt)
1213                 {
1214                         CodeMemberMethod m = new CodeMemberMethod ();
1215                         string rowType = opts.RowName (dt.TableName, gen);
1216                         m.Name = "Remove" + rowType;
1217                         m.Attributes = MemberAttributes.Public;
1218                         m.Parameters.Add (Param (TypeRef (rowType), "row"));
1219                         m.Statements.Add (Eval (MethodInvoke (PropRef ("Rows"), "Remove", ParamRef ("row"))));
1220                         return m;
1221                 }
1222
1223                 private CodeMemberMethod CreateTableGetRowType (DataTable dt)
1224                 {
1225                         CodeMemberMethod m = new CodeMemberMethod ();
1226                         m.Name = "GetRowType";
1227                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1228                         m.ReturnType = TypeRef (typeof (Type));
1229                         m.Statements.Add (Return (new CodeTypeOfExpression (opts.RowName (dt.TableName, gen))));
1230                         return m;
1231                 }
1232
1233                 private CodeMemberMethod CreateTableEventStarter (DataTable dt, string type)
1234                 {
1235                         CodeMemberMethod m = new CodeMemberMethod ();
1236                         m.Name = "OnRow" + type;
1237                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1238                         m.Parameters.Add (Param (typeof (DataRowChangeEventArgs), "e"));
1239
1240                         m.Statements.Add (Eval (MethodInvoke (
1241                                         Base (),
1242                                         m.Name,
1243                                         ParamRef ("e"))));
1244                         string eventName = opts.TableMemberName (dt.TableName, gen) + "Row" + type;
1245                         CodeStatement trueStmt = Eval (
1246                                 new CodeDelegateInvokeExpression(
1247                                         new CodeEventReferenceExpression (This (), eventName),
1248                                         This (), 
1249                                         New (
1250                                                 opts.EventArgsName (dt.TableName, gen),
1251                                                 Cast (opts.RowName (dt.TableName, gen), PropRef (ParamRef ("e"), "Row")),
1252                                                 PropRef (ParamRef ("e"), "Action"))));
1253
1254                         m.Statements.Add (
1255                                 new CodeConditionStatement (
1256                                         Inequals (EventRef (eventName), Const (null)),
1257                                         new CodeStatement [] {trueStmt},
1258                                         new CodeStatement [] {}));
1259
1260                         return m;
1261                 }
1262
1263                 private CodeMemberEvent CreateTableEvent (DataTable dt, string nameSuffix)
1264                 {
1265                         CodeMemberEvent cme = new CodeMemberEvent ();
1266                         cme.Attributes = MemberAttributes.Public;
1267                         cme.Name = opts.TableMemberName (dt.TableName, gen) + nameSuffix;
1268                         cme.Type = TypeRef (opts.TableDelegateName (dt.TableName, gen));
1269                         return cme;
1270                 }
1271
1272 #endregion
1273
1274
1275
1276 #region Row class
1277
1278                 public CodeTypeDeclaration GenerateDataRowType (DataTable dt)
1279                 {
1280                         CodeTypeDeclaration t = new CodeTypeDeclaration ();
1281                         t.Name = opts.RowName (dt.TableName, gen);
1282                         t.BaseTypes.Add (TypeRef (typeof (DataRow)));
1283
1284                         t.Members.Add (CreateRowCtor (dt));
1285
1286                         t.Members.Add (CreateRowTableField (dt));
1287
1288                         foreach (DataColumn col in dt.Columns) {
1289                                 if (col.ColumnMapping != MappingType.Hidden) {
1290                                         t.Members.Add (CreateRowColumnProperty (dt, col));
1291                                         t.Members.Add (CreateRowColumnIsNull (dt, col));
1292                                         t.Members.Add (CreateRowColumnSetNull (dt, col));
1293                                 }
1294                         }
1295
1296                         foreach (DataRelation rel in dt.ParentRelations)
1297                                 t.Members.Add (CreateRowParentRowProperty (dt, rel));
1298                         foreach (DataRelation rel in dt.ChildRelations)
1299                                 t.Members.Add (CreateRowGetChildRows (dt, rel));
1300
1301                         return t;
1302                 }
1303
1304                 private CodeConstructor CreateRowCtor (DataTable dt)
1305                 {
1306                         CodeConstructor c = new CodeConstructor ();
1307                         c.Attributes = MemberAttributes.Assembly;
1308                         c.Parameters.Add (Param (typeof (DataRowBuilder), "builder"));
1309                         c.BaseConstructorArgs.Add (ParamRef ("builder"));
1310                         c.Statements.Add (Let (FieldRef (GetRowTableFieldName (dt)), Cast (
1311                                 opts.TableTypeName (dt.TableName, gen),
1312                                 PropRef ("Table"))));
1313                         return c;
1314                 }
1315                 
1316                 private string GetRowTableFieldName (DataTable dt)
1317                 {
1318                         return "table" + dt.TableName;
1319                 }
1320                 private CodeMemberField CreateRowTableField (DataTable dt)
1321                 {
1322                         CodeMemberField f = new CodeMemberField ();
1323                         f.Name = GetRowTableFieldName (dt);
1324                         f.Type = TypeRef (opts.TableTypeName (dt.TableName, gen));
1325                         return f;
1326                 }
1327
1328                 private CodeMemberProperty CreateRowColumnProperty (DataTable dt, DataColumn col)
1329                 {
1330                         CodeMemberProperty p = new CodeMemberProperty ();
1331                         p.Name = opts.ColumnName (col.ColumnName, gen);
1332                         p.Type = TypeRef (col.DataType);
1333                         p.Attributes = MemberAttributes.Public;
1334
1335                         // This part should be better than MS code output.
1336                         // Code:
1337                         //  object ret = this [col];
1338                         //  if (ret == DBNull.Value)
1339                         //    throw new StrongTypingException ()
1340                         //  else
1341                         //    return (type) ret;
1342                         p.GetStatements.Add (VarDecl (typeof (object), "ret",
1343                                 IndexerRef (PropRef 
1344                                         (PropRef (GetRowTableFieldName (dt)), 
1345                                         opts.TableColName (col.ColumnName, gen) + "Column"))));
1346                         p.GetStatements.Add (new CodeConditionStatement (
1347                                 Equals (
1348                                         Local ("ret"),
1349                                         PropRef (TypeRefExp (typeof (DBNull)), "Value")),
1350                                 new CodeStatement [] {
1351                                         Throw (New (typeof (StrongTypingException), Const ("Cannot get strong typed value since it is DB null."), Const (null))) },
1352                                 new CodeStatement [] {
1353                                         Return (Cast (col.DataType, Local ("ret"))) }));
1354
1355                         p.SetStatements.Add (Let (IndexerRef (PropRef (PropRef (GetRowTableFieldName (dt)), opts.TableColName (col.ColumnName, gen) + "Column")), new CodePropertySetValueReferenceExpression ()));
1356
1357                         return p;
1358                 }
1359
1360                 private CodeMemberMethod CreateRowColumnIsNull (DataTable dt, DataColumn col)
1361                 {
1362                         CodeMemberMethod m = new CodeMemberMethod ();
1363                         m.Name = "Is" + opts.ColumnName (col.ColumnName, gen) + "Null";
1364                         m.Attributes = MemberAttributes.Public;
1365                         m.ReturnType = TypeRef (typeof (bool));
1366                         m.Statements.Add (Return (MethodInvoke (
1367                                 "IsNull",
1368                                 // table[foo].[bar]Column
1369                                 PropRef (
1370                                         PropRef (GetRowTableFieldName (dt)), 
1371                                         opts.TableColName (col.ColumnName, gen) + "Column"))));
1372                         return m;
1373                 }
1374
1375                 private CodeMemberMethod CreateRowColumnSetNull (DataTable dt, DataColumn col)
1376                 {
1377                         CodeMemberMethod m = new CodeMemberMethod ();
1378                         m.Name = "Set" + opts.ColumnName (col.ColumnName, gen) + "Null";
1379                         m.Attributes = MemberAttributes.Public;
1380                         m.Statements.Add (Let (IndexerRef (
1381                                 PropRef (
1382                                         PropRef (GetRowTableFieldName (dt)), 
1383                                         opts.TableColName (col.ColumnName, gen) + "Column")),
1384                                 PropRef (TypeRefExp (typeof (DBNull)), "Value")));
1385
1386                         return m;
1387                 }
1388
1389                 private CodeMemberProperty CreateRowParentRowProperty (DataTable dt, DataRelation rel)
1390                 {
1391                         CodeMemberProperty p = new CodeMemberProperty ();
1392                         p.Name = opts.TableMemberName (rel.ParentTable.TableName, gen) + "Row" +
1393                                 (rel.ParentTable.TableName == rel.ChildTable.TableName ? "Parent" : String.Empty);
1394                         p.Attributes = MemberAttributes.Public;
1395                         p.Type = TypeRef (opts.RowName (rel.ParentTable.TableName, gen));
1396                         p.GetStatements.Add (Return (Cast (p.Type, MethodInvoke (
1397                                 "GetParentRow",
1398                                 IndexerRef (
1399                                         PropRef (
1400                                                 PropRef (
1401                                                         PropRef ("Table"),
1402                                                         "DataSet"),
1403                                                 "Relations"),
1404                                         Const (rel.RelationName))))));
1405                         p.SetStatements.Add (Eval (MethodInvoke (
1406                                 "SetParentRow",
1407                                 new CodePropertySetValueReferenceExpression (),
1408                                 IndexerRef (
1409                                         PropRef (
1410                                                 PropRef (
1411                                                         PropRef ("Table"),
1412                                                         "DataSet"),
1413                                                 "Relations"),
1414                                         Const (rel.RelationName)))));
1415
1416                         return p;
1417                 }
1418
1419                 private CodeMemberMethod CreateRowGetChildRows (DataTable dt, DataRelation rel)
1420                 {
1421                         CodeMemberMethod m = new CodeMemberMethod ();
1422                         m.Name = "Get" + opts.TableMemberName (rel.ChildTable.TableName, gen) + "Rows";
1423                         m.Attributes = MemberAttributes.Public;
1424                         m.ReturnType = new CodeTypeReference (opts.RowName (rel.ChildTable.TableName, gen), 1);
1425                         m.Statements.Add (Return (Cast (m.ReturnType, MethodInvoke (
1426                                 "GetChildRows",
1427                                 IndexerRef (
1428                                         PropRef (
1429                                                 PropRef (
1430                                                         PropRef ("Table"),
1431                                                         "DataSet"),
1432                                                 "Relations"),
1433                                         Const (rel.RelationName))))));
1434                         return m;
1435                 }
1436
1437 #endregion
1438
1439
1440 #region Event class
1441
1442                 // Code:
1443                 //  public class [foo]ChangeEventArgs : EventArgs
1444                 //  {
1445                 //    private [foo]Row eventRow;
1446                 //    private DataRowAction eventAction;
1447                 //    (.ctor())
1448                 //    (Row)
1449                 //    (Action)
1450                 //  }
1451                 private CodeTypeDeclaration GenerateEventType (DataTable dt)
1452                 {
1453                         CodeTypeDeclaration t = new CodeTypeDeclaration ();
1454                         t.Name = opts.EventArgsName (dt.TableName, gen);
1455                         t.BaseTypes.Add (TypeRef (typeof (EventArgs)));
1456                         t.Attributes = MemberAttributes.Public;
1457
1458                         t.Members.Add (
1459                                 new CodeMemberField (
1460                                         TypeRef (opts.RowName (dt.TableName, gen)),
1461                                         "eventRow"));
1462                         t.Members.Add (
1463                                 new CodeMemberField (
1464                                         TypeRef (typeof (DataRowAction)), "eventAction"));
1465                         t.Members.Add (CreateEventCtor (dt));
1466
1467                         t.Members.Add (CreateEventRow (dt));
1468
1469                         t.Members.Add (CreateEventAction (dt));
1470
1471                         return t;
1472                 }
1473
1474                 // Code:
1475                 //  public [foo]RowChangeEventArgs ([foo]Row r, DataRowAction a)
1476                 //  {
1477                 //    eventRow = r;
1478                 //    eventAction = a;
1479                 //  }
1480                 private CodeConstructor CreateEventCtor (DataTable dt)
1481                 {
1482                         CodeConstructor c = new CodeConstructor ();
1483                         c.Attributes = MemberAttributes.Public;
1484                         c.Parameters.Add (Param (TypeRef (opts.RowName (dt.TableName, gen)), "r"));
1485                         c.Parameters.Add (Param (TypeRef (typeof (DataRowAction)), "a"));
1486                         c.Statements.Add (Let (FieldRef ("eventRow"), ParamRef ("r")));
1487                         c.Statements.Add (Let (FieldRef ("eventAction"), ParamRef ("a")));
1488
1489                         return c;
1490                 }
1491
1492                 // Code:
1493                 //  public [foo]Row Row {
1494                 //   get { return eventRow; }
1495                 // }
1496                 private CodeMemberProperty CreateEventRow (DataTable dt)
1497                 {
1498                         CodeMemberProperty p = new CodeMemberProperty ();
1499                         p.Name = "Row";
1500                         p.Attributes = MemberAttributes.Public | MemberAttributes.Final;
1501                         p.Type = TypeRef (opts.RowName (dt.TableName, gen));
1502                         p.HasSet = false;
1503                         p.GetStatements.Add (Return (FieldRef ("eventRow")));
1504                         return p;
1505                 }
1506
1507                 // Code:
1508                 //  public DataRowAction Action {
1509                 //   get { return eventAction; }
1510                 // }
1511                 private CodeMemberProperty CreateEventAction (DataTable dt)
1512                 {
1513                         CodeMemberProperty p = new CodeMemberProperty ();
1514                         p.Name = "Action";
1515                         p.Attributes = MemberAttributes.Public | MemberAttributes.Final;
1516                         p.Type = TypeRef (typeof (DataRowAction));
1517                         p.HasSet = false;
1518                         p.GetStatements.Add (Return (FieldRef ("eventAction")));
1519                         return p;
1520                 }
1521
1522 #endregion
1523
1524         }
1525 }
1526
1527
1528 /* =========================================================
1529
1530
1531 MonoDataSetGenerator API notes
1532
1533
1534 ** generator API:
1535         CreateDataSetClasses (
1536                 DataSet ds,
1537                 CodeNamespace cns,
1538                 ICodeGenerator gen,
1539                 GeneratorOptions options)
1540
1541 ** classes:
1542
1543 *** Code naming method delegate
1544
1545         public delegate string CodeNamingMethod (string sourceName);
1546
1547         It is used in CodeGeneratorOptions (describled immediately below).
1548
1549
1550
1551 *** Generator Options
1552
1553         public bool MakeClassesInsideDataSet
1554                 indicates whether classes and delegates other than DataSet
1555                 itself are "contained" in the DataSet class or not.
1556
1557         public CodeNamingMethod CreateDataSetName;
1558         public CodeNamingMethod CreateTableTypeName;
1559         public CodeNamingMethod CreateTableMemberName;
1560         public CodeNamingMethod CreateColumnName;
1561         public CodeNamingMethod CreateRowName;
1562         public CodeNamingMethod CreateRelationName;
1563         public CodeNamingMethod CreateTableDelegateName;
1564         public CodeNamingMethod CreateEventArgsName;
1565                 Custom methods each of that returns type or member name.
1566
1567                 By default, they are set as to useTypedDataSetGenerator.
1568                 CreateIdName() with modifications listed as below:
1569
1570                 DataSetName: as is
1571                 TableTypeName: "DataTable" suffix
1572                 TableMemberName: as is
1573                 ColumnName: as is
1574                 RowName: "Row" suffix
1575                 RelationName: (TBD; maybe had better have another delegate type)
1576                 DelegateName: "RowChangedEventHandler" suffix
1577                 EventArgsName: "RowChangedEventArgs" suffix
1578
1579 ** Auto Generated classes
1580
1581 1. Custom DataSet class 
1582
1583         class name = dataset name, encoded by options.CreateDataSetName().
1584
1585 *** .ctor
1586
1587         public default .ctor()
1588                 "initialize" class.
1589                 set custom delegate on Tables.CollectionChanged
1590                 set custom delegate on Relations.CollectionChanged
1591
1592         runtime serialization .ctor()
1593                 TBD
1594
1595 *** public members
1596
1597         data tables: [foo]DataTable foo { return this.table[foo]; }
1598
1599         Clone()
1600                 init variables on new dataset.
1601
1602 *** protected members
1603
1604         ShouldSerializeTables()
1605                 returns false, while default DataSet returns true.
1606         ShouldSerializeRelations()
1607                 returns false, while default DataSet returns true.
1608
1609         ReadXmlSerializable() ... similar to runtime serialization
1610                 TBD
1611
1612         GetSchemaSerializable()
1613                 Write its schema to temporary MemoryStream
1614                 Read XML schema from the stream
1615
1616 *** internal members
1617
1618         "init variables"
1619                 set member fields (tables, relations)
1620                 call members' "init variables"
1621
1622         "init class"
1623                 set DataSetName, Prefix, Namespace, Locale, CaseSensitive, EnforceConstraints
1624                 for each table
1625                         allocate table[foo] 
1626                         Tables.Add() 
1627                         create FKC: new FKC([rel], new DataColumn [] {table[foo].[keyColumnName]Column}, new DataColumn [] {table[child].[childColName]Column}
1628                 fill Rule properties.
1629                 allocate relation[rel] and fill Nested, then Relations.Add()
1630
1631 *** private members
1632
1633         data tables: [foo]DataTable table[foo];
1634
1635         data relations: DataRelation relation[rel];
1636
1637         ShouldSerialize[foo]
1638
1639
1640
1641 2. Custom DataTable classes for each DataTable
1642
1643         This class is created under the dataset.
1644
1645 *** internal members
1646
1647         .ctor() : base("[foo]")
1648                 initialize class
1649
1650         .ctor(DataTable)
1651                 wtf?
1652
1653         DataColumn [bar]Column { return column[bar]; }
1654
1655         "init variables"()
1656                 fill each column fields
1657
1658 *** public members
1659
1660         int Count { rowcount }
1661
1662         this [int index] { row [i]; }
1663
1664         event [foo]RowChangedEventHandler [foo]RowChanged
1665         event [foo]RowChangedEventHandler [foo]RowChanging
1666         event [foo]RowChangedEventHandler [foo]RowDeleted
1667         event [foo]RowChangedEventHandler [foo]RowDeleting
1668
1669         void Add[foo]Row ([foo]Row row) { Rows.Add (row); }
1670
1671         [foo]Row Add[foo]Row ([columnType] [columnName])
1672                 create new [foo]row.
1673                 set members
1674                 Rows.Add ()
1675                 // where
1676                 //      non-relation-children are just created as column type
1677                 //      relation-children are typeof fooRow[]
1678
1679         GetEnumerator() { Rows.GetEnumerator (); }
1680
1681         override DataTable Clone()
1682                 "init variables"
1683
1684         [foo]Row New[foo]Row()
1685
1686         void Remove[foo]Row([foo]Row)
1687
1688         //for each ChildRelations
1689         [bar]Row [] Get[foo_bar]Rows ()
1690
1691 *** protected members
1692
1693         override DataTable CreateInstance() { return new }
1694
1695         override DataRow NewRowFromBuilder(DataRowBuilder)
1696
1697         override Type GetRowType()
1698
1699         override void OnRowChanged(DataRowChangedEventArgs)
1700                 base.()
1701                 check this event [foo]RowChanged.
1702
1703         override void OnRowChanging(DataRowChangedEventArgs)
1704         override void OnRowDeleted(DataRowChangedEventArgs)
1705         override void OnRowDeleting(DataRowChangedEventArgs)
1706         ... as well
1707
1708 *** private members
1709
1710         "initialize class"
1711                 for each columns {
1712                         column[bar] = new DataColumn (...);
1713                         Columns.Add()
1714                 }
1715
1716         DataColumn [bar]Column
1717
1718 3. Custom DataRow classses
1719
1720 *** public members
1721
1722         for simple members:
1723
1724                 [bar_type] [bar] {
1725                         get { try { } catch { throw StrongTypingException(); }
1726                         set { this [[foo]Table.[bar]Column] = value; }
1727
1728                 bool Is[bar]Null ()
1729                         IsNull ([foo]Table.[bar]Column);
1730
1731                 void Set[bar]Null ()
1732
1733         if the table is parent of some relations
1734
1735                 public [child]Row [] Get[child]Rows()
1736
1737 *** internal members
1738
1739         .ctor(DataRowBuilder) : base.()
1740                 table[foo] = Table;
1741
1742 *** private members
1743
1744         [foo]DataTable table[foo]
1745
1746
1747 4. Custom DataRowChangeEvent classes
1748
1749 *** private members
1750
1751         [foo]Row eventRow
1752         DataRowAction eventAction
1753
1754 *** public members
1755
1756         .ctor([foo]Row row, DataRowAction action)
1757
1758         [foo]Row Row
1759
1760         DataRowAction Action
1761
1762
1763
1764 5. public Table RowChangedEventHandler delegates
1765
1766         [foo]RowChangedEventHandler(object, [foo]RowChangedEvent e)
1767
1768
1769 ======================================================== */