// 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;
    }

    @Override
    public void serverDiscoveryTimeout() {
        if (discoveryReceiver != null)
            discoveryReceiver.onDiscoveryTimeout();
    }

    private void registerMessageBroadcastReceiver() {
        BroadcastReceiver receiver = new MessageBroadcastReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(SESSION_MESSAGE);
        LocalBroadcastManager.getInstance(context).registerReceiver(receiver, intentFilter);
    }

    private class MessageBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            SessionMessage message = (SessionMessage) intent.getExtras().getSerializable(SessionMessage.class.getName());
            if (message.getSignal() == SessionMessage.NONE) {
                if (messageReceiver != null) messageReceiver.onMessageReceived(message.getPayload());
            } else if (message.getSignal() == SessionMessage.START) {
                if (discoveryReceiver != null) discoveryReceiver.onSessionStart();
            }
        }
    }

    /*
     * Interface for receiving session messages from server
     */
// 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;

    }

    @Override
    public void serverDiscoveryTimeout() {
        if (discoveryReceiver != null)
            discoveryReceiver.onDiscoveryTimeout();
    }

    private void registerMessageBroadcastReceiver() {
        BroadcastReceiver receiver = new MessageBroadcastReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(SESSION_MESSAGE);
        LocalBroadcastManager.getInstance(context).registerReceiver(receiver, intentFilter);
    }

    private class MessageBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            SessionMessage message = (SessionMessage) intent.getExtras().getSerializable(SessionMessage.class.getName());
            if (message.getSignal() == SessionMessage.NONE) {
                if (messageReceiver != null) messageReceiver.onMessageReceived(message.getPayload());
            } else if (message.getSignal() == SessionMessage.START) {
                if (discoveryReceiver != null) discoveryReceiver.onSessionStart();
            }
        }
    }

    /*
     * Interface for receiving session messages from server
     */
    public interface MessageReceiver {