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(DataChangeMode dataChangeMode, T newItem, T originalItem = default(T))where T: class, IId { 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 : IList, IList, IReadOnlyList where T: class, IId { protected readonly List 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; /// /// GetAllMessageTag /// /// /// public void LoadDataSource() { if (SignalRCrudTags.GetAllMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.GetAllMessageTag == SignalRTags.None;"); lock (_syncRoot) { var resultList = SignalRClient.GetAllAsync>(SignalRCrudTags.GetAllMessageTag, ContextId).GetAwaiter().GetResult() ?? throw new NullReferenceException(); Clear(); InnerList.AddRange(resultList); } } /// /// set: UpdateMessageTag /// /// /// /// 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; } } /// /// AddMessageTag /// /// /// 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); } } /// /// AddMessageTag or UpdateMessageTag /// /// /// public T AddOrUpdate(T item) { lock (_syncRoot) { var index = IndexOf(item); return index > -1 ? Update(index, item) : UnsafeAdd(item); } } //public void AddRange(IEnumerable 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; } /// /// AddMessageTag /// /// /// /// /// 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); } } /// /// UpdateMessageTag /// /// public T Update(T item) => Update(IndexOf(item), item); /// /// UpdateMessageTag /// /// /// /// /// /// /// /// /// 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; } } /// /// RemoveMessageTag /// /// /// public bool Remove(T item) { lock (_syncRoot) { var index = IndexOf(item); if (index < 0) return false; RemoveAt(index); return true; } } /// /// RemoveMessageTag /// /// /// /// /// /// 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? 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? comparer) => BinarySearch(0, Count, item, comparer); public IEnumerator GetEnumerator() { lock (_syncRoot) return InnerList.ToList().GetEnumerator(); } public ReadOnlyCollection 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.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.Count => Count; bool ICollection.IsReadOnly => false; void IList.RemoveAt(int index) => RemoveAt(index); int IReadOnlyCollection.Count => Count; #endregion IList, ICollection } }