2026-01-26 14:51:28 +09:00

232 lines
12 KiB
C#

/*
* 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<DifferenceItem> difference, string prefix, object org, object diff);
#region Difference Check : 공용 Method
/// <summary>
/// C#에서 기본 제공되는 데이터형의 difference check (각 Type별 체크)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="difference">체크 결과를 return하기 위한 string</param>
/// <param name="prefix">차이가 있을 경우, 해당 데이터 변경점 앞에 붙일 string(예: Module #1)</param>
/// <param name="org">원본</param>
/// <param name="diff">비교 대상</param>
/// <returns></returns>
protected bool CheckPrimaryType<T>(ref List<DifferenceItem> difference, string prefix, object org, object diff)
{
if (org is IList<T> orgList && diff is IList<T> diffList) {
for (int i = 0; i < Math.Max(orgList.Count(), diffList.Count()); i++) {
if (i < orgList.Count() && i < diffList.Count()) {
CheckPrimaryType<T>(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;
}
/// <summary>
/// C#에서 기본 제공되는 데이터형의 단순 "before -> after" string 반환
/// </summary>
/// <param name="org">원본</param>
/// <param name="diff">비교 대상</param>
/// <returns></returns>
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);
}
/// <summary>
/// C#에서 기본 제공되는 데이터형의 difference check (외부에서 호출하는 일괄 체크 함수)
/// </summary>
/// <param name="prefix">차이가 있을 경우, 해당 데이터 변경점 앞에 붙일 string(예: Module #1)</param>
/// <param name="difference">체크 결과를 return하기 위한 string</param>
/// <param name="org">원본</param>
/// <param name="diff">비교 대상</param>
/// <returns></returns>
public bool CheckPrimaryTypeAll(ref List<DifferenceItem> 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<double>(ref difference, prefix, org, diff);
if (!ret) ret = CheckPrimaryType<float>(ref difference, prefix, org, diff);
if (!ret) ret = CheckPrimaryType<ulong>(ref difference, prefix, org, diff);
if (!ret) ret = CheckPrimaryType<long>(ref difference, prefix, org, diff);
if (!ret) ret = CheckPrimaryType<uint>(ref difference, prefix, org, diff);
if (!ret) ret = CheckPrimaryType<int>(ref difference, prefix, org, diff);
if (!ret) ret = CheckPrimaryType<ushort>(ref difference, prefix, org, diff);
if (!ret) ret = CheckPrimaryType<short>(ref difference, prefix, org, diff);
if (!ret) ret = CheckPrimaryType<string>(ref difference, prefix, org, diff);
if (!ret) ret = CheckPrimaryType<char>(ref difference, prefix, org, diff);
if (!ret) ret = CheckPrimaryType<bool>(ref difference, prefix, org, diff);
return ret;
}
/// <summary>
/// 사용자가 추가한 Class의 difference check (각 Type별 체크) : Primary Type이 나올 때까지 상속자에서 구현한 CheckDifference를 반복
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="prefix"></param>
/// <param name="title"></param>
/// <param name="difference"></param>
/// <param name="org"></param>
/// <param name="diff"></param>
/// <returns></returns>
protected bool CheckCustomType<T>(ref List<DifferenceItem> 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<T> obserOrgList && diff is ObservableCollection<T> obserDiffList) {
org = obserOrgList.ToList();
diff = obserDiffList.ToList();
}
if (org is IList<T> orgList && diff is IList<T> 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
}
}