ln.types/odb/ng/DocumentChanges.cs

116 lines
3.3 KiB
C#

using System;
using System.Collections.Generic;
using ln.types.odb.values;
using System.Xml.Serialization;
using System.Linq;
namespace ln.types.odb.ng
{
public class DocumentChanges
{
public Document Source { get; }
public Document Destination { get; }
List<DocumentChange> changes = new List<DocumentChange>();
public DocumentChange[] Changes => changes.ToArray();
public DocumentChanges(Document src,Document dst)
{
Source = src;
Destination = dst;
diffDocument(src, dst);
}
private void diffDocument(Document src, Document dst) => diffDocument(new Stack<ODBValue>(), src, dst);
private void diffDocument(Stack<ODBValue> path,Document src,Document dst)
{
HashSet<ODBValue> keys = new HashSet<ODBValue>(src.Keys);
foreach (ODBValue key in dst.Keys)
keys.Add(key);
foreach (ODBValue key in keys)
{
path.Push(key);
diff(path, src[key], dst[key]);
path.Pop();
}
}
private void diffList(Stack<ODBValue> path,ODBList src,ODBList dst)
{
int commonLength = src.Count < dst.Count ? src.Count : dst.Count;
for (int i = 0; i < commonLength; i++)
{
path.Push(i);
diff(path, src[i], dst[i]);
path.Pop();
}
for (int i = commonLength; i < src.Count; i++)
{
path.Push(i);
diff(path, src[i], null);
path.Pop();
}
for (int i = commonLength; i < dst.Count; i++)
{
path.Push(i);
diff(path, ODBNull.Instance, dst[i]);
path.Pop();
}
}
private void diff(Stack<ODBValue> path,ODBValue srcValue,ODBValue dstValue)
{
if ((srcValue is ODBList) && (dstValue is ODBList))
{
diffList(path, srcValue as ODBList, dstValue as ODBList);
}
else if ((srcValue is Document) && (dstValue is Document))
{
diffDocument(path, srcValue as Document, dstValue as Document);
}
else if (!srcValue.Equals(dstValue))
{
changes.Add(new DocumentChange(path.Reverse(), dstValue));
}
}
public class DocumentChange
{
public ODBValue[] Path { get; }
public ODBValue Key => Path[Path.Length - 1];
public ODBValue Value { get; }
public DocumentChange(ODBValue value)
{
Value = value;
}
public DocumentChange(IEnumerable<ODBValue> path,ODBValue value)
:this(value)
{
if (path is ODBValue[])
Path = path as ODBValue[];
else
Path = path.ToArray();
}
public void Apply(Document document)
{
}
public override string ToString()
{
return String.Format("[DocumentChange Path={0} Value={1}]", String.Join("/", Path.Select((x) => x?.AsString)), Value);
}
}
}
}