// Path: localnet/src/main/java/dev/jokr/localnet/discovery/ClientJoinHandler.java
// public class ClientJoinHandler implements Runnable {
// 
//     private DatagramSocket socket;
//     private ServerDiscoveryCallback callback;
// 
//     public ClientJoinHandler(ServerDiscoveryCallback callback) {
//         this.callback = callback;
//     }
// 
//     @Override
//     public void run() {
//         try {
//             socket = new DatagramSocket(0);
//             socket.setBroadcast(true);
// 
//             // data is not important for braodcast discovery request
//             byte[]  sendData = "DISCOVER_ME".getBytes();
//             InetAddress broadcastAddr = InetAddress.getByName("255.255.255.255");
// 
//             int basePort = NetworkUtil.BASE_PORT;
//             for (int i=0; i<5; i++) {
//                 DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, broadcastAddr, basePort-i);
//                 socket.send(sendPacket);
//                 Log.d("USER", "Packet sent to 255.255.255.255:" + (basePort-i));
//             }
//             byte[] buffer = new byte[15000];
//             DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);
//             socket.setSoTimeout(2500);
//             socket.receive(receivePacket);
//             Log.d("USER", "Received packet from: " + receivePacket.getAddress().getHostAddress());
// 
//             byte[] bytes = receivePacket.getData();
//             DiscoveryReply reply = (DiscoveryReply) SerializationUtil.deserialize(bytes);
//             Log.d("USER", "Reply: " + reply.getIp() + ":" + reply.getPort());
//             discoveryReply(reply);
//         } catch (SocketTimeoutException e) {
//             discoveryTimeout();
//         } catch (SocketException e) {
//             e.printStackTrace();
//         } catch (UnknownHostException e) {
//             e.printStackTrace();
//         } catch (IOException e) {
//             e.printStackTrace();
//         }
//     }
// 
// 
//     private void discoveryReply(final DiscoveryReply reply) {
//         new Handler(Looper.getMainLooper()).post(new Runnable() {
//             @Override
//             public void run() {
//                 callback.serverDiscovered(reply);
//             }
//         });
//     }
// 
//     private void discoveryTimeout() {
//         new Handler(Looper.getMainLooper()).post(new Runnable() {
//             @Override
//             public void run() {
//                 callback.serverDiscoveryTimeout();
//             }
//         });
//     }
// 
//     public interface ServerDiscoveryCallback {
//         public void serverDiscovered(DiscoveryReply reply);
//         public void serverDiscoveryTimeout();
//     }
// }
// 
// Path: localnet/src/main/java/dev/jokr/localnet/discovery/models/DiscoveryReply.java
// public class DiscoveryReply implements Serializable {
// 
//     private String ip;
//     private int port;
// 
//     public DiscoveryReply(String ip, int port) {
//         this.ip = ip;
//         this.port = port;
//     }
// 
//     public String getIp() {
//         return ip;
//     }
// 
//     public int getPort() {
//         return port;
//     }
// }
// 
// Path: localnet/src/main/java/dev/jokr/localnet/models/Payload.java
// public class Payload<T> implements Serializable {
// 
//     private T payload;
// 
//     public Payload(T payload) {
//         this.payload = payload;
//     }
// 
//     public T getPayload() {
//         return payload;
//     }
// 
// 
// }
// 
// Path: localnet/src/main/java/dev/jokr/localnet/models/SessionMessage.java
// public class SessionMessage implements Serializable {
// 
//     public static final int NONE = 0;
//     public static final int START = 1;
//     public static final int END = 2;
// 
//     private Payload<?> payload;
//     private int signal;
// 
// 
//     public SessionMessage(Payload<?> payload) {
//         this.payload = payload;
//         this.signal = NONE;
//     }
// 
//     public SessionMessage(Payload<?> payload, int signal) {
//         this.payload = payload;
//         this.signal = signal;
//     }
// 
//     public int getSignal() {
//         return signal;
//     }
// 
//     public Payload<?> getPayload() {
//         return payload;
//     }
// }


import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import dev.jokr.localnet.discovery.ClientJoinHandler;
import dev.jokr.localnet.discovery.models.DiscoveryReply;
import dev.jokr.localnet.models.Payload;
import dev.jokr.localnet.models.SessionMessage;
    public void sendSessionMessage(Payload<?> payload) {
        Intent i = new Intent(context, ClientService.class);
        i.putExtra(ClientService.ACTION, ClientService.SESSION_MESSAGE);
        i.putExtra(ClientService.PAYLOAD, payload);
        context.startService(i);
    }

    /*
     * Set interface implementation for receiving session messages from server
     */
    public void setReceiver(MessageReceiver receiver) {
        this.messageReceiver = receiver;
    }

    /*
     * Set interface implementation for receiving discovery phase events
     */
    public void setDiscoveryReceiver(DiscoveryStatusReceiver discoveryReceiver) {
        this.discoveryReceiver = discoveryReceiver;
    }

    /*
     * Stops the service
     */
    public void shutdown() {
        Intent i = new Intent(context, ClientService.class);
        context.stopService(i);
    }

    @Override
// Path: localnet/src/main/java/dev/jokr/localnet/discovery/ClientJoinHandler.java
// public class ClientJoinHandler implements Runnable {
// 
//     private DatagramSocket socket;
//     private ServerDiscoveryCallback callback;
// 
//     public ClientJoinHandler(ServerDiscoveryCallback callback) {
//         this.callback = callback;
//     }
// 
//     @Override
//     public void run() {
//         try {
//             socket = new DatagramSocket(0);
//             socket.setBroadcast(true);
// 
//             // data is not important for braodcast discovery request
//             byte[]  sendData = "DISCOVER_ME".getBytes();
//             InetAddress broadcastAddr = InetAddress.getByName("255.255.255.255");
// 
//             int basePort = NetworkUtil.BASE_PORT;
//             for (int i=0; i<5; i++) {
//                 DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, broadcastAddr, basePort-i);
//                 socket.send(sendPacket);
//                 Log.d("USER", "Packet sent to 255.255.255.255:" + (basePort-i));
//             }
//             byte[] buffer = new byte[15000];
//             DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);
//             socket.setSoTimeout(2500);
//             socket.receive(receivePacket);
//             Log.d("USER", "Received packet from: " + receivePacket.getAddress().getHostAddress());
// 
//             byte[] bytes = receivePacket.getData();
//             DiscoveryReply reply = (DiscoveryReply) SerializationUtil.deserialize(bytes);
//             Log.d("USER", "Reply: " + reply.getIp() + ":" + reply.getPort());
//             discoveryReply(reply);
//         } catch (SocketTimeoutException e) {
//             discoveryTimeout();
//         } catch (SocketException e) {
//             e.printStackTrace();
//         } catch (UnknownHostException e) {
//             e.printStackTrace();
//         } catch (IOException e) {
//             e.printStackTrace();
//         }
//     }
// 
// 
//     private void discoveryReply(final DiscoveryReply reply) {
//         new Handler(Looper.getMainLooper()).post(new Runnable() {
//             @Override
//             public void run() {
//                 callback.serverDiscovered(reply);
//             }
//         });
//     }
// 
//     private void discoveryTimeout() {
//         new Handler(Looper.getMainLooper()).post(new Runnable() {
//             @Override
//             public void run() {
//                 callback.serverDiscoveryTimeout();
//             }
//         });
//     }
// 
//     public interface ServerDiscoveryCallback {
//         public void serverDiscovered(DiscoveryReply reply);
//         public void serverDiscoveryTimeout();
//     }
// }
// 
// Path: localnet/src/main/java/dev/jokr/localnet/discovery/models/DiscoveryReply.java
// public class DiscoveryReply implements Serializable {
// 
//     private String ip;
//     private int port;
// 
//     public DiscoveryReply(String ip, int port) {
//         this.ip = ip;
//         this.port = port;
//     }
// 
//     public String getIp() {
//         return ip;
//     }
// 
//     public int getPort() {
//         return port;
//     }
// }
// 
// Path: localnet/src/main/java/dev/jokr/localnet/models/Payload.java
// public class Payload<T> implements Serializable {
// 
//     private T payload;
// 
//     public Payload(T payload) {
//         this.payload = payload;
//     }
// 
//     public T getPayload() {
//         return payload;
//     }
// 
// 
// }
// 
// Path: localnet/src/main/java/dev/jokr/localnet/models/SessionMessage.java
// public class SessionMessage implements Serializable {
// 
//     public static final int NONE = 0;
//     public static final int START = 1;
//     public static final int END = 2;
// 
//     private Payload<?> payload;
//     private int signal;
// 
// 
//     public SessionMessage(Payload<?> payload) {
//         this.payload = payload;
//         this.signal = NONE;
//     }
// 
//     public SessionMessage(Payload<?> payload, int signal) {
//         this.payload = payload;
//         this.signal = signal;
//     }
// 
//     public int getSignal() {
//         return signal;
//     }
// 
//     public Payload<?> getPayload() {
//         return payload;
//     }
// }


// Path: localnet/src/main/java/dev/jokr/localnet/LocalClient.java
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import dev.jokr.localnet.discovery.ClientJoinHandler;
import dev.jokr.localnet.discovery.models.DiscoveryReply;
import dev.jokr.localnet.models.Payload;
import dev.jokr.localnet.models.SessionMessage;

    public void sendSessionMessage(Payload<?> payload) {
        Intent i = new Intent(context, ClientService.class);
        i.putExtra(ClientService.ACTION, ClientService.SESSION_MESSAGE);
        i.putExtra(ClientService.PAYLOAD, payload);
        context.startService(i);
    }

    /*
     * Set interface implementation for receiving session messages from server
     */
    public void setReceiver(MessageReceiver receiver) {
        this.messageReceiver = receiver;
    }

    /*
     * Set interface implementation for receiving discovery phase events
     */
    public void setDiscoveryReceiver(DiscoveryStatusReceiver discoveryReceiver) {
        this.discoveryReceiver = discoveryReceiver;
    }

    /*
     * Stops the service
     */
    public void shutdown() {
        Intent i = new Intent(context, ClientService.class);
        context.stopService(i);
    }

    @Override
    public void serverDiscovered(DiscoveryReply reply) {