Ooui-tws-port/Ooui/Node.cs

150 lines
4.5 KiB
C#
Raw Normal View History

2017-06-12 20:45:27 +00:00
using System;
using System.Collections.Generic;
using System.Linq;
namespace Ooui
{
public abstract class Node
{
public string Id { get; private set; } = GenerateId ();
2017-06-12 20:46:42 +00:00
public Mapping Mapping { get; private set; }
2017-06-12 20:45:27 +00:00
readonly List<Node> children = new List<Node> ();
readonly List<Message> messages = new List<Message> ();
readonly List<Message> stateMessages = new List<Message> ();
2017-06-13 03:31:47 +00:00
public event Action<Message> MessageLogged;
public IEnumerable<Message> AllMessages =>
messages
.Concat (from c in children from m in c.AllMessages select m)
2017-06-13 07:03:01 +00:00
.OrderBy (x => x.Id);
2017-06-13 03:31:47 +00:00
2017-06-13 07:51:24 +00:00
public string TextContent {
get { return String.Join ("", from c in children select c.TextContent); }
set {
ReplaceAll (new Text (value ?? ""));
}
}
2017-06-12 20:45:27 +00:00
public Node ()
{
2017-06-12 20:46:42 +00:00
Mapping = Mapping.Get (GetType ());
2017-06-12 20:45:27 +00:00
LogCreate ();
}
public Node AppendChild (Node newChild)
{
return InsertBefore (newChild, null);
}
public Node ParentNode { get; private set; }
public Node InsertBefore (Node newChild, Node referenceChild)
{
if (referenceChild == null) {
children.Add (newChild);
}
else {
var index = children.IndexOf (referenceChild);
if (index < 0) {
throw new ArgumentException ("Reference must be a child of this element", nameof(referenceChild));
}
children.Insert (index, newChild);
}
newChild.ParentNode = this;
LogCall ("insertBefore", newChild, referenceChild);
return newChild;
}
public Node RemoveChild (Node child)
{
if (!children.Remove (child)) {
throw new ArgumentException ("Child not contained in this element", nameof(child));
}
child.ParentNode = null;
LogCall ("removeChild", child);
return child;
}
2017-06-13 07:51:24 +00:00
protected void ReplaceAll (Node newNode)
{
var toRemove = new List<Node> (children);
foreach (var c in toRemove)
RemoveChild (c);
InsertBefore (newNode, null);
}
2017-06-12 20:45:27 +00:00
protected void Log (Message message)
{
messages.Add (message);
switch (message.MessageType) {
case MessageType.Create:
stateMessages.Add (message);
break;
case MessageType.Set:
{
var old = stateMessages.FirstOrDefault (
x => x.MessageType == MessageType.Set &&
2017-06-13 03:31:47 +00:00
x.Key == message.Key);
2017-06-12 20:45:27 +00:00
if (old != null) {
stateMessages.Remove (old);
}
stateMessages.Add (message);
}
break;
}
2017-06-13 03:31:47 +00:00
MessageLogged?.Invoke (message);
2017-06-12 20:45:27 +00:00
}
protected void LogCreate ()
{
Log (new Message {
MessageType = MessageType.Create,
TargetId = Id,
2017-06-13 07:03:01 +00:00
Key = Mapping.TagName,
2017-06-12 20:45:27 +00:00
});
}
protected void LogCall (string methodName, params object[] args)
{
Log (new Message {
MessageType = MessageType.Call,
TargetId = Id,
2017-06-13 03:31:47 +00:00
Key = methodName,
2017-06-13 07:51:24 +00:00
Value = args,
2017-06-12 20:45:27 +00:00
});
}
2017-06-13 07:03:01 +00:00
protected void LogSet (string attributeName, object value)
2017-06-12 20:45:27 +00:00
{
2017-06-13 04:50:15 +00:00
Log (new Message {
2017-06-12 20:45:27 +00:00
MessageType = MessageType.Set,
TargetId = Id,
2017-06-13 07:03:01 +00:00
Key = attributeName,
2017-06-13 04:50:15 +00:00
Value = value,
});
2017-06-12 20:45:27 +00:00
}
2017-06-13 07:03:01 +00:00
protected bool SetProperty<T> (ref T backingStore, T newValue, string attributeName, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
2017-06-12 20:45:27 +00:00
{
if (!backingStore.Equals (newValue)) {
backingStore = newValue;
2017-06-13 07:03:01 +00:00
LogSet (attributeName, newValue);
2017-06-12 20:45:27 +00:00
return true;
}
return false;
}
2017-06-13 07:03:01 +00:00
static long idCounter = 0;
2017-06-12 20:45:27 +00:00
static string GenerateId ()
{
2017-06-13 07:03:01 +00:00
var id = System.Threading.Interlocked.Increment (ref idCounter);
return "n" + id;
2017-06-12 20:45:27 +00:00
}
}
}