|   |  | 1 |  | // Copyright (c) 2020-2024 dotBunny Inc. | 
|   |  | 2 |  | // dotBunny licenses this file to you under the BSL-1.0 license. | 
|   |  | 3 |  | // See the LICENSE file in the project root for more information. | 
|   |  | 4 |  |  | 
|   |  | 5 |  | using System; | 
|   |  | 6 |  | using System.Collections.Generic; | 
|   |  | 7 |  | using UnityEngine; | 
|   |  | 8 |  |  | 
|   |  | 9 |  | namespace GDX.DataTables.DataBinding | 
|   |  | 10 |  | { | 
|   |  | 11 |  |     /// <summary> | 
|   |  | 12 |  |     ///     A serializable object used during import and export of <see cref="DataTableBase" /> based data. | 
|   |  | 13 |  |     /// </summary> | 
|   |  | 14 |  |     [Serializable] | 
|   |  | 15 |  |     public class SerializableTable | 
|   |  | 16 |  |     { | 
|   |  | 17 |  | #pragma warning disable IDE1006 | 
|   |  | 18 |  |         // ReSharper disable InconsistentNaming | 
|   |  | 19 |  |  | 
|   |  | 20 |  |         /// <summary> | 
|   |  | 21 |  |         ///     The version of the data at the point of export. | 
|   |  | 22 |  |         /// </summary> | 
|   |  | 23 |  |         public ulong DataVersion; | 
|   |  | 24 |  |  | 
|   |  | 25 |  |         /// <summary> | 
|   |  | 26 |  |         ///     The structural version of the data at the point of export. | 
|   |  | 27 |  |         /// </summary> | 
|   |  | 28 |  |         public int StructureVersion; | 
|   |  | 29 |  |  | 
|   |  | 30 |  |         /// <summary> | 
|   |  | 31 |  |         ///     The column names. | 
|   |  | 32 |  |         /// </summary> | 
|   |  | 33 |  |         public string[] Headers; | 
|   |  | 34 |  |  | 
|   |  | 35 |  |         /// <summary> | 
|   |  | 36 |  |         ///     The column types. | 
|   |  | 37 |  |         /// </summary> | 
|   |  | 38 |  |         public string[] Types; | 
|   |  | 39 |  |  | 
|   |  | 40 |  |         /// <summary> | 
|   |  | 41 |  |         ///     The row data. | 
|   |  | 42 |  |         /// </summary> | 
|   |  | 43 |  |         public SerializableRow[] Rows; | 
|   |  | 44 |  |  | 
|   |  | 45 |  |         // ReSharper enable InconsistentNaming | 
|   |  | 46 |  | #pragma warning restore IDE1006 | 
|   |  | 47 |  |  | 
|   |  | 48 |  |         /// <summary> | 
|   |  | 49 |  |         ///     Creates a new empty <see cref="SerializableTable" />. | 
|   |  | 50 |  |         /// </summary> | 
|   | 0 | 51 |  |         public SerializableTable() | 
|   | 0 | 52 |  |         { | 
|   | 0 | 53 |  |         } | 
|   |  | 54 |  |  | 
|   |  | 55 |  |         /// <summary> | 
|   |  | 56 |  |         ///     Creates a new <see cref="SerializableTable" /> from a <see cref="DataTableBase" />. | 
|   |  | 57 |  |         /// </summary> | 
|   |  | 58 |  |         /// <param name="dataTable">Populate the data set from this target.</param> | 
|   | 0 | 59 |  |         public SerializableTable(DataTableBase dataTable) | 
|   | 0 | 60 |  |         { | 
|   | 0 | 61 |  |             ColumnDescription[] columnDescriptions = dataTable.GetAllColumnDescriptions(); | 
|   | 0 | 62 |  |             int columnCount = columnDescriptions.Length; | 
|   |  | 63 |  |  | 
|   | 0 | 64 |  |             DataVersion = dataTable.GetDataVersion(); | 
|   | 0 | 65 |  |             StructureVersion = dataTable.GetStructureVersion(); | 
|   |  | 66 |  |  | 
|   |  | 67 |  |             // Build Headers | 
|   | 0 | 68 |  |             Headers = new string[columnCount]; | 
|   | 0 | 69 |  |             Types = new string[columnCount]; | 
|   |  | 70 |  |  | 
|   | 0 | 71 |  |             for (int i = 0; i < columnCount; i++) | 
|   | 0 | 72 |  |             { | 
|   | 0 | 73 |  |                 Headers[i] = columnDescriptions[i].Name; | 
|   | 0 | 74 |  |                 Types[i] = columnDescriptions[i].Type.GetLabel(); | 
|   | 0 | 75 |  |             } | 
|   |  | 76 |  |  | 
|   | 0 | 77 |  |             RowDescription[] rowDescriptions = dataTable.GetAllRowDescriptions(); | 
|   | 0 | 78 |  |             int rowCount = rowDescriptions.Length; | 
|   |  | 79 |  |  | 
|   | 0 | 80 |  |             Rows = new SerializableRow[rowCount]; | 
|   |  | 81 |  |  | 
|   | 0 | 82 |  |             for (int i = 0; i < rowCount; i++) | 
|   | 0 | 83 |  |             { | 
|   | 0 | 84 |  |                 RowDescription rowDescription = rowDescriptions[i]; | 
|   |  | 85 |  |  | 
|   | 0 | 86 |  |                 Rows[i] = new SerializableRow(columnCount) | 
|   |  | 87 |  |                 { | 
|   |  | 88 |  |                     Identifier = rowDescription.Identifier, Name = rowDescription.Name | 
|   |  | 89 |  |                 }; | 
|   |  | 90 |  |  | 
|   | 0 | 91 |  |                 for (int c = 0; c < columnCount; c++) | 
|   | 0 | 92 |  |                 { | 
|   | 0 | 93 |  |                     ColumnDescription columnDescription = columnDescriptions[c]; | 
|   | 0 | 94 |  |                     Rows[i].Data[c] = dataTable.GetCellValueAsString(rowDescription.Identifier, | 
|   |  | 95 |  |                         columnDescription.Identifier, | 
|   |  | 96 |  |                         columnDescription.Type); | 
|   | 0 | 97 |  |                 } | 
|   | 0 | 98 |  |             } | 
|   | 0 | 99 |  |         } | 
|   |  | 100 |  |  | 
|   |  | 101 |  |         /// <summary> | 
|   |  | 102 |  |         ///     Update the target <paramref name="dataTable" /> based on the data found in the <see cref="SerializableTa | 
|   |  | 103 |  |         /// </summary> | 
|   |  | 104 |  |         /// <param name="dataTable">The <see cref="DataTableBase" /> to update.</param> | 
|   |  | 105 |  |         /// <param name="removeRowIfNotFound"> | 
|   |  | 106 |  |         ///     Should rows not found in the <see cref="SerializableTable" /> be removed from the | 
|   |  | 107 |  |         ///     <see cref="DataTableBase" />. | 
|   |  | 108 |  |         /// </param> | 
|   |  | 109 |  |         /// <returns>Was this operation successful?</returns> | 
|   |  | 110 |  |         public bool Update(DataTableBase dataTable, bool removeRowIfNotFound = true) | 
|   | 0 | 111 |  |         { | 
|   | 0 | 112 |  |             int tableRowCount = dataTable.GetRowCount(); | 
|   | 0 | 113 |  |             int tableColumnCount = dataTable.GetColumnCount(); | 
|   |  | 114 |  |  | 
|   | 0 | 115 |  |             ColumnDescription[] columnDescriptions = dataTable.GetAllColumnDescriptions(); | 
|   | 0 | 116 |  |             int neededColumnCount = columnDescriptions.Length; | 
|   | 0 | 117 |  |             if (neededColumnCount != Types.Length || neededColumnCount != Headers.Length) | 
|   | 0 | 118 |  |             { | 
|   | 0 | 119 |  |                 Debug.LogError( | 
|   |  | 120 |  |                     $"The importing data has {Types.Length.ToString()} columns where {neededColumnCount.ToString()} was  | 
|   | 0 | 121 |  |                 return false; | 
|   |  | 122 |  |             } | 
|   |  | 123 |  |  | 
|   |  | 124 |  |             // Build a list of previous row ID, so we know what was removed | 
|   | 0 | 125 |  |             List<int> previousRowInternalIndices = new List<int>(tableRowCount); | 
|   | 0 | 126 |  |             RowDescription[] rowDescriptions = dataTable.GetAllRowDescriptions(); | 
|   | 0 | 127 |  |             int rowDescriptionsLength = rowDescriptions.Length; | 
|   | 0 | 128 |  |             for (int i = 0; i < rowDescriptionsLength; i++) | 
|   | 0 | 129 |  |             { | 
|   | 0 | 130 |  |                 previousRowInternalIndices.Add(rowDescriptions[i].Identifier); | 
|   | 0 | 131 |  |             } | 
|   |  | 132 |  |  | 
|   | 0 | 133 |  |             int fileRowCount = Rows.Length; | 
|   | 0 | 134 |  |             List<int> foundRowInternalIndices = new List<int>(tableRowCount); | 
|   |  | 135 |  |  | 
|   | 0 | 136 |  |             for (int i = 0; i < fileRowCount; i++) | 
|   | 0 | 137 |  |             { | 
|   |  | 138 |  |                 int rowIdentifier; | 
|   |  | 139 |  |                 string rowName; | 
|   | 0 | 140 |  |                 if (Rows[i].Identifier == -1) | 
|   | 0 | 141 |  |                 { | 
|   | 0 | 142 |  |                     rowName = Rows[i].Name; | 
|   | 0 | 143 |  |                     if (string.IsNullOrEmpty(rowName)) | 
|   | 0 | 144 |  |                     { | 
|   | 0 | 145 |  |                         rowName = "Unnamed"; | 
|   | 0 | 146 |  |                     } | 
|   |  | 147 |  |  | 
|   | 0 | 148 |  |                     rowIdentifier = dataTable.AddRow(rowName); | 
|   | 0 | 149 |  |                 } | 
|   |  | 150 |  |                 else | 
|   | 0 | 151 |  |                 { | 
|   | 0 | 152 |  |                     rowIdentifier = Rows[i].Identifier; | 
|   | 0 | 153 |  |                     rowName = Rows[i].Name; | 
|   | 0 | 154 |  |                 } | 
|   |  | 155 |  |  | 
|   | 0 | 156 |  |                 foundRowInternalIndices.Add(rowIdentifier); | 
|   | 0 | 157 |  |                 dataTable.SetRowName(rowIdentifier, rowName); | 
|   |  | 158 |  |  | 
|   | 0 | 159 |  |                 for (int j = 0; j < tableColumnCount; j++) | 
|   | 0 | 160 |  |                 { | 
|   | 0 | 161 |  |                     dataTable.SetCellValueFromString(rowIdentifier, columnDescriptions[j].Identifier, Rows[i].Data[j], | 
|   |  | 162 |  |                         columnDescriptions[j].Type); | 
|   | 0 | 163 |  |                 } | 
|   | 0 | 164 |  |             } | 
|   |  | 165 |  |  | 
|   |  | 166 |  |             // Remove indices that were not found any more? | 
|   | 0 | 167 |  |             if (removeRowIfNotFound) | 
|   | 0 | 168 |  |             { | 
|   | 0 | 169 |  |                 int foundIndicesCount = foundRowInternalIndices.Count; | 
|   | 0 | 170 |  |                 for (int i = 0; i < foundIndicesCount; i++) | 
|   | 0 | 171 |  |                 { | 
|   | 0 | 172 |  |                     if (previousRowInternalIndices.Contains(foundRowInternalIndices[i])) | 
|   | 0 | 173 |  |                     { | 
|   | 0 | 174 |  |                         previousRowInternalIndices.Remove(foundRowInternalIndices[i]); | 
|   | 0 | 175 |  |                     } | 
|   | 0 | 176 |  |                 } | 
|   |  | 177 |  |  | 
|   | 0 | 178 |  |                 int indicesToRemove = previousRowInternalIndices.Count; | 
|   | 0 | 179 |  |                 for (int i = 0; i < indicesToRemove; i++) | 
|   | 0 | 180 |  |                 { | 
|   | 0 | 181 |  |                     dataTable.RemoveRow(previousRowInternalIndices[i]); | 
|   | 0 | 182 |  |                 } | 
|   | 0 | 183 |  |             } | 
|   |  | 184 |  |  | 
|   | 0 | 185 |  |             return true; | 
|   | 0 | 186 |  |         } | 
|   |  | 187 |  |     } | 
|   |  | 188 |  | } |