using System;
using System.Collections.Generic;
using System.IO;
namespace OpenNest.IO
{
///
/// An in-memory copy of a whole nest for undo: the .nest archive a save would
/// write, except that empty plates are kept, best fits are left out (they are a cache)
/// and the nest's modified date is not stamped.
///
public sealed class NestSnapshot
{
private readonly byte[] bytes;
private NestSnapshot(byte[] bytes) => this.bytes = bytes;
public long SizeInBytes => bytes.Length;
/// The archive, for tests and diagnostics; never written over a user's file.
public ReadOnlySpan Bytes => bytes;
public static NestSnapshot Capture(Nest nest)
{
ArgumentNullException.ThrowIfNull(nest);
using var stream = new MemoryStream();
new NestWriter(nest) { PreserveDateLastModified = true, KeepEmptyPlates = true }.Write(stream);
return new NestSnapshot(stream.ToArray());
}
///
/// Reads the copy back as a new nest. Each drawing of whose saved
/// content equals a drawing in the copy is used in its place, so caches keyed by the
/// drawing (best fits, fill results), its color and its id survive; a drawing whose
/// content changed comes from the copy. Reused drawings' nested counts then follow the
/// returned nest, which replaces .
///
public Nest Restore(Nest live = null)
{
var reusable = live == null ? null : ReusableDrawings(live);
try
{
var nest = new NestReader(new MemoryStream(bytes, writable: false)) { ReusableDrawings = reusable }.Read();
nest.UpdateDrawingQuantities();
return nest;
}
catch when (live != null)
{
// Reading adds parts to reused drawings; give the live nest its counts back.
live.UpdateDrawingQuantities();
throw;
}
}
// Fingerprints include the name, and a nest's drawings have distinct names, so each
// fingerprint names one drawing.
private static Dictionary ReusableDrawings(Nest live)
{
var fingerprints = NestWriter.GetDrawingFingerprints(live);
var result = new Dictionary(StringComparer.Ordinal);
var i = 0;
// Same order as the fingerprints: both follow the collection's enumeration.
foreach (var drawing in live.Drawings)
result.TryAdd(fingerprints[i++], drawing);
return result;
}
}
}