package peergos.shared.merklebtree;

import peergos.shared.cbor.*;
import peergos.shared.ipfs.api.*;
import peergos.shared.util.*;

import java.io.*;
import java.util.*;

public class MerkleNode implements Cborable {
    public final byte[] data;
    public final List<Link> links;

    public MerkleNode(byte[] data, List<Link> links) {
        this.data = data;
        this.links = links;
        Collections.sort(this.links);
    }

    public MerkleNode(byte[] data) {
        this(data, Collections.emptyList());
    }

    public static class Link implements Comparable<Link> {
        public final String label;
        public final Multihash target;

        public Link(String label, Multihash target) {
            this.label = label;
            this.target = target;
        }

        @Override
        public int compareTo(Link link) {
            return label.compareTo(link.label);
        }
    }

    public MerkleNode addLink(String label, Multihash linkTarget) {
        List<Link> tmp = new ArrayList<>(links);
        tmp.add(new Link(label, linkTarget));
        return new MerkleNode(data, tmp);
    }

    public MerkleNode setData(byte[] newData) {
        return new MerkleNode(newData, links);
    }

    public CborObject.CborMap toCbor() {
        SortedMap<CborObject, CborObject> cbor = new TreeMap<>();
        cbor.put(new CborObject.CborString("Data"), new CborObject.CborByteArray(data));
        for (Link link: links) {
            cbor.put(new CborObject.CborString(link.label), new CborObject.CborByteArray(link.target.toBytes()));
        }
        return new CborObject.CborMap(cbor);
    }

    public static MerkleNode fromCbor(CborObject obj) {
        try {
            CborObject.CborMap map = (CborObject.CborMap) obj;
            CborObject.CborString dataLabel = new CborObject.CborString("Data");
            CborObject.CborByteArray data = (CborObject.CborByteArray) map.values.get(dataLabel);
            List<Link> links = new ArrayList<>(map.values.size() - 1);
            for (Map.Entry<CborObject, CborObject> entry : map.values.entrySet()) {
                if (entry.getKey().equals(dataLabel))
                    continue;
                String label = ((CborObject.CborString) entry.getKey()).value;
                byte[] value = ((CborObject.CborByteArray) entry.getValue()).value;
                links.add(new Link(label, Multihash.deserialize(new DataSource(value))));
            }
            return new MerkleNode(data.value, links);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     *
     * @param in a CBOR encoding of a merkle node
     * @return
     * @throws IOException for an invalid encoding
     */
    public static MerkleNode deserialize(byte[] in) throws IOException {
        CborDecoder decoder = new CborDecoder(new ByteArrayInputStream(in));
        CborObject cbor = CborObject.deserialize(decoder);
        return fromCbor(cbor);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        MerkleNode that = (MerkleNode) o;

        if (!Arrays.equals(data, that.data)) return false;
        return links != null ? links.equals(that.links) : that.links == null;

    }

    @Override
    public int hashCode() {
        int result = Arrays.hashCode(data);
        result = 31 * result + (links != null ? links.hashCode() : 0);
        return result;
    }
}
@@ -1531,25 +1531,26 @@
 ect.Cbor
-ByteArray
+MerkleLink
 (link.ta
@@ -1557,18 +1557,8 @@
 rget
-.toBytes()
 ));%0A
@@ -1679,26 +1679,8 @@
 ) %7B%0A
-        try %7B%0A    
     
@@ -1734,36 +1734,32 @@
 p) obj;%0A        
-   
- 
 CborObject.CborS
@@ -1811,20 +1811,16 @@
 Data%22);%0A
-    
         
@@ -1909,28 +1909,24 @@
 l);%0A        
-  
-  
 List%3CLink%3E l
@@ -1972,20 +1972,16 @@
 ) - 1);%0A
-    
         
@@ -2060,28 +2060,24 @@
             
- 
-   
 if (entry.ge
@@ -2102,20 +2102,16 @@
 Label))%0A
-    
         
@@ -2140,20 +2140,16 @@
         
-    
 String l
@@ -2219,18 +2219,17 @@
     
-    byte%5B%5D
+Multihash
  val
@@ -2250,25 +2250,26 @@
 ect.Cbor
-ByteArray
+MerkleLink
 ) entry.
@@ -2276,35 +2276,32 @@
 getValue()).
-value;%0A    
+target;%0A
             
@@ -2330,54 +2330,15 @@
 el, 
-Multihash.deserialize(new DataSource(
 value))
-)
-)
 ;%0A  
@@ -2339,34 +2339,26 @@
 ));%0A        
-  
-  %7D%0A    
+%7D%0A
         retu
@@ -2399,95 +2399,8 @@
 s);%0A
-        %7D catch (IOException e) %7B%0A            throw new RuntimeException(e);%0A        %7D%0A
     

make merkle node use cbor merkle links