381 lines
12 KiB
C#
381 lines
12 KiB
C#
using System.Collections;
|
|
using System.Collections.ObjectModel;
|
|
using System.Diagnostics;
|
|
using AyCode.Core.Enums;
|
|
using AyCode.Core.Extensions;
|
|
using AyCode.Core.Interfaces;
|
|
using AyCode.Services.SignalRs;
|
|
using TIAM.Services;
|
|
using TIAMWebApp.Shared.Application.Services;
|
|
|
|
namespace TIAMWebApp.Shared.Application.Utility
|
|
{
|
|
public class ChangeTracking<T>(DataChangeMode dataChangeMode, T newItem, T originalItem = default(T))where T: class, IId<Guid>
|
|
{
|
|
public DataChangeMode DataChangeMode { get; init; } = dataChangeMode;
|
|
public T NewItem { get; init; } = newItem;
|
|
public T OriginalItem { get; init; } = originalItem;
|
|
}
|
|
|
|
[Serializable]
|
|
[DebuggerDisplay("Count = {Count}")]
|
|
public class SignalRDataSource<T> : IList<T>, IList, IReadOnlyList<T> where T: class, IId<Guid>
|
|
{
|
|
protected readonly List<T> InnerList = [];
|
|
private readonly object _syncRoot = new();
|
|
|
|
protected Guid? ContextId;
|
|
protected AcSignalRClientBase SignalRClient;
|
|
protected readonly SignalRCrudTags SignalRCrudTags;
|
|
|
|
public SignalRDataSource(AcSignalRClientBase signalRClient, SignalRCrudTags signalRCrudTags, Guid? contextId = null, bool autoLoadDataSource = true)
|
|
{
|
|
ContextId = contextId;
|
|
|
|
SignalRCrudTags = signalRCrudTags;
|
|
SignalRClient = signalRClient;
|
|
|
|
if (autoLoadDataSource) LoadDataSource();
|
|
}
|
|
|
|
public bool IsSynchronized => true;
|
|
public object SyncRoot => _syncRoot;
|
|
public bool IsFixedSize => false;
|
|
|
|
/// <summary>
|
|
/// GetAllMessageTag
|
|
/// </summary>
|
|
/// <exception cref="ArgumentException"></exception>
|
|
/// <exception cref="NullReferenceException"></exception>
|
|
public void LoadDataSource()
|
|
{
|
|
if (SignalRCrudTags.GetAllMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.GetAllMessageTag == SignalRTags.None;");
|
|
|
|
lock (_syncRoot)
|
|
{
|
|
var resultList = SignalRClient.GetAllAsync<List<T>>(SignalRCrudTags.GetAllMessageTag, ContextId).GetAwaiter().GetResult() ?? throw new NullReferenceException();
|
|
|
|
Clear();
|
|
InnerList.AddRange(resultList);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// set: UpdateMessageTag
|
|
/// </summary>
|
|
/// <param name="index"></param>
|
|
/// <returns></returns>
|
|
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
|
public T this[int index]
|
|
{
|
|
get
|
|
{
|
|
if ((uint)index >= (uint)Count) throw new ArgumentOutOfRangeException(nameof(index));
|
|
|
|
lock (_syncRoot)
|
|
{
|
|
return InnerList[index];
|
|
}
|
|
}
|
|
set
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
Update(index, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public int Count
|
|
{
|
|
get
|
|
{
|
|
lock (_syncRoot) return InnerList.Count;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// AddMessageTag
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
/// <exception cref="ArgumentException"></exception>
|
|
public void Add(T item)
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
if (Contains(item))
|
|
throw new ArgumentException($@"It already contains this Id! Id: {item.Id}", nameof(item));
|
|
|
|
UnsafeAdd(item);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// AddMessageTag or UpdateMessageTag
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
/// <returns></returns>
|
|
public T AddOrUpdate(T item)
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
var index = IndexOf(item);
|
|
|
|
return index > -1 ? Update(index, item) : UnsafeAdd(item);
|
|
}
|
|
}
|
|
|
|
//public void AddRange(IEnumerable<T> collection)
|
|
//{
|
|
// lock (_syncRoot)
|
|
// {
|
|
|
|
// }
|
|
//}
|
|
|
|
private T UnsafeAdd(T item)
|
|
{
|
|
if (SignalRCrudTags.AddMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.AddMessageTag == SignalRTags.None;");
|
|
|
|
var result = SignalRClient.PostDataAsync(SignalRCrudTags.AddMessageTag, item).GetAwaiter().GetResult() ?? throw new NullReferenceException();
|
|
InnerList.Add(result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// AddMessageTag
|
|
/// </summary>
|
|
/// <param name="index"></param>
|
|
/// <param name="item"></param>
|
|
/// <exception cref="ArgumentException"></exception>
|
|
/// <exception cref="NullReferenceException"></exception>
|
|
public void Insert(int index, T item)
|
|
{
|
|
if (SignalRCrudTags.AddMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.AddMessageTag == SignalRTags.None;");
|
|
|
|
lock (_syncRoot)
|
|
{
|
|
if (Contains(item))
|
|
throw new ArgumentException($@"It already contains this Id! Id: {item.Id}", nameof(item));
|
|
|
|
var result = SignalRClient.PostDataAsync(SignalRCrudTags.AddMessageTag, item).GetAwaiter().GetResult() ?? throw new NullReferenceException();
|
|
InnerList.Insert(index, result);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// UpdateMessageTag
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
public T Update(T item) => Update(IndexOf(item), item);
|
|
|
|
/// <summary>
|
|
/// UpdateMessageTag
|
|
/// </summary>
|
|
/// <param name="index"></param>
|
|
/// <param name="item"></param>
|
|
/// /// <exception cref="ArgumentException"></exception>
|
|
/// /// <exception cref="NullReferenceException"></exception>
|
|
/// <exception cref="ArgumentNullException"></exception>
|
|
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
|
public T Update(int index, T item)
|
|
{
|
|
if (SignalRCrudTags.UpdateMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.UpdateMessageTag == SignalRTags.None;");
|
|
|
|
if (default(T) != null && item == null) throw new NullReferenceException(nameof(item));
|
|
if (item.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(item), "Update->item.Id.IsNullOrEmpty()");
|
|
if ((uint)index >= (uint)Count) throw new ArgumentOutOfRangeException(nameof(index));
|
|
|
|
lock (_syncRoot)
|
|
{
|
|
if (InnerList[index].Id != item.Id)
|
|
throw new ArgumentException($@"_list[index].Id != item.Id! Id: {item.Id}", nameof(item));
|
|
|
|
var result = SignalRClient.PostDataAsync(SignalRCrudTags.UpdateMessageTag, item).GetAwaiter().GetResult() ?? throw new NullReferenceException();
|
|
|
|
InnerList[index] = result;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// RemoveMessageTag
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
/// <returns></returns>
|
|
public bool Remove(T item)
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
var index = IndexOf(item);
|
|
|
|
if (index < 0) return false;
|
|
|
|
RemoveAt(index);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// RemoveMessageTag
|
|
/// </summary>
|
|
/// <param name="index"></param>
|
|
/// <exception cref="ArgumentException"></exception>
|
|
/// /// <exception cref="ArgumentNullException"></exception>
|
|
/// <exception cref="NullReferenceException"></exception>
|
|
public void RemoveAt(int index)
|
|
{
|
|
if (SignalRCrudTags.RemoveMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.RemoveMessageTag == SignalRTags.None;");
|
|
|
|
lock (_syncRoot)
|
|
{
|
|
var item = InnerList[index];
|
|
if (item.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(item), $@"RemoveAt->item.Id.IsNullOrEmpty(); index: {index}");
|
|
|
|
var result = SignalRClient.PostDataAsync(SignalRCrudTags.RemoveMessageTag, item).GetAwaiter().GetResult() ?? throw new NullReferenceException();
|
|
|
|
InnerList.RemoveAt(index);
|
|
}
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
lock (_syncRoot) InnerList.Clear();
|
|
}
|
|
|
|
public int IndexOf(T item)
|
|
{
|
|
lock (_syncRoot)
|
|
return InnerList.FindIndex(x => x.Id == item.Id);
|
|
}
|
|
|
|
public bool Contains(T item)
|
|
{
|
|
lock (_syncRoot)
|
|
return IndexOf(item) > -1;
|
|
}
|
|
|
|
public void CopyTo(T[] array) => CopyTo(array, 0);
|
|
|
|
public void CopyTo(T[] array, int arrayIndex)
|
|
{
|
|
lock (_syncRoot) InnerList.CopyTo(array, arrayIndex);
|
|
}
|
|
|
|
public int BinarySearch(int index, int count, T item, IComparer<T>? comparer)
|
|
{
|
|
if (index < 0)
|
|
throw new ArgumentOutOfRangeException(nameof(index));
|
|
if (count < 0)
|
|
throw new ArgumentOutOfRangeException(nameof(count));
|
|
if (Count - index < count)
|
|
throw new ArgumentException("Invalid length");
|
|
|
|
lock (_syncRoot)
|
|
return InnerList.BinarySearch(index, count, item, comparer);
|
|
}
|
|
|
|
public int BinarySearch(T item) => BinarySearch(0, Count, item, null);
|
|
public int BinarySearch(T item, IComparer<T>? comparer) => BinarySearch(0, Count, item, comparer);
|
|
|
|
public IEnumerator<T> GetEnumerator()
|
|
{
|
|
lock (_syncRoot)
|
|
return InnerList.ToList().GetEnumerator();
|
|
}
|
|
|
|
public ReadOnlyCollection<T> AsReadOnly() => new(this);
|
|
private static bool IsCompatibleObject(object? value) => (value is T) || (value == null && default(T) == null);
|
|
|
|
|
|
#region IList, ICollection
|
|
bool IList.IsReadOnly => false;
|
|
|
|
object? IList.this[int index]
|
|
{
|
|
get => this[index];
|
|
set
|
|
{
|
|
if (default(T) != null && value == null) throw new NullReferenceException(nameof(value));
|
|
|
|
try
|
|
{
|
|
this[index] = (T)value!;
|
|
}
|
|
catch (InvalidCastException)
|
|
{
|
|
throw new InvalidCastException(nameof(value));
|
|
}
|
|
}
|
|
}
|
|
|
|
int IList.Add(object? item)
|
|
{
|
|
if (default(T) != null && item == null) throw new NullReferenceException(nameof(item));
|
|
|
|
try
|
|
{
|
|
Add((T)item!);
|
|
}
|
|
catch (InvalidCastException)
|
|
{
|
|
throw new InvalidCastException(nameof(item));
|
|
}
|
|
|
|
return Count - 1;
|
|
}
|
|
|
|
void IList.Clear() => Clear();
|
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
bool IList.Contains(object? item) => IsCompatibleObject(item) && Contains((T)item!);
|
|
int IList.IndexOf(object? item) => (IsCompatibleObject(item)) ? IndexOf((T)item!) : -1;
|
|
|
|
void IList.Insert(int index, object? item)
|
|
{
|
|
if (default(T) != null && item == null) throw new NullReferenceException(nameof(item));
|
|
|
|
try
|
|
{
|
|
Insert(index, (T)item!);
|
|
}
|
|
catch (InvalidCastException)
|
|
{
|
|
throw new InvalidCastException(nameof(item));
|
|
}
|
|
}
|
|
|
|
void IList.Remove(object? item)
|
|
{
|
|
if (IsCompatibleObject(item)) Remove((T)item!);
|
|
}
|
|
|
|
void ICollection<T>.Clear() => Clear();
|
|
|
|
void ICollection.CopyTo(Array array, int arrayIndex)
|
|
{
|
|
if ((array != null) && (array.Rank != 1))
|
|
{
|
|
throw new ArgumentException();
|
|
}
|
|
|
|
try
|
|
{
|
|
//TODO: _list.ToArray() - ez nem az igazi... - J.
|
|
Array.Copy(InnerList.ToArray(), 0, array!, arrayIndex, InnerList.Count);
|
|
}
|
|
catch (ArrayTypeMismatchException)
|
|
{
|
|
throw new ArrayTypeMismatchException();
|
|
}
|
|
}
|
|
|
|
int ICollection.Count => Count;
|
|
int ICollection<T>.Count => Count;
|
|
bool ICollection<T>.IsReadOnly => false;
|
|
void IList<T>.RemoveAt(int index) => RemoveAt(index);
|
|
int IReadOnlyCollection<T>.Count => Count;
|
|
#endregion IList, ICollection
|
|
}
|
|
}
|