// Path: src/main/java/nl/pvdberg/pnet/event/PNetListener.java
// public interface PNetListener
// {
//     /**
//      * Called when a connection is made
//      * @param c Connected Client
//      */
//     void onConnect(final Client c);
// 
//     /**
//      * Called when a connection is lost
//      * @param c Lost Client
//      */
//     void onDisconnect(final Client c);
// 
//     /**
//      * Called when a new Packet has been received. May throw a caught and silenced IOException
//      * @param p New Packet
//      * @param c Sender
//      * @throws IOException when anything goes wrong during data extraction. This exception is caught because invalid Packets should not crash the Client or Server
//      */
//     void onReceive(final Packet p, final Client c) throws IOException;
// }
// 
// Path: src/main/java/nl/pvdberg/pnet/factory/SocketFactory.java
// public interface SocketFactory
// {
//     Socket getSocket(final String host, final int port) throws Exception;
// }
// 
// Path: src/main/java/nl/pvdberg/pnet/packet/Packet.java
// public class Packet
// {
//     private final PacketType packetType;
//     private final short packetID;
//     private final int dataLength;
//     private final byte[] data;
// 
//     public enum PacketType
//     {
//         Request,
//         Reply;
// 
//         public static final PacketType[] fastValues = values();
//     }
// 
//     /**
//      * Creates a new immutable Packet
//      * @param packetType Packet Type
//      * @param packetID Packet ID
//      * @param data Packet Data
//      */
//     public Packet(final PacketType packetType, final short packetID, final byte[] data)
//     {
//         this.packetType = packetType;
//         this.packetID = packetID;
//         dataLength = data.length;
//         this.data = data;
//     }
// 
//     /**
//      * Returns Packet Type
//      * @return Packet Type
//      */
//     public PacketType getPacketType()
//     {
//         return packetType;
//     }
// 
//     /**
//      * Returns whether Packet is of type Request
//      * @return PacketType is Request
//      */
//     public boolean isRequest()
//     {
//         return packetType == PacketType.Request;
//     }
// 
//     /**
//      * Returns whether Packet is of type Reply
//      * @return PacketType is Reply
//      */
//     public boolean isReply()
//     {
//         return packetType == PacketType.Reply;
//     }
// 
//     /**
//      * Returns Packet ID
//      * @return Packet ID
//      */
//     public short getPacketID()
//     {
//         return packetID;
//     }
// 
//     /**
//      * Returns Data length
//      * @return Data length
//      */
//     public int getDataLength()
//     {
//         return dataLength;
//     }
// 
//     /**
//      * Returns Packet data
//      * @return Data
//      */
//     public byte[] getData()
//     {
//         return data;
//     }
// 
//     /**
//      * Writes Packet into DataOutputStream
//      * @param out DataOutputStream to write into
//      * @throws IOException when unable to write to stream
//      */
//     public void write(final DataOutputStream out) throws IOException
//     {
//         // Packet Type
//         out.writeByte(packetType.ordinal());
// 
//         // Packet ID
//         out.writeShort(packetID);
// 
//         // Data Length
//         out.writeInt(dataLength);
// 
//         // Data
//         out.write(data);
//     }
// 
//     /**
//      * Reads a Packet from raw input data
//      * @param in DataInputStream to fromStream from
//      * @return Packet created from input
//      * @throws IOException when unable to read from stream
//      */
//     public static Packet fromStream(final DataInputStream in) throws IOException
//     {
//         // Packet Type
//         final Packet.PacketType packetType = Packet.PacketType.fastValues[in.readByte()];
// 
//         // Packet ID
//         final short packetID = in.readShort();
// 
//         // Data Length
//         final int dataLength = in.readInt();
// 
//         // Data
//         final byte[] data = new byte[dataLength];
//         in.readFully(data);
// 
//         return new Packet(
//                 packetType,
//                 packetID,
//                 data
//         );
//     }
// 
//     @Override
//     public String toString()
//     {
//         return "Type: [" + packetType + "] ID: [" + packetID + "] Data: [" + dataLength + " bytes]";
//     }
// }
// 
// Path: src/main/java/nl/pvdberg/pnet/threading/ThreadManager.java
// public static Future launchThread(final Runnable runnable)
// {
//     return service.submit(runnable);
// }


import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import static nl.pvdberg.pnet.threading.ThreadManager.launchThread;
import nl.pvdberg.pnet.event.PNetListener;
import nl.pvdberg.pnet.factory.SocketFactory;
import nl.pvdberg.pnet.packet.Packet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
        }
    }

    @Override
    public synchronized void setSocket(final Socket socket) throws IOException
    {
        if (this.socket != null && !this.socket.isClosed()) throw new IllegalStateException("Client not closed");

        this.socket = socket;
        socket.setKeepAlive(false);
        dataInputStream = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
        dataOutputStream = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));

        logger.debug("Starting thread");
        launchThread(new Runnable()
        {
            @Override
            public void run()
            {
                listenerThreadImpl();
            }
        });

        if (clientListener != null) clientListener.onConnect(this);
    }

    private void listenerThreadImpl()
    {
        while (true)
        {
// Path: src/main/java/nl/pvdberg/pnet/event/PNetListener.java
// public interface PNetListener
// {
//     /**
//      * Called when a connection is made
//      * @param c Connected Client
//      */
//     void onConnect(final Client c);
// 
//     /**
//      * Called when a connection is lost
//      * @param c Lost Client
//      */
//     void onDisconnect(final Client c);
// 
//     /**
//      * Called when a new Packet has been received. May throw a caught and silenced IOException
//      * @param p New Packet
//      * @param c Sender
//      * @throws IOException when anything goes wrong during data extraction. This exception is caught because invalid Packets should not crash the Client or Server
//      */
//     void onReceive(final Packet p, final Client c) throws IOException;
// }
// 
// Path: src/main/java/nl/pvdberg/pnet/factory/SocketFactory.java
// public interface SocketFactory
// {
//     Socket getSocket(final String host, final int port) throws Exception;
// }
// 
// Path: src/main/java/nl/pvdberg/pnet/packet/Packet.java
// public class Packet
// {
//     private final PacketType packetType;
//     private final short packetID;
//     private final int dataLength;
//     private final byte[] data;
// 
//     public enum PacketType
//     {
//         Request,
//         Reply;
// 
//         public static final PacketType[] fastValues = values();
//     }
// 
//     /**
//      * Creates a new immutable Packet
//      * @param packetType Packet Type
//      * @param packetID Packet ID
//      * @param data Packet Data
//      */
//     public Packet(final PacketType packetType, final short packetID, final byte[] data)
//     {
//         this.packetType = packetType;
//         this.packetID = packetID;
//         dataLength = data.length;
//         this.data = data;
//     }
// 
//     /**
//      * Returns Packet Type
//      * @return Packet Type
//      */
//     public PacketType getPacketType()
//     {
//         return packetType;
//     }
// 
//     /**
//      * Returns whether Packet is of type Request
//      * @return PacketType is Request
//      */
//     public boolean isRequest()
//     {
//         return packetType == PacketType.Request;
//     }
// 
//     /**
//      * Returns whether Packet is of type Reply
//      * @return PacketType is Reply
//      */
//     public boolean isReply()
//     {
//         return packetType == PacketType.Reply;
//     }
// 
//     /**
//      * Returns Packet ID
//      * @return Packet ID
//      */
//     public short getPacketID()
//     {
//         return packetID;
//     }
// 
//     /**
//      * Returns Data length
//      * @return Data length
//      */
//     public int getDataLength()
//     {
//         return dataLength;
//     }
// 
//     /**
//      * Returns Packet data
//      * @return Data
//      */
//     public byte[] getData()
//     {
//         return data;
//     }
// 
//     /**
//      * Writes Packet into DataOutputStream
//      * @param out DataOutputStream to write into
//      * @throws IOException when unable to write to stream
//      */
//     public void write(final DataOutputStream out) throws IOException
//     {
//         // Packet Type
//         out.writeByte(packetType.ordinal());
// 
//         // Packet ID
//         out.writeShort(packetID);
// 
//         // Data Length
//         out.writeInt(dataLength);
// 
//         // Data
//         out.write(data);
//     }
// 
//     /**
//      * Reads a Packet from raw input data
//      * @param in DataInputStream to fromStream from
//      * @return Packet created from input
//      * @throws IOException when unable to read from stream
//      */
//     public static Packet fromStream(final DataInputStream in) throws IOException
//     {
//         // Packet Type
//         final Packet.PacketType packetType = Packet.PacketType.fastValues[in.readByte()];
// 
//         // Packet ID
//         final short packetID = in.readShort();
// 
//         // Data Length
//         final int dataLength = in.readInt();
// 
//         // Data
//         final byte[] data = new byte[dataLength];
//         in.readFully(data);
// 
//         return new Packet(
//                 packetType,
//                 packetID,
//                 data
//         );
//     }
// 
//     @Override
//     public String toString()
//     {
//         return "Type: [" + packetType + "] ID: [" + packetID + "] Data: [" + dataLength + " bytes]";
//     }
// }
// 
// Path: src/main/java/nl/pvdberg/pnet/threading/ThreadManager.java
// public static Future launchThread(final Runnable runnable)
// {
//     return service.submit(runnable);
// }


// Path: src/main/java/nl/pvdberg/pnet/client/ClientImpl.java
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import static nl.pvdberg.pnet.threading.ThreadManager.launchThread;
import nl.pvdberg.pnet.event.PNetListener;
import nl.pvdberg.pnet.factory.SocketFactory;
import nl.pvdberg.pnet.packet.Packet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

        }
    }

    @Override
    public synchronized void setSocket(final Socket socket) throws IOException
    {
        if (this.socket != null && !this.socket.isClosed()) throw new IllegalStateException("Client not closed");

        this.socket = socket;
        socket.setKeepAlive(false);
        dataInputStream = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
        dataOutputStream = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));

        logger.debug("Starting thread");
        launchThread(new Runnable()
        {
            @Override
            public void run()
            {
                listenerThreadImpl();
            }
        });

        if (clientListener != null) clientListener.onConnect(this);
    }

    private void listenerThreadImpl()
    {
        while (true)
        {
            final Packet packet;