package org.ingrahamrobotics.robottables;

import java.io.IOException;
import java.net.InetAddress;
import org.ingrahamrobotics.robottables.api.RobotTablesClient;
import org.ingrahamrobotics.robottables.network.IO;
import org.ingrahamrobotics.robottables.network.Queue;
import org.ingrahamrobotics.robottables.network.Queue.QueueEvents;

public class RobotTables implements QueueEvents {

    // Make IO a package-level variable (instead of a local variable) so that it is accessible from the outside
    IO io;
    private Dispatch dispatch;
    private ProtocolHandler protocolHandler;
    private TablesInterfaceHandler tablesInterfaceHandler;

    public void run(InetAddress targetAddress) throws IOException {
        // Message queue between listener and dispatch
        Queue queue = new Queue(this);

        io = new IO(targetAddress);

        // Listen for and queue incoming messages
        io.listen(queue);

        dispatch = new Dispatch(queue);

        protocolHandler = new ProtocolHandler(io);

        // Dispatch all messages from the queue to the protocol handler
        dispatch.setAllHandlers(protocolHandler);

        tablesInterfaceHandler = new TablesInterfaceHandler(protocolHandler);

        // Set the internal handler on the protocol handler
        protocolHandler.setInternalHandler(tablesInterfaceHandler);

        (new Thread(dispatch)).start();
    }

    public void queueError(int size, boolean draining, int targetSize) {
        if (!draining) {
            System.err.println("Queue Warning: Large message queue size: " + size);
        } else {
            System.err.println("Queue Error: Drained to size: " + targetSize);
        }
        if (dispatch.currentMessage() == null) {
            System.err.println("\tNo dispatch handler running");
        } else {
            long now = System.currentTimeMillis();
            System.err.println("\tDispatch time: " + (now - dispatch.dispatchTime()) + " ms ago");
            System.err.println("\tDispatch message:\n" + dispatch.currentMessage().displayStr());
        }
    }

    public RobotTablesClient getClientInterface() {
        return tablesInterfaceHandler;
    }

    public void close() {
        io.close();
    }
}

@@ -502,44 +502,27 @@
     
-IO io;%0A    private Dispatch dispatch
+private final IO io
 ;%0A  
@@ -531,16 +531,22 @@
 private 
+final 
 Protocol
@@ -582,16 +582,22 @@
 private 
+final 
 TablesIn
@@ -634,16 +634,47 @@
 Handler;
+%0A    private Dispatch dispatch;
 %0A%0A    pu
@@ -682,16 +682,19 @@
 lic 
-void run
+RobotTables
 (Ine
@@ -738,16 +738,340 @@
 ption %7B%0A
+        io = new IO(targetAddress);%0A        protocolHandler = new ProtocolHandler(io);%0A        tablesInterfaceHandler = new TablesInterfaceHandler(protocolHandler);%0A        // Set the internal handler on the protocol handler%0A        protocolHandler.setInternalHandler(tablesInterfaceHandler);%0A    %7D%0A%0A    public void run() %7B%0A
         
@@ -1117,16 +1117,17 @@
 ispatch%0A
+%0A
         
@@ -1161,46 +1161,8 @@
 s);%0A
-%0A        io = new IO(targetAddress);%0A%0A
     
@@ -1279,60 +1279,8 @@
 );%0A%0A
-        protocolHandler = new ProtocolHandler(io);%0A%0A
     
@@ -1402,216 +1402,8 @@
 );%0A%0A
-        tablesInterfaceHandler = new TablesInterfaceHandler(protocolHandler);%0A%0A        // Set the internal handler on the protocol handler%0A        protocolHandler.setInternalHandler(tablesInterfaceHandler);%0A%0A
     

Initialize IO, TablesInterfaceHandler and ProtocolHandler in the constructor of RobotTables rather than the run() method. This allows for a small amount of program initialization to run before starting the proccessing of recieved messages.