/**
   * Appends the given deltas to the deltas already stored. Updates the latest snapshot and latest
   * version as well. This method will make a copy of the snapshot.
   *
   * @param updatedSnapshot the snapshot after deltas have been applied
   * @param newDeltas the deltas that have been applied since the last call to appendDeltas.
   */
  public void appendDeltas(ReadableWaveletData updatedSnapshot, DeltaSequence newDeltas) {
    HashedVersion newEndVersion = newDeltas.getEndVersion();
    Preconditions.checkArgument(
        !newDeltas.isEmpty(), "There were no new deltas passed to appendDeltas");
    Preconditions.checkArgument(
        updatedSnapshot.getVersion() == newEndVersion.getVersion(),
        String.format(
            "Version of snapshot %s doesn't match the HashedVersion %s",
            updatedSnapshot.getVersion(), newEndVersion));
    Preconditions.checkArgument(
        areContiguousToCurrentVersion(newDeltas),
        String.format(
            "Deltas are not contiguous to the current version(%s) %s",
            getVersionAfterDeltas(), deltas));
    WaveletName updatedWaveletName = WaveletDataUtil.waveletNameOf(updatedSnapshot);
    Preconditions.checkArgument(
        updatedWaveletName.equals(waveletName),
        String.format(
            "Updated wavelet doesn't have the same name as with which this class has been "
                + "instantiated. %s != %s",
            updatedWaveletName, waveletName));

    // TODO(ljvderijk): This should actually be applying the deltas, however
    // they do not contain a timestamp at this time.
    snapshotAfterDeltas = WaveletDataUtil.copyWavelet(updatedSnapshot);
    deltas = DeltaSequence.join(deltas, newDeltas);
  }
  /**
   * Constructs a {@link WaveletAndDeltas} from wavelet data and a tail of the sequence of
   * transformed deltas leading to that snapshot. Takes a copy of the WaveletData so that operations
   * can happily applied to it.
   *
   * <p>The resulting version of the last delta must match the snapshot's version.
   *
   * @param snapshot the state of the wavelet after the deltas have been applied.
   * @param deltas the deltas in the order they have been applied to the wavelet.
   * @throws OperationException if the operations can not be rolled back to create a snapshot before
   *     the deltas have been applied.
   */
  public static WaveletAndDeltas create(ReadableWaveletData snapshot, DeltaSequence deltas)
      throws OperationException {
    HashedVersion endVersion =
        deltas.isEmpty() ? snapshot.getHashedVersion() : deltas.getEndVersion();
    Preconditions.checkArgument(
        snapshot.getVersion() == endVersion.getVersion(),
        String.format(
            "Version of snapshot %s doesn't match the end version %s",
            snapshot.getVersion(), endVersion));

    ObservableWaveletData preDeltaWavelet = WaveletDataUtil.copyWavelet(snapshot);
    rollback(preDeltaWavelet, deltas);
    ObservableWaveletData postDeltaWavelet = WaveletDataUtil.copyWavelet(snapshot);
    return new WaveletAndDeltas(preDeltaWavelet, postDeltaWavelet, deltas);
  }