/* * Copyright (c) 2022 LG Electronics Inc. * SPDX-License-Identifier: LicenseRef-LGE-Proprietary */ using Aurora.Api; using Aurora.View; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace AuroraUIComponent.Util { public class DifferenceItem : NotifyPropertyChangedBase { private string _Item; public string Item { get => _Item; set => SetProperty(ref _Item, value); } private string _Before; public string Before { get => _Before; set => SetProperty(ref _Before, value); } private string _After; public string After { get => _After; set => SetProperty(ref _After, value); } public DifferenceItem(string item, string before, string after) { Item = item; Before = before; After = after; } public override string ToString() { return $"[{Item}] {Before} -> {After}"; } } public abstract class IDataDifferenceCheck : NotifyPropertyChangedBase { public abstract bool CheckDifference(ref List difference, string prefix, object org, object diff); #region Difference Check : 공용 Method /// /// C#에서 기본 제공되는 데이터형의 difference check (각 Type별 체크) /// /// /// 체크 결과를 return하기 위한 string /// 차이가 있을 경우, 해당 데이터 변경점 앞에 붙일 string(예: Module #1) /// 원본 /// 비교 대상 /// protected bool CheckPrimaryType(ref List difference, string prefix, object org, object diff) { if (org is IList orgList && diff is IList diffList) { for (int i = 0; i < Math.Max(orgList.Count(), diffList.Count()); i++) { if (i < orgList.Count() && i < diffList.Count()) { CheckPrimaryType(ref difference, $"{prefix} #{i + 1}", orgList[i], diffList[i]); } else if (i < orgList.Count()) { //difference = difference + "\n" + $"{prefix} #{i + 1} :: [{orgList[i]}] Deleted"; difference.Add(new DifferenceItem($"{prefix} #{i + 1}", orgList[i].ToString(), "Deleted")); } else if (i < diffList.Count()) { //difference = difference + "\n" + $"{prefix} #{i + 1} :: [{diffList[i]}] Added"; difference.Add(new DifferenceItem($"{prefix} #{i + 1}", "Added", diffList[i].ToString())); } } return true; } if (org is T orgValue && diff is T diffValue) { var diffString = GetDiffString(orgValue, diffValue); if (!string.IsNullOrEmpty(diffString.Item1) || !string.IsNullOrEmpty(diffString.Item2)) { //difference = difference + "\n" + $"{prefix} :: " + diffString; difference.Add(new DifferenceItem(prefix, diffString.Item1, diffString.Item2)); } } return false; } /// /// C#에서 기본 제공되는 데이터형의 단순 "before -> after" string 반환 /// /// 원본 /// 비교 대상 /// protected (string, string) GetDiffString(object org, object diff) { if (org is double doubleOrgValue && diff is double doubleDiffValue && doubleOrgValue != doubleDiffValue) { return (doubleOrgValue.ToString("F3"), doubleDiffValue.ToString("F3")); } else if (org is float floatOrgValue && diff is float floatDiffValue && floatOrgValue != floatDiffValue) { return (floatOrgValue.ToString("F3"), floatDiffValue.ToString("F3")); } else if (org is ulong ulongOrgValue && diff is ulong ulongDiffValue && ulongOrgValue != ulongDiffValue) { return (ulongOrgValue.ToString(), ulongDiffValue.ToString()); } else if (org is long longOrgValue && diff is long longDiffValue && longOrgValue != longDiffValue) { return (longOrgValue.ToString(), longDiffValue.ToString()); } else if (org is uint uintOrgValue && diff is uint uintDiffValue && uintOrgValue != uintDiffValue) { return (uintOrgValue.ToString(), uintDiffValue.ToString()); } else if (org is int intOrgValue && diff is int intDiffValue && intOrgValue != intDiffValue) { return (intOrgValue.ToString(), intDiffValue.ToString()); } else if (org is ushort ushortOrgValue && diff is ushort ushortDiffValue && ushortOrgValue != ushortDiffValue) { return (ushortOrgValue.ToString(), ushortDiffValue.ToString()); } else if (org is short shortOrgValue && diff is short shortDiffValue && shortOrgValue != shortDiffValue) { return (shortOrgValue.ToString(), shortDiffValue.ToString()); } else if (org is string stringOrgValue && diff is string stringDiffValue && stringOrgValue != stringDiffValue) { return (stringOrgValue, stringDiffValue); } else if (org is char charOrgValue && diff is char charDiffValue && charOrgValue != charDiffValue) { return (charOrgValue.ToString(), charDiffValue.ToString()); } else if (org is bool boolOrgValue && diff is bool boolDiffValue && boolOrgValue != boolDiffValue) { return (boolOrgValue.ToString(), boolDiffValue.ToString()); } return (null, null); } /// /// C#에서 기본 제공되는 데이터형의 difference check (외부에서 호출하는 일괄 체크 함수) /// /// 차이가 있을 경우, 해당 데이터 변경점 앞에 붙일 string(예: Module #1) /// 체크 결과를 return하기 위한 string /// 원본 /// 비교 대상 /// public bool CheckPrimaryTypeAll(ref List difference, string prefix, object org, object diff) { // JsonIgnore 설정되어 있으면 skip var jsonIgnoreAttribute = org.GetType().GetCustomAttributes(typeof(JsonIgnoreAttribute), false).FirstOrDefault(); if (jsonIgnoreAttribute != null) { //Logger.V($"Ignore {org.GetType().Name} has JsonIgnore attribute."); return true; } else { //Logger.V($"Ignore {org.GetType().Name} does not have JsonIgnore attribute."); } if (org == null && diff == null) { return true; } else if (diff == null) { //difference = difference + "\n" + $"{prefix} :: [{org}] Deleted"; difference.Add(new DifferenceItem(prefix, org.ToString(), "Deleted")); return true; } else if (org == null) { //difference = difference + "\n" + $"{prefix} :: [{diff}] Added"; difference.Add(new DifferenceItem(prefix, "Added", diff.ToString())); return true; } // Enum Check if (org.GetType().IsEnum && diff.GetType().IsEnum) { if (org.ToString() != diff.ToString()) { //difference = difference + "\n" + prefix + " :: " + org.ToString() + "->" + diff.ToString(); difference.Add(new DifferenceItem(prefix, org.ToString(), diff.ToString())); } return true; } bool ret = CheckPrimaryType(ref difference, prefix, org, diff); if (!ret) ret = CheckPrimaryType(ref difference, prefix, org, diff); if (!ret) ret = CheckPrimaryType(ref difference, prefix, org, diff); if (!ret) ret = CheckPrimaryType(ref difference, prefix, org, diff); if (!ret) ret = CheckPrimaryType(ref difference, prefix, org, diff); if (!ret) ret = CheckPrimaryType(ref difference, prefix, org, diff); if (!ret) ret = CheckPrimaryType(ref difference, prefix, org, diff); if (!ret) ret = CheckPrimaryType(ref difference, prefix, org, diff); if (!ret) ret = CheckPrimaryType(ref difference, prefix, org, diff); if (!ret) ret = CheckPrimaryType(ref difference, prefix, org, diff); if (!ret) ret = CheckPrimaryType(ref difference, prefix, org, diff); return ret; } /// /// 사용자가 추가한 Class의 difference check (각 Type별 체크) : Primary Type이 나올 때까지 상속자에서 구현한 CheckDifference를 반복 /// /// /// /// /// /// /// /// protected bool CheckCustomType(ref List difference, string prefix, object org, object diff) { // Null Check if (org == null && diff == null) { return true; } else if (diff == null) { //difference = difference + "\n" + $"{prefix} :: [{org}] Deleted"; difference.Add(new DifferenceItem(prefix, org.ToString(), "Deleted")); return true; } else if (org == null) { //difference = difference + "\n" + $"{prefix} :: [{diff}] Added"; difference.Add(new DifferenceItem(prefix, "Added", diff.ToString())); return true; } // Logger.V("TEST", prefix); // List Check if (org is ObservableCollection obserOrgList && diff is ObservableCollection obserDiffList) { org = obserOrgList.ToList(); diff = obserDiffList.ToList(); } if (org is IList orgList && diff is IList diffList) { for (int i = 0; i < Math.Max(orgList.Count(), diffList.Count()); i++) { if (orgList.Count > i && diffList.Count > i) { CheckDifference(ref difference, $"{prefix} #{i + 1}", orgList[i], diffList[i]); } else if (i < orgList.Count()) { //difference = difference + "\n" + $"{prefix} #{i + 1} :: [{orgList[i]}] Deleted"; difference.Add(new DifferenceItem($"{prefix} #{i + 1}", org.ToString(), "Deleted")); } else if (i < diffList.Count()) { //difference = difference + "\n" + $"{prefix} #{i + 1} :: [{diffList[i]}] Added"; difference.Add(new DifferenceItem($"{prefix} #{i + 1}", "Added", diff.ToString())); } } return true; } // Object Check if (org.GetType() == typeof(T) && diff.GetType() == typeof(T)) { PropertyInfo[] sourceProperties = typeof(T).GetProperties(); foreach (PropertyInfo sourceProperty in sourceProperties) { CheckDifference(ref difference, $"{prefix} [{sourceProperty.Name}]", sourceProperty.GetValue(org), sourceProperty.GetValue(diff)); } return true; } return false; } #endregion } }