using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; namespace UVC.Data { /// /// DataObject 객체 컬렉션의 변경사항을 추적하는 데이터 배열 클래스 /// public class DataArray : List, IDataObject { // 추가 된 항목 목록 protected List addedList = new List(); // 제거 된 항목 목록 protected List removedList = new List(); // 수정 된 항목 목록 protected List modifiedList = new List(); // 추가된 항목에 접근할 수 있는 읽기 전용 컬렉션 public ReadOnlyCollection AddedItems => addedList.AsReadOnly(); // 제거된 항목에 접근할 수 있는 읽기 전용 컬렉션 public ReadOnlyCollection RemovedItems => removedList.AsReadOnly(); // 제거된 항목에 접근할 수 있는 읽기 전용 컬렉션 public ReadOnlyCollection ModifiedList => modifiedList.AsReadOnly(); /// /// 변경 추적 활성화 여부 /// public bool IsChangeTracking { get; set; } = false; /// /// 기본 생성자 /// public DataArray() : base() { } /// /// 초기 용량을 지정하는 생성자 /// /// 초기 용량 public DataArray(int capacity) : base(capacity) { } /// /// 기존 컬렉션으로부터 생성하는 생성자 /// /// 초기 항목을 포함하는 컬렉션 public DataArray(IEnumerable collection) : base(collection) { } public DataArray(string jsonString) : base() { if (!string.IsNullOrEmpty(jsonString)) { try { JArray jArray = JArray.Parse(jsonString); foreach (var item in jArray) { Add(ConvertToDataObject(item)); } } catch (Exception ex) { throw new ArgumentException("Invalid JSON string format.", nameof(jsonString), ex); } } } /// /// JArray로부터 DataArray를 생성하는 생성자 /// /// JSON 배열 public DataArray(JArray jArray) : base() { if (jArray != null) { foreach (var item in jArray) { Add(ConvertToDataObject(item)); } } } /// /// JToken을 DataObject로 변환합니다. /// private DataObject ConvertToDataObject(JToken token) { if (token.Type == JTokenType.Object) { return new DataObject((JObject)token); } else { // JObject가 아닌 경우, 새 DataObject를 만들고 값을 넣어줍니다 var dataObject = new DataObject(); dataObject.Add("value", ConvertJTokenToObject(token)); return dataObject; } } private object ConvertJTokenToObject(JToken token) { switch (token.Type) { case JTokenType.String: return token.ToString(); case JTokenType.Integer: return token.ToObject(); case JTokenType.Float: return token.ToObject(); case JTokenType.Boolean: return token.ToObject(); case JTokenType.Object: return new DataObject((JObject)token); case JTokenType.Array: JArray array = (JArray)token; return new DataArray(array); default: return token.ToString(); } } /// /// 항목을 추가합니다. /// /// 추가할 항목 public new void Add(DataObject item) { base.Add(item); // 변경 사항을 추적하고 이벤트 발생 if (IsChangeTracking) { int index = Count - 1; addedList.Add(item); } } /// /// 항목을 제거합니다. /// /// 제거할 항목 /// 제거 성공 여부 public new bool Remove(DataObject item) { int index = IndexOf(item); if (index >= 0) { RemoveAt(index); return true; } return false; } /// /// 지정된 인덱스의 항목을 제거합니다. /// /// 제거할 항목의 인덱스 public new void RemoveAt(int index) { if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException(nameof(index)); DataObject removedItem = this[index]; base.RemoveAt(index); if (IsChangeTracking) { removedList.Add(removedItem); } } /// /// 컬렉션의 모든 항목을 제거합니다. /// public new void Clear() { if (Count > 0) { var oldItems = new List(this); base.Clear(); if (IsChangeTracking) { // 모든 항목을 제거 목록에 추가 removedList.AddRange(oldItems); } } } /// /// 지정된 인덱스에 항목을 삽입합니다. /// /// 삽입할 위치 /// 삽입할 항목 public new void Insert(int index, DataObject item) { base.Insert(index, item); if (IsChangeTracking) { addedList.Add(item); } } /// /// 지정된 인덱스의 항목을 교체합니다. /// /// 교체할 위치 /// 새 항목 public new DataObject this[int index] { get { return base[index]; } set { if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException(nameof(index)); DataObject oldItem = base[index]; base[index] = value; if (IsChangeTracking) { addedList.Add(value); removedList.Add(oldItem); } } } /// /// 범위의 항목을 추가합니다. /// /// 추가할 항목의 컬렉션 public new void AddRange(IEnumerable collection) { if (collection == null) throw new ArgumentNullException(nameof(collection)); int startIndex = Count; base.AddRange(collection); if (IsChangeTracking) { var items = collection.ToList(); for (int i = 0; i < items.Count; i++) { addedList.Add(items[i]); } } } /// /// 변경된 인덱스 목록을 초기화합니다. /// public void ResetChangedIndices() { addedList.Clear(); removedList.Clear(); modifiedList.Clear(); } /// /// 변경 내역을 저장하지 않고 항목을 추가합니다. /// /// 추가할 항목 public void AddWithoutTracking(DataObject item) { bool oldTracking = IsChangeTracking; IsChangeTracking = false; Add(item); IsChangeTracking = oldTracking; } /// /// DataArray를 JArray로 변환합니다. /// public JArray ToJArray() { JArray array = new JArray(); foreach (var item in this) { array.Add(item); } return array; } /// /// DataArray를 JArray로 암시적 변환합니다. /// public static implicit operator JArray(DataArray dataArray) { return dataArray.ToJArray(); } /// /// JArray를 DataArray로 암시적 변환합니다. /// public static implicit operator DataArray(JArray jArray) { return new DataArray(jArray); } } }