using System;
using System.Collections.Generic;
using System.Linq;
namespace Ariadne.UnitTests
{
///
/// Saves an arc as plain objects, for testing arcs without a save library.
///
public class ArcRecord : IArcWriter, IArcReader
{
public readonly Dictionary Fields = new Dictionary(StringComparer.Ordinal);
///
/// This field holds the locals written at this level, which leave out those of the calls it holds.
///
public readonly Dictionary Locals = new Dictionary(StringComparer.Ordinal);
///
/// This field holds what each call written at this level saved, by the name the call was given.
///
public readonly Dictionary Scopes =
new Dictionary(StringComparer.Ordinal);
///
/// This field holds the type each field and local was written as, by key.
///
public readonly Dictionary Types = new Dictionary(StringComparer.Ordinal);
///
/// This field holds each arc handed to Publish, in order.
///
public readonly List Published = new List();
// The record of the whole arc, which is this one unless this holds the locals of a call.
private readonly ArcRecord root;
public ArcRecord()
{
root = this;
}
private ArcRecord(ArcRecord root)
{
this.root = root;
}
public List Cursor { get; } = new List();
IReadOnlyList IArcReader.Cursor
{
get
{
return root.Cursor;
}
}
public bool Finished { get; set; }
bool IArcReader.Finished
{
get
{
return root.Finished;
}
}
public IEnumerable LocalKeys
{
get
{
return Locals.Keys;
}
}
public IEnumerable ScopeNames
{
get
{
return Scopes.Keys;
}
}
///
/// Returns every local written, by the path of calls it was written under and its key, eg:
/// Run.first/Step.gate .
///
public Dictionary AllLocals()
{
var returnMe = new Dictionary(StringComparer.Ordinal);
var pending = new Stack>();
pending.Push(new KeyValuePair("", this));
while (pending.Count > 0)
{
KeyValuePair level = pending.Pop();
foreach (KeyValuePair local in level.Value.Locals)
{
returnMe.Add(level.Key + local.Key, local.Value);
}
foreach (KeyValuePair scope in level.Value.Scopes)
{
pending.Push(new KeyValuePair(level.Key + scope.Key, scope.Value));
}
}
return returnMe;
}
public static ArcRecord Of(Arc arc)
{
var returnMe = new ArcRecord();
arc.Save(returnMe);
return returnMe;
}
void IArcWriter.Cursor(IReadOnlyList cursor)
{
root.Cursor.Clear();
root.Cursor.AddRange(cursor);
}
void IArcWriter.Finished(bool finished)
{
root.Finished = finished;
}
/// The arc already wrote a field with this key.
public void Field(string key, T value)
{
root.Fields.Add(key, value);
root.Types.Add(key, typeof(T));
}
/// The arc already wrote a local with this key.
public void Local(string key, T value)
{
Locals.Add(key, value);
Types.Add(key, typeof(T));
}
/// The arc already wrote a call with this name.
public IArcWriter Scope(string name)
{
var returnMe = new ArcRecord(root);
Scopes.Add(name, returnMe);
return returnMe;
}
private static bool TryGet(Dictionary values, string key, out T value)
{
object found;
if (!values.TryGetValue(key, out found))
{
value = default(T);
return false;
}
value = (T)found;
return true;
}
///
/// This field holds the type arguments written at this level, or null if none were.
///
public Type[] SavedTypeArguments;
public void TypeArguments(params Type[] types)
{
SavedTypeArguments = types;
}
public bool TryTypeArguments(out Type[] types)
{
types = SavedTypeArguments;
return types != null;
}
public bool TryField(string key, out T value)
{
return TryGet(root.Fields, key, out value);
}
public bool HasField(string key)
{
return root.Fields.ContainsKey(key);
}
public bool TryLocal(string key, out T value)
{
return TryGet(Locals, key, out value);
}
public bool TryScope(string name, out IArcReader scope)
{
ArcRecord found;
bool returnMe = Scopes.TryGetValue(name, out found);
scope = found;
return returnMe;
}
public void Publish(object built)
{
root.Published.Add(built);
}
}
}