259 lines
8.9 KiB
C#
259 lines
8.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
using mbts;
|
|
|
|
namespace BCG {
|
|
internal class MutableAppendTable : IBlueRowCollection {
|
|
private class MyRow : IBlueRow {
|
|
private IBlueRow myRow;
|
|
private int myID;
|
|
|
|
public MyRow(IBlueRow r, int id) {
|
|
myRow = r;
|
|
myID = id;
|
|
}
|
|
|
|
#region IBlueRow Members
|
|
|
|
public IBlueTableSchema schema { get { return myRow.schema; } }
|
|
|
|
public object this[int index] {
|
|
get {
|
|
if (myRow.schema[index].colName == "id")
|
|
return myID;
|
|
else
|
|
return myRow[index];
|
|
}
|
|
}
|
|
|
|
public object this[string colName] { get { return colName == "id" ? (object)myID : myRow[colName]; } }
|
|
|
|
#endregion
|
|
|
|
#region IDictionary Members
|
|
|
|
public void Add(object key, object value) { throw new Exception("Row is read only."); }
|
|
|
|
public void Clear() { throw new Exception("Row is read only."); }
|
|
|
|
public bool Contains(object key) { return myRow.Contains(key); }
|
|
|
|
public System.Collections.IDictionaryEnumerator GetEnumerator() { return new BlueRowDictionaryEnumerator(this); }
|
|
|
|
public bool IsFixedSize { get { return true; } }
|
|
|
|
public bool IsReadOnly { get { return true; } }
|
|
|
|
public System.Collections.ICollection Keys { get { return myRow.Keys; } }
|
|
|
|
public void Remove(object key) { throw new Exception("The method or operation is not implemented."); }
|
|
|
|
public System.Collections.ICollection Values {
|
|
get {
|
|
object[] vals = new object[myRow.Count];
|
|
CopyTo(vals, 0);
|
|
return vals;
|
|
}
|
|
}
|
|
|
|
public object this[object key] {
|
|
get { return key is string ? this[key as string] : this[(int)key]; }
|
|
set { throw new Exception("The method or operation is not implemented."); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ICollection Members
|
|
|
|
public void CopyTo(Array array, int index) {
|
|
myRow.CopyTo(array, index);
|
|
array.SetValue(myID, index + myRow.schema["id"].colNo);
|
|
}
|
|
|
|
public int Count { get { return myRow.Count; } }
|
|
|
|
public bool IsSynchronized { get { return myRow.IsSynchronized; } }
|
|
|
|
public object SyncRoot { get { return myRow.SyncRoot; } }
|
|
|
|
#endregion
|
|
|
|
#region IEnumerable Members
|
|
|
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return new BlueRowEnumerator(this); }
|
|
|
|
#endregion
|
|
}
|
|
|
|
private BlueTable myRows;
|
|
private int myID = 0;
|
|
/// <summary>
|
|
/// maps the table no to a dictionary containing the
|
|
/// local IDs to a row in the final big table
|
|
/// </summary>
|
|
private Dictionary<int, Dictionary<int, IBlueRow>> myIDMap = new Dictionary<int, Dictionary<int, IBlueRow>>();
|
|
|
|
public MutableAppendTable(IBlueTableSchema schema) { myRows = new BlueTable(schema); }
|
|
|
|
public IBlueRow addRow(IBlueRow r, int tableNo) {
|
|
if (!myIDMap.ContainsKey(tableNo))
|
|
myIDMap.Add(tableNo, new Dictionary<int, IBlueRow>());
|
|
IBlueRow nr = new MyRow(r, myID++); // BlueDataUtility.getNewReplacedRow(r, myID++, "id");
|
|
myRows.addRow(nr);
|
|
myIDMap[tableNo].Add((int)r["id"], nr);
|
|
return nr;
|
|
}
|
|
|
|
public IBlueRow removeRow(IBlueRow r, int tableNo) {
|
|
IBlueRow dr = myIDMap[tableNo][(int)r["id"]];
|
|
myRows.deleteRow(dr);
|
|
myIDMap[tableNo].Remove((int)r["id"]);
|
|
return dr;
|
|
}
|
|
|
|
public IBlueRowCollection removeTable(int tableNo) {
|
|
if (!myIDMap.ContainsKey(tableNo))
|
|
return null;
|
|
else {
|
|
BlueTable rv = new BlueTable(myRows.schema);
|
|
foreach (IBlueRow r in myIDMap[tableNo].Values)
|
|
rv.addRow(r);
|
|
myRows.deleteRows(rv);
|
|
myIDMap.Remove(tableNo);
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
public void clear() {
|
|
myRows.clear();
|
|
myIDMap.Clear();
|
|
}
|
|
|
|
#region IBlueRowCollection Members
|
|
|
|
public IBlueRow this[int id] { get { return myRows[id]; } }
|
|
|
|
public IBlueTableSchema schema { get { return myRows.schema; } }
|
|
|
|
public bool containsID(int id) { return myRows.containsID(id); }
|
|
|
|
#endregion
|
|
|
|
#region ICollection Members
|
|
|
|
public void CopyTo(Array array, int index) { myRows.CopyTo(array, index); }
|
|
|
|
public int Count { get { return myRows.Count; } }
|
|
|
|
public bool IsSynchronized { get { return myRows.IsSynchronized; } }
|
|
|
|
public object SyncRoot { get { return myRows.SyncRoot; } }
|
|
|
|
#endregion
|
|
|
|
#region IEnumerable Members
|
|
|
|
public System.Collections.IEnumerator GetEnumerator() { return myRows.GetEnumerator(); }
|
|
|
|
#endregion
|
|
}
|
|
/// <summary>
|
|
/// MutableStream can append multiple streams
|
|
/// as well as give the user the flexibility
|
|
/// to append (or remove) more streams at
|
|
/// runtime
|
|
/// </summary>
|
|
[DataStreamUserRespresentation("UnionStream")]
|
|
public class MutableAppendStream : ViewStream {
|
|
private bool mySubscriptionActive = false;
|
|
private MutableAppendTable myTable;
|
|
private int myMovingIndex;
|
|
private Dictionary<int, Pair<ViewStream, ViewStream>> myStreamIndex = new Dictionary<int, Pair<ViewStream, ViewStream>>();
|
|
private bool _allign_col_orders = true;
|
|
|
|
public MutableAppendStream(params ViewStream[] streams)
|
|
: this(new List<ViewStream>(streams)) { }
|
|
|
|
public MutableAppendStream(bool allign_col_order, params ViewStream[] streams)
|
|
: this(allign_col_order, new List<ViewStream>(streams)) { }
|
|
|
|
public MutableAppendStream(ICollection<ViewStream> streams)
|
|
: this(true, streams) { }
|
|
|
|
public MutableAppendStream(bool allign_col_orders, ICollection<ViewStream> streams) {
|
|
_allign_col_orders = allign_col_orders;
|
|
foreach (ViewStream vs in streams) {
|
|
myMovingIndex++;
|
|
ViewStream pj = new ChangeTableNameStream(vs, myMovingIndex.ToString());
|
|
if (_allign_col_orders)
|
|
pj = new ProjectStream(pj, "!");
|
|
myStreamIndex.Add(myMovingIndex, new Pair<ViewStream, ViewStream>(vs, pj));
|
|
}
|
|
}
|
|
|
|
public void addStream(ViewStream vs) {
|
|
myMovingIndex++;
|
|
///the change name is done to identify the callbacks, and the project to
|
|
///make all the schemas col orders the same
|
|
ViewStream pj = new ChangeTableNameStream(vs, myMovingIndex.ToString());
|
|
if (_allign_col_orders)
|
|
pj = new ProjectStream(pj, "!");
|
|
myStreamIndex.Add(myMovingIndex, new Pair<ViewStream, ViewStream>(vs, pj));
|
|
if (mySubscriptionActive)
|
|
pj.onChange += new ChangeDelegate(myHandleStreamChanges);
|
|
}
|
|
|
|
public void removeStream(ViewStream vs) {
|
|
int index = -1;
|
|
foreach (KeyValuePair<int, Pair<ViewStream, ViewStream>> p in myStreamIndex) {
|
|
if (p.Value.first == vs) {
|
|
index = p.Key;
|
|
if (mySubscriptionActive) {
|
|
p.Value.second.onChange -= new ChangeDelegate(myHandleStreamChanges);
|
|
if (myTable != null) {
|
|
IBlueRowCollection delRows = myTable.removeTable(p.Key);
|
|
if (delRows != null)
|
|
myFireEvent(new DataPacket(myTable, new BlueTable(myTable.schema), delRows));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (index > 0)
|
|
myStreamIndex.Remove(index);
|
|
}
|
|
}
|
|
|
|
protected override void myOnFirstSubscriber() {
|
|
mySubscriptionActive = true;
|
|
foreach (KeyValuePair<int, Pair<ViewStream, ViewStream>> p in myStreamIndex)
|
|
p.Value.second.onChange += new ChangeDelegate(myHandleStreamChanges);
|
|
}
|
|
|
|
protected override void myOnLastSubscriber() {
|
|
mySubscriptionActive = false;
|
|
foreach (KeyValuePair<int, Pair<ViewStream, ViewStream>> p in myStreamIndex)
|
|
p.Value.second.onChange -= new ChangeDelegate(myHandleStreamChanges);
|
|
if (myTable != null)
|
|
myTable.clear();
|
|
}
|
|
|
|
private void myHandleStreamChanges(object newValue) {
|
|
DataPacket dp = newValue as DataPacket;
|
|
myTable = myTable ?? new MutableAppendTable(new BlueTableSchema("MutableAppend", dp.schema.columnInfo));
|
|
BlueTable adds = new BlueTable(myTable.schema),
|
|
dels = new BlueTable(myTable.schema);
|
|
int index = Int32.Parse(dp.schema.tableName);
|
|
foreach (IBlueRow r in dp.deletedRows) {
|
|
IBlueRow dr = myTable.removeRow(r, index);
|
|
dels.addRow(dr);
|
|
}
|
|
foreach (IBlueRow r in dp.addedRows) {
|
|
IBlueRow nr = myTable.addRow(r, index);
|
|
adds.addRow(nr);
|
|
}
|
|
myFireEvent(new DataPacket(myTable, adds, dels));
|
|
}
|
|
}
|
|
}
|