// Path: src/socialkademlia/routing/JSocialKademliaRoutingTable.java
// public class JSocialKademliaRoutingTable extends JKademliaRoutingTable implements SocialKademliaRoutingTable
// {
// 
//     /* Connections of the actor of this node in the DOSN */
//     private final HashMap<String, Connection> connections;
// 
//     
//     {
//         connections = new HashMap<>();
//     }
// 
//     public JSocialKademliaRoutingTable(Node localNode, KadConfiguration config)
//     {
//         super(localNode, config);
//     }
// 
//     @Override
//     public synchronized void insertConnection(String actorId, Node node)
//     {
//         if (this.containsConnection(actorId))
//         {
//             Connection c = this.connections.get(actorId);
//             c.setNode(node);
//             c.setSeenNow();
//         }
//         else
//         {
//             this.connections.put(actorId, new Connection(actorId, node));
//         }
//     }
// 
//     @Override
//     public synchronized boolean containsConnection(String actorId)
//     {
//         return this.connections.containsKey(actorId);
//     }
// 
//     @Override
//     public synchronized boolean removeConnection(String actorId)
//     {
//         if (this.containsConnection(actorId))
//         {
//             this.connections.remove(actorId);
//             return true;
//         }
//         return false;
//     }
// 
//     @Override
//     public synchronized List<Connection> getConnections()
//     {
//         return this.connections.isEmpty() ? new ArrayList<>() : new ArrayList<>(this.connections.values());
//     }
// 
//     @Override
//     public synchronized Node getConnectionNode(String actorId)
//     {
//         if (this.containsConnection(actorId))
//         {
//             return this.connections.get(actorId).getNode();
//         }
//         else
//         {
//             throw new NoSuchElementException("This connection does not exist.");
//         }
//     }
// }
// 
// Path: src/socialkademlia/routing/SocialKademliaRoutingTable.java
// public interface SocialKademliaRoutingTable extends KademliaRoutingTable
// {
// 
//     /**
//      * Adds a Connection to the routing table
//      *
//      * @param actorId The actor Id of this connection
//      * @param node    The node related to this connection
//      */
//     public void insertConnection(String actorId, Node node);
// 
//     /**
//      * Checks if this routing table contain a connection.
//      *
//      * @param actorId The id of the actor
//      *
//      * @return boolean
//      */
//     public boolean containsConnection(String actorId);
// 
//     /**
//      * Remove a connection from this routing table.
//      *
//      * @param actorId
//      *
//      * @return Boolean whether the removal was successful.
//      */
//     public boolean removeConnection(String actorId);
// 
//     /**
//      * @param actorId
//      *
//      * @return The node of a given connection
//      */
//     public Node getConnectionNode(String actorId);
// 
//     /**
//      * @return An Iterable structure with all connections in this routing table
//      */
//     public List<Connection> getConnections();
// }


import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import kademlia.routing.JKademliaRoutingTable;
import java.lang.reflect.Type;
import java.util.List;
import kademlia.KadConfiguration;
import kademlia.routing.Contact;
import kademlia.util.serializer.KadSerializer;
import socialkademlia.routing.JSocialKademliaRoutingTable;
import socialkademlia.routing.SocialKademliaRoutingTable;
package socialkademlia.util.serializer;


/**
 * A KadSerializer that serializes routing tables to JSON format
 The generic serializer is not working for routing tables

 Why a JKademliaRoutingTable specific serializer?
 The routing table structure:
 - JKademliaRoutingTable
 -- Buckets[]
 --- Map<NodeId, Node>
 * ---- NodeId:KeyBytes
 * ---- Node: NodeId, InetAddress, Port
 *
 * The above structure seems to be causing some problem for Gson,
 * especially at the Map part.
 *
 * Solution
 - Make the Buckets[] transient
 - Simply store all Nodes in the serialized object
 - When reloading, re-add all nodes to the JKademliaRoutingTable
 *
 * @author Joshua Kissoon
 *
 * @since 20140310
 */
public class JsonSocialKadRoutingTableSerializer implements KadSerializer<SocialKademliaRoutingTable>
{

    private final Gson gson;

    Type contactCollectionType = new TypeToken<List<Contact>>()
    {
    }.getType();

    private final KadConfiguration config;
    
    
    {
        gson = new Gson();
    }

    /**
     * Initialize the class
     *
     * @param config
     */
    public JsonSocialKadRoutingTableSerializer(KadConfiguration config)
    {
        this.config = config;
    }

    @Override
    public void write(SocialKademliaRoutingTable data, DataOutputStream out) throws IOException
    {
        try (JsonWriter writer = new JsonWriter(new OutputStreamWriter(out)))
        {
            writer.beginArray();

            /* Write the basic JKademliaRoutingTable */
// Path: src/socialkademlia/routing/JSocialKademliaRoutingTable.java
// public class JSocialKademliaRoutingTable extends JKademliaRoutingTable implements SocialKademliaRoutingTable
// {
// 
//     /* Connections of the actor of this node in the DOSN */
//     private final HashMap<String, Connection> connections;
// 
//     
//     {
//         connections = new HashMap<>();
//     }
// 
//     public JSocialKademliaRoutingTable(Node localNode, KadConfiguration config)
//     {
//         super(localNode, config);
//     }
// 
//     @Override
//     public synchronized void insertConnection(String actorId, Node node)
//     {
//         if (this.containsConnection(actorId))
//         {
//             Connection c = this.connections.get(actorId);
//             c.setNode(node);
//             c.setSeenNow();
//         }
//         else
//         {
//             this.connections.put(actorId, new Connection(actorId, node));
//         }
//     }
// 
//     @Override
//     public synchronized boolean containsConnection(String actorId)
//     {
//         return this.connections.containsKey(actorId);
//     }
// 
//     @Override
//     public synchronized boolean removeConnection(String actorId)
//     {
//         if (this.containsConnection(actorId))
//         {
//             this.connections.remove(actorId);
//             return true;
//         }
//         return false;
//     }
// 
//     @Override
//     public synchronized List<Connection> getConnections()
//     {
//         return this.connections.isEmpty() ? new ArrayList<>() : new ArrayList<>(this.connections.values());
//     }
// 
//     @Override
//     public synchronized Node getConnectionNode(String actorId)
//     {
//         if (this.containsConnection(actorId))
//         {
//             return this.connections.get(actorId).getNode();
//         }
//         else
//         {
//             throw new NoSuchElementException("This connection does not exist.");
//         }
//     }
// }
// 
// Path: src/socialkademlia/routing/SocialKademliaRoutingTable.java
// public interface SocialKademliaRoutingTable extends KademliaRoutingTable
// {
// 
//     /**
//      * Adds a Connection to the routing table
//      *
//      * @param actorId The actor Id of this connection
//      * @param node    The node related to this connection
//      */
//     public void insertConnection(String actorId, Node node);
// 
//     /**
//      * Checks if this routing table contain a connection.
//      *
//      * @param actorId The id of the actor
//      *
//      * @return boolean
//      */
//     public boolean containsConnection(String actorId);
// 
//     /**
//      * Remove a connection from this routing table.
//      *
//      * @param actorId
//      *
//      * @return Boolean whether the removal was successful.
//      */
//     public boolean removeConnection(String actorId);
// 
//     /**
//      * @param actorId
//      *
//      * @return The node of a given connection
//      */
//     public Node getConnectionNode(String actorId);
// 
//     /**
//      * @return An Iterable structure with all connections in this routing table
//      */
//     public List<Connection> getConnections();
// }


// Path: src/socialkademlia/util/serializer/JsonSocialKadRoutingTableSerializer.java
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import kademlia.routing.JKademliaRoutingTable;
import java.lang.reflect.Type;
import java.util.List;
import kademlia.KadConfiguration;
import kademlia.routing.Contact;
import kademlia.util.serializer.KadSerializer;
import socialkademlia.routing.JSocialKademliaRoutingTable;
import socialkademlia.routing.SocialKademliaRoutingTable;

package socialkademlia.util.serializer;


/**
 * A KadSerializer that serializes routing tables to JSON format
 The generic serializer is not working for routing tables

 Why a JKademliaRoutingTable specific serializer?
 The routing table structure:
 - JKademliaRoutingTable
 -- Buckets[]
 --- Map<NodeId, Node>
 * ---- NodeId:KeyBytes
 * ---- Node: NodeId, InetAddress, Port
 *
 * The above structure seems to be causing some problem for Gson,
 * especially at the Map part.
 *
 * Solution
 - Make the Buckets[] transient
 - Simply store all Nodes in the serialized object
 - When reloading, re-add all nodes to the JKademliaRoutingTable
 *
 * @author Joshua Kissoon
 *
 * @since 20140310
 */
public class JsonSocialKadRoutingTableSerializer implements KadSerializer<SocialKademliaRoutingTable>
{

    private final Gson gson;

    Type contactCollectionType = new TypeToken<List<Contact>>()
    {
    }.getType();

    private final KadConfiguration config;
    
    
    {
        gson = new Gson();
    }

    /**
     * Initialize the class
     *
     * @param config
     */
    public JsonSocialKadRoutingTableSerializer(KadConfiguration config)
    {
        this.config = config;
    }

    @Override
    public void write(SocialKademliaRoutingTable data, DataOutputStream out) throws IOException
    {
        try (JsonWriter writer = new JsonWriter(new OutputStreamWriter(out)))
        {
            writer.beginArray();

            /* Write the basic JKademliaRoutingTable */
            gson.toJson(data, JSocialKademliaRoutingTable.class, writer);