namespace Spectre.Console;
///
/// Represents a collection holding table rows.
///
public sealed class TableRowCollection : IReadOnlyList
{
private readonly Table _table;
private readonly IList _list;
private readonly object _lock;
///
TableRow IReadOnlyList.this[int index]
{
get
{
lock (_lock)
{
return _list[index];
}
}
}
///
/// Gets the number of rows in the collection.
///
public int Count
{
get
{
lock (_lock)
{
return _list.Count;
}
}
}
internal TableRowCollection(Table table)
{
_table = table ?? throw new ArgumentNullException(nameof(table));
_list = new List();
_lock = new object();
}
///
/// Adds a new row.
///
/// The columns that are part of the row to add.
/// The index of the added item.
public int Add(IEnumerable columns)
{
if (columns is null)
{
throw new ArgumentNullException(nameof(columns));
}
lock (_lock)
{
var row = CreateRow(columns);
_list.Add(row);
return _list.IndexOf(row);
}
}
///
/// Inserts a new row at the specified index.
///
/// The index to insert the row at.
/// The columns that are part of the row to insert.
/// The index of the inserted item.
public int Insert(int index, IEnumerable columns)
{
if (columns is null)
{
throw new ArgumentNullException(nameof(columns));
}
lock (_lock)
{
var row = CreateRow(columns);
_list.Insert(index, row);
return _list.IndexOf(row);
}
}
///
/// Update a table cell at the specified index.
///
/// Index of cell row.
/// index of cell column.
/// The new cells details.
public void Update(int row, int column, IRenderable cellData)
{
if (cellData is null)
{
throw new ArgumentNullException(nameof(cellData));
}
lock (_lock)
{
if (row < 0)
{
throw new IndexOutOfRangeException("Table row index cannot be negative.");
}
else if (row >= _list.Count)
{
throw new IndexOutOfRangeException("Table row index cannot exceed the number of rows in the table.");
}
var tableRow = _list.ElementAt(row);
var currentRenderables = tableRow.ToList();
if (column < 0)
{
throw new IndexOutOfRangeException("Table column index cannot be negative.");
}
else if (column >= currentRenderables.Count)
{
throw new IndexOutOfRangeException("Table column index cannot exceed the number of rows in the table.");
}
currentRenderables.RemoveAt(column);
currentRenderables.Insert(column, cellData);
var newTableRow = new TableRow(currentRenderables);
_list.RemoveAt(row);
_list.Insert(row, newTableRow);
}
}
///
/// Removes a row at the specified index.
///
/// The index to remove a row at.
public void RemoveAt(int index)
{
lock (_lock)
{
if (index < 0)
{
throw new IndexOutOfRangeException("Table row index cannot be negative.");
}
else if (index >= _list.Count)
{
throw new IndexOutOfRangeException("Table row index cannot exceed the number of rows in the table.");
}
_list.RemoveAt(index);
}
}
///
/// Clears all rows.
///
public void Clear()
{
lock (_lock)
{
_list.Clear();
}
}
///
public IEnumerator GetEnumerator()
{
lock (_lock)
{
var items = new TableRow[_list.Count];
_list.CopyTo(items, 0);
return new TableRowEnumerator(items);
}
}
///
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private TableRow CreateRow(IEnumerable columns)
{
var row = new TableRow(columns);
if (row.Count > _table.Columns.Count)
{
throw new InvalidOperationException("The number of row columns are greater than the number of table columns.");
}
// Need to add missing columns
if (row.Count < _table.Columns.Count)
{
var diff = _table.Columns.Count - row.Count;
Enumerable.Range(0, diff).ForEach(_ => row.Add(Text.Empty));
}
return row;
}
}