using System;
using System.Collections.Generic;
using Vellum;
namespace Amphora.Vellum
{
///
/// Saves an OrderedDictionary as a table holding a list of its key and value pairs in order, and its comparer
/// unless that's the default.
///
public sealed class OrderedDictionaryConverter<[Saveable] KeyType, [Saveable] ValueType>
: SaveContainerConverter>
{
// A list of pairs rather than a map, since a map is written sorted and this order is the point.
public const string EntriesKey = "entries";
public const string KeyKey = "key";
public const string ValueKey = "value";
public override SaveNode Write(OrderedDictionary value, SaveSession session)
{
SaveNode entries = SaveNode.NewList();
foreach (var entry in value)
{
SaveNode pair = SaveNode.NewTable();
pair.Entries[KeyKey] = session.ToNode(entry.Key);
pair.Entries[ValueKey] = session.ToNode(entry.Value);
entries.Items.Add(pair);
}
SaveNode returnMe = SaveNode.NewTable();
SavedComparer.Write(returnMe, value.Comparer);
returnMe.Entries[EntriesKey] = entries;
return returnMe;
}
public override OrderedDictionary Allocate(SaveNode node, SaveSession session)
{
node.RequireEntry(EntriesKey).RequireItems();
return new OrderedDictionary(SavedComparer.Read(node));
}
// A pair that can't be loaded whole is left out, and the session's Sandbox records why.
public override void Fill(OrderedDictionary blank, SaveNode node, SaveSession session)
{
SaveNode entries = node.RequireEntry(EntriesKey);
IReadOnlyList pairs = entries.RequireItems();
for (int i = 0; i < pairs.Count; ++i)
{
try
{
var reader = new SaveReader(pairs[i], session);
KeyType key = reader.Require(KeyKey);
SavedEntries.RejectRepeatedKey(blank, key, pairs[i].Entries[KeyKey]);
blank.Add(key, reader.Require(ValueKey));
}
catch (Exception exception) when (LoadSandbox.CanRecover(exception))
{
session.RecordFailure(exception, entries, i);
}
}
}
public override bool FillNeedsFilledPart(Type partType)
{
return partType == typeof(KeyType);
}
public override bool TryListChildren(SaveNode node, ChildList children)
{
SaveNode entries;
if (!node.TryGetEntry(EntriesKey, out entries))
{
return false;
}
IReadOnlyList pairs;
if (!entries.TryGetItems(out pairs))
{
return false;
}
foreach (SaveNode pair in pairs)
{
SaveNode key;
SaveNode value;
if (!pair.TryGetEntry(KeyKey, out key) || !pair.TryGetEntry(ValueKey, out value))
{
return false;
}
children.Add(key, typeof(KeyType));
children.Add(value, typeof(ValueType));
}
return true;
}
}
}