package peergos.server.mutable;

import peergos.shared.cbor.*;
import peergos.shared.crypto.asymmetric.*;
import peergos.shared.merklebtree.*;
import peergos.shared.mutable.*;
import peergos.shared.storage.ContentAddressedStorage;

import java.util.concurrent.*;

public class PinningMutablePointers implements MutablePointers {
    private static final boolean LOGGING = true;
    private final MutablePointers target;
    private final ContentAddressedStorage storage;

    public PinningMutablePointers(MutablePointers target, ContentAddressedStorage storage) {
        this.target = target;
        this.storage = storage;
    }

    @Override
    public CompletableFuture<Boolean> setPointer(PublicSigningKey owner, PublicSigningKey signer, byte[] sharingKeySignedBtreeRootHashes) {
        // first pin new root
        byte[] message = signer.unsignMessage(sharingKeySignedBtreeRootHashes);
        HashCasPair cas = HashCasPair.fromCbor(CborObject.fromByteArray(message));
        long t1 = System.currentTimeMillis();
        return (cas.original.isPresent() ? storage.pinUpdate(cas.original.get(), cas.updated.get()) :
                storage.recursivePin(cas.updated.get())).thenCompose(pins -> {
            if (!pins.contains(cas.updated.get())) {
                CompletableFuture<Boolean> err = new CompletableFuture<>();
                err.completeExceptionally(new IllegalStateException("Couldn't pin new hash: " + cas.updated.get()));
                return err;
            }
            long t2 = System.currentTimeMillis();
            if (LOGGING)
                System.out.println("Pinning "+cas.updated+" took: " + (t2 -t1) + " mS");
            return target.setPointer(owner, signer, sharingKeySignedBtreeRootHashes)
                    .thenCompose(b -> {
                        if (!b) {
                            CompletableFuture<Boolean> err = new CompletableFuture<>();
                            err.completeExceptionally(new IllegalStateException("Couldn't update mutable pointer, cas failed: " + cas));
                            return err;
                        }
                        long t3 = System.currentTimeMillis();
                        // unpin old root
                        return !cas.original.isPresent() ?
                                CompletableFuture.completedFuture(true) :
                                storage.recursiveUnpin(cas.original.get())
                                        .thenApply(unpins -> {
                                            long t4 = System.currentTimeMillis();
                                            if (LOGGING)
                                                System.out.println("Unpinning "+cas.original+" took: " + (t4 -t3) + " mS");
                                            return unpins.contains(cas.original.get());
                                        });
                    });
        });
    }

    @Override
    public CompletableFuture<MaybeMultihash> getPointer(PublicSigningKey encodedSharingKey) {
        return target.getPointer(encodedSharingKey);
    }
}

@@ -95,24 +95,147 @@
 ymmetric.*;%0A
+import peergos.shared.io.ipfs.cid.*;%0Aimport peergos.shared.io.ipfs.multiaddr.*;%0Aimport peergos.shared.io.ipfs.multihash.*;%0A
 import peerg
@@ -255,24 +255,24 @@
 klebtree.*;%0A
-
 import peerg
@@ -344,24 +344,44 @@
 edStorage;%0A%0A
+import java.util.*;%0A
 import java.
@@ -398,16 +398,43 @@
 rrent.*;
+%0Aimport java.util.stream.*;
 %0A%0Apublic
@@ -1289,16 +1289,76 @@
 d.get())
+%0A                .thenApply(PinningMutablePointers::convert)
  :%0A     
@@ -3138,32 +3138,336 @@
      %7D);%0A    %7D%0A%0A
+    private static List%3CMultihash%3E convert(List%3CMultiAddress%3E addresses) %7B%0A        return addresses.stream()%0A                .filter(addr -%3E addr.toString().startsWith(%22/ipfs/%22))%0A                .map(addr -%3E Cid.decode(addr.toString().substring(6)))%0A                .collect(Collectors.toList());%0A    %7D%0A%0A
     @Override%0A  

Fix pinning mutable pointers use of pin update