Drop of Mainsoft.System.Data
[mono.git] / mcs / class / System.Data / System.Data / DataColumnCollection.cs
index 9e7fae7704dd30dbca8311bb969d73a6c1d69537..5c8bae2d75445c85b857986ab396b34d68a1683d 100644 (file)
@@ -4,32 +4,61 @@
 // Author:
 //   Christopher Podurgiel (cpodurgiel@msn.com)
 //   Stuart Caborn     <stuart.caborn@virgin.net>
+//   Tim Coleman (tim@timcoleman.com)
 //
 // (C) Chris Podurgiel
+// Copyright (C) Tim Coleman, 2002
+// Copyright (C) Daniel Morgan, 2003
+//
+
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
 using System;
 using System.Collections;
 using System.ComponentModel;
 
-namespace System.Data
-{
-       /// <summary>
-       /// Represents a collection of DataColumn objects for a DataTable.
-       /// </summary>
+namespace System.Data {
+       [Editor]
        [Serializable]
+       [DefaultEvent ("CollectionChanged")]
        public class DataColumnCollection : InternalDataCollectionBase
        {
-               // The defaultNameIndex is used to create a default name for a column if one wasn't given.
-               private int defaultNameIndex;
-
+               //This hashtable maps between column name to DataColumn object.
+               private Hashtable columnFromName = new Hashtable();
+               //This ArrayList contains the auto-increment columns names
+               private ArrayList autoIncrement = new ArrayList();
+               //This holds the next index to use for default column name.
+               private int defaultColumnIndex = 1;
                //table should be the DataTable this DataColumnCollection belongs to.
                private DataTable parentTable = null;
+               // Keep reference to most recent columns passed to AddRange()
+               // so that they can be added when EndInit() is called.
+               DataColumn[] _mostRecentColumns = null;
 
                // Internal Constructor.  This Class can only be created from other classes in this assembly.
                internal DataColumnCollection(DataTable table):base()
                {
-                       defaultNameIndex = 1;
                        parentTable = table;
                }
 
@@ -40,6 +69,9 @@ namespace System.Data
                {
                        get
                        {
+                               if (index < 0 || index > base.List.Count) {
+                                       throw new IndexOutOfRangeException("Cannot find column " + index + ".");
+                               }
                                return (DataColumn) base.List[index];
                        }
                }
@@ -51,21 +83,22 @@ namespace System.Data
                {
                        get
                        {
-                               foreach (DataColumn column in base.List)
-                               {
-                                       if (column.ColumnName == name)
-                                       {
-                                               return column;
-                                       }
-                               }
-                               return null;                
+                               DataColumn dc = columnFromName[name] as DataColumn;
+                               
+                               if (dc != null)
+                                       return dc;
+
+                               int tmp = IndexOf(name, true);
+                               if (tmp == -1)
+                                       return null;
+                               return this[tmp]; 
                        }
                }
 
                /// <summary>
                /// Gets a list of the DataColumnCollection items.
                /// </summary>
-               protected internal override ArrayList List 
+               protected override ArrayList List 
                {
                        get
                        {
@@ -73,6 +106,14 @@ namespace System.Data
                        }
                }
 
+               internal ArrayList AutoIncrmentColumns 
+               {
+                       get
+                       {
+                               return autoIncrement;
+                       }
+               }
+
                //Add Logic
                //
                //Changing Event
@@ -91,49 +132,109 @@ namespace System.Data
                /// <returns></returns>
                public virtual DataColumn Add()
                {
-                       //FIXME:
-                       DataColumn column = new DataColumn("Column" + defaultNameIndex.ToString());
-                       CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
-                       
-                       column.SetTable(parentTable);
-                       base.List.Add(column);
-                       OnCollectionChanged(e);
-                       defaultNameIndex++;
+                       string defaultName = GetNextDefaultColumnName ();
+                       DataColumn column = new DataColumn (defaultName);
+                       Add (column);
                        return column;
                }
 
+               internal void RegisterName(string name, DataColumn column)
+               {
+                       if (columnFromName.Contains(name))
+                               throw new DuplicateNameException("A DataColumn named '" + name + "' already belongs to this DataTable.");
+
+                       columnFromName[name] = column;
+
+                       if (name.StartsWith("Column") && name == MakeName(defaultColumnIndex + 1))
+                       {
+                               do
+                               {
+                                       defaultColumnIndex++;
+                               }
+                               while (Contains(MakeName(defaultColumnIndex + 1)));
+                       }
+               }
+
+               internal void UnregisterName(string name)
+               {
+                       if (columnFromName.Contains(name))
+                               columnFromName.Remove(name);
+
+                       if (name.StartsWith("Column") && name == MakeName(defaultColumnIndex - 1))
+                       {
+                               do
+                               {
+                                       defaultColumnIndex--;
+                               }
+                               while (!Contains(MakeName(defaultColumnIndex - 1)) && defaultColumnIndex > 1);
+                       }
+               }
+
+               private string GetNextDefaultColumnName ()
+               {
+                       string defColumnName = MakeName(defaultColumnIndex);
+                       for (int index = defaultColumnIndex + 1; Contains(defColumnName); ++index) {
+                               defColumnName = MakeName(index);
+                               defaultColumnIndex++;
+                       }
+                       defaultColumnIndex++;
+                       return defColumnName;
+               }
+
+               static readonly string[] TenColumns = { "Column0", "Column1", "Column2", "Column3", "Column4", "Column5", "Column6", "Column7", "Column8", "Column9" };
+
+               private string MakeName(int index)
+               {
+                       if (index < 10)
+                               return TenColumns[index];
+
+                       return String.Concat("Column", index.ToString());
+               }
+
                /// <summary>
                /// Creates and adds the specified DataColumn object to the DataColumnCollection.
                /// </summary>
                /// <param name="column">The DataColumn to add.</param>
-               [MonoTODO]
                public void Add(DataColumn column)
-               {       
-                       //FIXME:
-                       if(Contains(column.ColumnName))
+               {
+
+                       if (column == null)
+                               throw new ArgumentNullException ("column", "'column' argument cannot be null.");
+
+                       if (column.ColumnName.Equals(String.Empty))
                        {
-                               throw new DuplicateNameException("A column named " + column.ColumnName + " already belongs to this DataTable.");
+                               column.ColumnName = GetNextDefaultColumnName ();
                        }
-                       else
-                       {
-                               CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
-                               
-                               column.SetTable( parentTable);
-                               base.List.Add(column);
-                               
-                               //add constraints if neccesary
 
-                               if(column.Unique)
-                               {
-                                       UniqueConstraint uc = new UniqueConstraint(column);
-                                       parentTable.Constraints.Add(uc);
-                               }
-                               
-                               //TODO: add missing constraints. i.e. Primary/Foreign keys
+//                     if (Contains(column.ColumnName))
+//                             throw new DuplicateNameException("A DataColumn named '" + column.ColumnName + "' already belongs to this DataTable.");
 
-                               OnCollectionChanged(e);
-                               return;
+                       if (column.Table != null)
+                               throw new ArgumentException ("Column '" + column.ColumnName + "' already belongs to this or another DataTable.");
+
+                       CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
+
+                       column.SetTable (parentTable);
+                       RegisterName(column.ColumnName, column);
+                       int ordinal = base.List.Add(column);
+                       column.SetOrdinal (ordinal);
+
+                       // if table already has rows we need to allocate space 
+                       // in the column data container 
+                       if ( parentTable.Rows.Count > 0 ) {
+                               column.DataContainer.Capacity = parentTable.RecordCache.CurrentCapacity;
+                       }
+
+                       if (column.AutoIncrement) {
+                               DataRowCollection rows = column.Table.Rows;
+                               for (int i = 0; i < rows.Count; i++)
+                                       rows [i] [ordinal] = column.AutoIncrementValue ();
                        }
+
+                       if (column.AutoIncrement)
+                               autoIncrement.Add(column);
+
+                       OnCollectionChanged (e);
                }
 
                /// <summary>
@@ -143,30 +244,14 @@ namespace System.Data
                /// <returns>The newly created DataColumn.</returns>
                public virtual DataColumn Add(string columnName)
                {
-                       
-                       //FIXME: this wont work.  If the user decides to add a column named
-                       //"ColumnXX" where XX is a number these two will conflict.
                        if (columnName == null || columnName == String.Empty)
                        {
-                               columnName = "Column" + defaultNameIndex.ToString();
-                               defaultNameIndex++;
+                               columnName = GetNextDefaultColumnName();
                        }
                        
-                       if(Contains(columnName))
-                       {
-                               throw new DuplicateNameException("A column named " + columnName + " already belongs to this DataTable.");
-                       }
-                       else
-                       {
-                               DataColumn column = new DataColumn(columnName);
-                               
-                               CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
-                               column.SetTable(parentTable);                           
-                               int ordinal = base.List.Add(column);
-                               column.SetOrdinal( ordinal );
-                               OnCollectionChanged(e);
-                               return column;
-                       }
+                       DataColumn column = new DataColumn(columnName);
+                       Add (column);
+                       return column;
                }
 
                /// <summary>
@@ -179,26 +264,12 @@ namespace System.Data
                {
                        if (columnName == null || columnName == "")
                        {
-                               //FIXME: this wont work.  If the user decides to add a column named
-                               //"ColumnXX" where XX is a number these two will conflict.
-                               columnName = "Column" + defaultNameIndex.ToString();
-                               defaultNameIndex++;
-                       }
-
-                       if(Contains(columnName))
-                       {
-                               throw new DuplicateNameException("A column named " + columnName + " already belongs to this DataTable.");
-                       }
-                       else
-                       {
-                               DataColumn column = new DataColumn(columnName, type);
-                               CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
-                               column.SetTable(parentTable);
-                               int ordinal = base.List.Add(column);
-                               column.SetOrdinal( ordinal );                           
-                               OnCollectionChanged(e);
-                               return column;
+                               columnName = GetNextDefaultColumnName ();
                        }
+                       
+                       DataColumn column = new DataColumn(columnName, type);
+                       Add (column);
+                       return column;
                }
 
                /// <summary>
@@ -208,29 +279,16 @@ namespace System.Data
                /// <param name="type">The DataType of the new column.</param>
                /// <param name="expression">The expression to assign to the Expression property.</param>
                /// <returns>The newly created DataColumn.</returns>
-               public virtual DataColumn Add(string columnName, Type type,     string expression)
+               public virtual DataColumn Add(string columnName, Type type, string expression)
                {
-                       //FIXME: See Add Logic
                        if (columnName == null || columnName == "")
                        {
-                               columnName = "Column" + defaultNameIndex.ToString();
-                               defaultNameIndex++;
+                               columnName = GetNextDefaultColumnName ();
                        }
                        
-                       if(Contains(columnName))
-                       {
-                               throw new DuplicateNameException("A column named " + columnName + " already belongs to this DataTable.");
-                       }
-                       else
-                       {
-                               DataColumn column = new DataColumn(columnName, type, expression);
-                               CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
-                               column.SetTable(parentTable);
-                               int ordinal = base.List.Add(column);
-                               column.SetOrdinal( ordinal );
-                               OnCollectionChanged(e);
-                               return column;
-                       }
+                       DataColumn column = new DataColumn(columnName, type, expression);
+                       Add (column);
+                       return column;
                }
 
                /// <summary>
@@ -239,11 +297,18 @@ namespace System.Data
                /// <param name="columns">The array of DataColumn objects to add to the collection.</param>
                public void AddRange(DataColumn[] columns)
                {
+                       if (parentTable.fInitInProgress){
+                               _mostRecentColumns = columns;
+                               return;
+                       }
+
+                       if (columns == null)
+                               return;
+
                        foreach (DataColumn column in columns)
                        {
                                Add(column);
                        }
-                       return;
                }
 
                /// <summary>
@@ -255,34 +320,38 @@ namespace System.Data
                {
                                                
                        //Check that the column does not have a null reference.
-                       if (column == null)
+                       if (column == null) 
                        {
                 return false;
                        }
 
                        
                        //Check that the column is part of this collection.
-                       if (!Contains(column.ColumnName))
+                       if (parentTable != column.Table) 
                        {
                                return false;
                        }
 
+                       parentTable.OnRemoveColumn(column);
 
+                       UniqueConstraint primaryKey = parentTable.PrimaryKeyConstraint;
+                       if (primaryKey != null && primaryKey.IsColumnContained(column))
+                               return false;
                        
                        //Check if this column is part of a relationship. (this could probably be written better)
                        foreach (DataRelation childRelation in parentTable.ChildRelations)
                        {
-                               foreach (DataColumn childColumn in childRelation.ChildColumns)
+                               foreach (DataColumn childColumn in childRelation.ChildColumns) 
                                {
-                                       if (childColumn == column)
+                                       if (childColumn == column) 
                                        {
                                                return false;
                                        }
                                }
 
-                               foreach (DataColumn parentColumn in childRelation.ParentColumns)
+                               foreach (DataColumn parentColumn in childRelation.ParentColumns) 
                                {
-                                       if (parentColumn == column)
+                                       if (parentColumn == column) 
                                        {
                                                return false;
                                        }
@@ -290,38 +359,67 @@ namespace System.Data
                        }
 
                        //Check if this column is part of a relationship. (this could probably be written better)
-                       foreach (DataRelation parentRelation in parentTable.ParentRelations)
+                       foreach (DataRelation parentRelation in parentTable.ParentRelations) 
                        {
-                               foreach (DataColumn childColumn in parentRelation.ChildColumns)
+                               foreach (DataColumn childColumn in parentRelation.ChildColumns) 
                                {
-                                       if (childColumn == column)
+                                       if (childColumn == column) 
                                        {
                                                return false;
                                        }
                                }
 
-                               foreach (DataColumn parentColumn in parentRelation.ParentColumns)
+                               foreach (DataColumn parentColumn in parentRelation.ParentColumns) 
                                {
-                                       if (parentColumn == column)
+                                       if (parentColumn == column) 
                                        {
                                                return false;
                                        }
                                }
                        }
 
+                       //TODO: check constraints
+                       for (int i = 0; i < parentTable.Constraints.Count; i++) {
+                               if (parentTable.Constraints[i].IsColumnContained(column))
+                                       return false;
+                       }
+
+                       if (parentTable.DataSet != null) {
+                               //FIXME: check whether some parent key in ForeignConstriants contains
+                               // the column
+                       }
+
                        
                        //Check if another column's expression depends on this column.
                        
-                       foreach (DataColumn dataColumn in List)
+                       foreach (DataColumn dataColumn in List) 
                        {
-                               if (dataColumn.Expression.ToString().IndexOf(column.ColumnName) > 0)
+                               if (dataColumn.CompiledExpression != null && 
+                                               dataColumn.CompiledExpression.DependsOn(column)) 
                                {
                                        return false;
                                }
                        }
-                       
-                       //TODO: check constraints
-
+            // check for part of pk
+            UniqueConstraint uc = UniqueConstraint.GetPrimaryKeyConstraint (parentTable.Constraints);
+            if (uc != null && uc.IsColumnContained(column)) {
+               return false;
+                       }
+            // check for part of fk
+            DataSet ds = parentTable.DataSet;            
+            if (ds != null) {
+                foreach (DataTable t in ds.Tables) {
+                    if (t == parentTable)
+                        continue;
+                    foreach (Constraint c in t.Constraints) {
+                        if (! (c is ForeignKeyConstraint))
+                            continue;
+                        ForeignKeyConstraint fk = (ForeignKeyConstraint) c;
+                        if (fk.IsColumnContained(column))
+                                return false;                        
+                    }                        
+                }                                        
+            }                    
                        return true;
                }
 
@@ -331,9 +429,52 @@ namespace System.Data
                public void Clear()
                {
                        CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Refresh, this);
+
+                       // FIXME: Hmm... This loop could look little nicer :)
+                       foreach (DataColumn Col in List) {
+                               foreach (DataRelation Rel in Col.Table.ParentRelations) {
+                                       foreach (DataColumn Col2 in Rel.ParentColumns) {
+                                               if (Object.ReferenceEquals (Col, Col2))
+                                                       throw new ArgumentException ("Cannot remove this column, because " + 
+                                                                                    "it is part of the parent key for relationship " + 
+                                                                                    Rel.RelationName + ".");
+                                       }
+                                       foreach (DataColumn Col2 in Rel.ChildColumns) {
+                                               if (Object.ReferenceEquals (Col, Col2))
+                                                       throw new ArgumentException ("Cannot remove this column, because " + 
+                                                                                    "it is part of the parent key for relationship " + 
+                                                                                    Rel.RelationName + ".");
+
+                                       }
+                               }
+
+                               foreach (DataRelation Rel in Col.Table.ChildRelations) {
+                                       foreach (DataColumn Col2 in Rel.ParentColumns) {
+                                               if (Object.ReferenceEquals (Col, Col2))
+                                                       throw new ArgumentException ("Cannot remove this column, because " + 
+                                                                                    "it is part of the parent key for relationship " + 
+                                                                                    Rel.RelationName + ".");
+                                       }
+                                       foreach (DataColumn Col2 in Rel.ChildColumns) {
+                                               if (Object.ReferenceEquals (Col, Col2))
+                                                       throw new ArgumentException ("Cannot remove this column, because " + 
+                                                                                    "it is part of the parent key for relationship " + 
+                                                                                    Rel.RelationName + ".");
+                                       }
+                               }
+                       }
+
+            // whether all columns can be removed
+            foreach (DataColumn col in this) {
+                if (!CanRemove (col))
+                    throw new ArgumentException ("Cannot remove column {0}", col.ColumnName);
+            }
+
+                       columnFromName.Clear();
+                       autoIncrement.Clear();
                        base.List.Clear();
                        OnCollectionChanged(e);
-                       return;
+
                }
 
                /// <summary>
@@ -343,7 +484,10 @@ namespace System.Data
                /// <returns>true if a column exists with this name; otherwise, false.</returns>
                public bool Contains(string name)
                {
-                       return (IndexOf(name) != -1);
+                       if (columnFromName.Contains(name))
+                               return true;
+                       
+                       return (IndexOf(name, false) != -1);
                }
 
                /// <summary>
@@ -363,17 +507,12 @@ namespace System.Data
                /// <returns>The zero-based index of the column with the specified name, or -1 if the column doesn't exist in the collection.</returns>
                public int IndexOf(string columnName)
                {
-                       
-                       DataColumn column = this[columnName];
-                       
-                       if (column != null)
-                       {
-                               return IndexOf(column);
-                       }
-                       else
-                       {
-                               return -1;
-                       }
+                       DataColumn dc = columnFromName[columnName] as DataColumn;
+                               
+                       if (dc != null)
+                               return IndexOf(dc);
+
+                       return IndexOf(columnName, false);
                }
 
                /// <summary>
@@ -382,6 +521,7 @@ namespace System.Data
                /// <param name="ccevent">A CollectionChangeEventArgs that contains the event data.</param>
                protected virtual void OnCollectionChanged(CollectionChangeEventArgs ccevent)
                {
+                       parentTable.ResetPropertyDescriptorsCache();
                        if (CollectionChanged != null) 
                        {
                                CollectionChanged(this, ccevent);
@@ -408,11 +548,17 @@ namespace System.Data
                /// <param name="column">The DataColumn to remove.</param>
                public void Remove(DataColumn column)
                {
+                       if (column == null)
+                               throw new ArgumentNullException ("column", "'column' argument cannot be null.");
+
+                       if (!Contains(column.ColumnName))
+                               throw new ArgumentException ("Cannot remove a column that doesn't belong to this table.");
                        //TODO: can remove first with exceptions
                        //and OnChanging Event
                        CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Remove, this);
                        
                        int ordinal = column.Ordinal;
+                       UnregisterName(column.ColumnName);
                        base.List.Remove(column);
                        
                        //Update the ordinals
@@ -420,7 +566,13 @@ namespace System.Data
                        {
                                this[i].SetOrdinal( i );
                        }
-                       
+
+                       if (parentTable != null)
+                               parentTable.OnRemoveColumn(column);
+
+                       if (column.AutoIncrement)
+                               autoIncrement.Remove(column);
+
                        OnCollectionChanged(e);
                        return;
                }
@@ -431,8 +583,11 @@ namespace System.Data
                /// <param name="name">The name of the column to remove.</param>
                public void Remove(string name)
                {
-                       DataColumn column = this[name];                 
-                       Remove( column );
+                       DataColumn column = this[name];
+                       
+                       if (column == null)
+                               throw new ArgumentException ("Column '" + name + "' does not belong to table " + ( parentTable == null ? "" : parentTable.TableName ) + ".");
+                       Remove(column);
                }
 
                /// <summary>
@@ -441,13 +596,77 @@ namespace System.Data
                /// <param name="index">The index of the column to remove.</param>
                public void RemoveAt(int index)
                {
+                       if (Count <= index)
+                               throw new IndexOutOfRangeException ("Cannot find column " + index + ".");
+
                        DataColumn column = this[index];
-                       Remove( column );
+                       Remove(column);
+               }
+
+               // Helper AddRange() - Call this function when EndInit is called
+               internal void PostEndInit() {
+                       DataColumn[] cols = _mostRecentColumns;
+                       _mostRecentColumns = null;
+                       AddRange (cols);
                }
 
+
+               /// <summary>
+               ///  Do the same as Constains -method but case sensitive
+               /// </summary>
+               private bool CaseSensitiveContains(string columnName)
+               {
+                       DataColumn column = this[columnName];
+                       
+                       if (column != null)
+                               return string.Compare(column.ColumnName, columnName, false) == 0; 
+
+                       return false;
+               }
+
+               internal void UpdateAutoIncrement(DataColumn col,bool isAutoIncrement)
+               {
+                       if (isAutoIncrement)
+                       {
+                               if (!autoIncrement.Contains(col))
+                                       autoIncrement.Add(col);
+                       }
+                       else
+                       {
+                               if (autoIncrement.Contains(col))
+                                       autoIncrement.Remove(col);
+                       }
+               }
+
+               private int IndexOf (string name, bool error)
+               {
+                       int count = 0, match = -1;
+                       for (int i = 0; i < List.Count; i++)
+                       {
+                               String name2 = ((DataColumn) List[i]).ColumnName;
+                               if (String.Compare (name, name2, true) == 0)
+                               {
+                                       if (String.Compare (name, name2, false) == 0)
+                                               return i;
+                                       match = i;
+                                       count++;
+                               }
+                       }
+                       if (count == 1)
+                               return match;
+                       if (count > 1 && error)
+                               throw new ArgumentException ("There is no match for the name in the same case and there are multiple matches in different case.");
+                       return -1;
+               }
+               
+               #region Events
+
                /// <summary>
                /// Occurs when the columns collection changes, either by adding or removing a column.
                /// </summary>
+                [ResDescriptionAttribute ("Occurs whenever this collection's membership changes.")] 
                public event CollectionChangeEventHandler CollectionChanged;
+
+               #endregion 
        }
 }