aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.CSV
diff options
context:
space:
mode:
Diffstat (limited to 'Software/Visual_Studio/Tango.CSV')
-rw-r--r--Software/Visual_Studio/Tango.CSV/CsvDynamicWriter.cs126
-rw-r--r--Software/Visual_Studio/Tango.CSV/Tango.CSV.csproj1
2 files changed, 127 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Tango.CSV/CsvDynamicWriter.cs b/Software/Visual_Studio/Tango.CSV/CsvDynamicWriter.cs
new file mode 100644
index 000000000..1c460d5e3
--- /dev/null
+++ b/Software/Visual_Studio/Tango.CSV/CsvDynamicWriter.cs
@@ -0,0 +1,126 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.CSV
+{
+ public class CsvDynamicWriter
+ {
+ private sealed class ColumnInfo
+ {
+ public string Name;
+ public string Default;
+ public int Index;
+ public int CreationOrder;
+ }
+
+ private readonly Dictionary<string, ColumnInfo> _colMap = new Dictionary<string, ColumnInfo>();
+ private readonly List<ColumnInfo> _cols = new List<ColumnInfo>();
+ private int _creationCounter = 0;
+
+ private readonly List<Dictionary<string, string>> _rows = new List<Dictionary<string, string>>();
+ private Dictionary<string, string> _currentRow = new Dictionary<string, string>();
+
+ /// <summary>
+ /// Writes a value to the specified column in the current row.
+ /// If the column does not exist, it is created with the given default value and index.
+ /// Column order in the CSV header is by (Index asc, CreationOrder asc).
+ /// </summary>
+ public void Write(string value, string columnName, string defaultValue, int index)
+ {
+ ColumnInfo col;
+ if (!_colMap.TryGetValue(columnName, out col))
+ {
+ col = new ColumnInfo
+ {
+ Name = columnName,
+ Default = defaultValue,
+ Index = index,
+ CreationOrder = _creationCounter++
+ };
+ _colMap[columnName] = col;
+ _cols.Add(col);
+
+ // Backfill all prior rows with the column's default.
+ foreach (var row in _rows)
+ {
+ if (!row.ContainsKey(columnName))
+ row[columnName] = defaultValue;
+ }
+ }
+ // If the column already exists, we keep the original index/default.
+ // (If you need reindexing, add an explicit method to change col.Index.)
+
+ _currentRow[columnName] = value ?? "";
+ }
+
+ /// <summary>
+ /// Moves to the next row, finalizing the current one.
+ /// Missing cells get their column default value.
+ /// </summary>
+ public void Next()
+ {
+ if (_currentRow == null) _currentRow = new Dictionary<string, string>();
+
+ foreach (var col in _cols)
+ {
+ if (!_currentRow.ContainsKey(col.Name))
+ _currentRow[col.Name] = col.Default ?? "";
+ }
+
+ _rows.Add(_currentRow);
+ _currentRow = new Dictionary<string, string>();
+ }
+
+ /// <summary>
+ /// Saves the CSV to disk using the column order defined by (Index, CreationOrder).
+ /// </summary>
+ public void Save(string filePath)
+ {
+ // Auto-finalize last row if it has any values.
+ if (_currentRow != null && _currentRow.Count > 0)
+ Next();
+
+ var orderedCols = _cols
+ .OrderBy(c => c.Index)
+ .ThenBy(c => c.CreationOrder)
+ .ToList();
+
+ var sb = new StringBuilder();
+
+ // Header
+ sb.AppendLine(string.Join(",", orderedCols.Select(c => EscapeCsv(c.Name))));
+
+ // Rows
+ foreach (var row in _rows)
+ {
+ var values = new List<string>(orderedCols.Count);
+ for (int i = 0; i < orderedCols.Count; i++)
+ {
+ var name = orderedCols[i].Name;
+ string v;
+ if (!row.TryGetValue(name, out v))
+ {
+ // Shouldn't happen (Next() fills), but be defensive.
+ v = orderedCols[i].Default ?? "";
+ }
+ values.Add(EscapeCsv(v));
+ }
+ sb.AppendLine(string.Join(",", values));
+ }
+
+ File.WriteAllText(filePath, sb.ToString(), Encoding.UTF8);
+ }
+
+ private static string EscapeCsv(string input)
+ {
+ if (input == null) return "";
+ if (input.IndexOfAny(new[] { ',', '"', '\n', '\r' }) >= 0)
+ return "\"" + input.Replace("\"", "\"\"") + "\"";
+ return input;
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Tango.CSV/Tango.CSV.csproj b/Software/Visual_Studio/Tango.CSV/Tango.CSV.csproj
index b6743bede..0fc1948a4 100644
--- a/Software/Visual_Studio/Tango.CSV/Tango.CSV.csproj
+++ b/Software/Visual_Studio/Tango.CSV/Tango.CSV.csproj
@@ -81,6 +81,7 @@
</Compile>
<Compile Include="CsvDefinition.cs" />
<Compile Include="CsvDestination.cs" />
+ <Compile Include="CsvDynamicWriter.cs" />
<Compile Include="CsvFile.cs" />
<Compile Include="CsvFileLinqExtensions.cs" />
<Compile Include="CsvFileReader.cs" />