/
codebase/
codebase/area/
codebase/doc/
codebase/etc/
codebase/src/net/sourceforge/pain/data/trigger/
codebase/src/net/sourceforge/pain/logic/
codebase/src/net/sourceforge/pain/logic/affect/
codebase/src/net/sourceforge/pain/logic/event/
codebase/src/net/sourceforge/pain/logic/event/deploy/
codebase/src/net/sourceforge/pain/logic/event/guitool/
codebase/src/net/sourceforge/pain/logic/event/guitool/event/
codebase/src/net/sourceforge/pain/logic/fn/util/
codebase/src/net/sourceforge/pain/logic/trigger/
codebase/src/net/sourceforge/pain/logic/trigger/impl/
codebase/src/net/sourceforge/pain/network/console/
codebase/src/net/sourceforge/pain/network/console/telnet/
codebase/src/net/sourceforge/pain/network/guitool/
codebase/src/net/sourceforge/pain/plugin/
codebase/src/net/sourceforge/pain/plugin/command/
codebase/src/net/sourceforge/pain/plugin/reset/
codebase/src/net/sourceforge/pain/plugin/shutdown/
codebase/src/net/sourceforge/pain/plugin/social/
codebase/src/net/sourceforge/pain/util/
db/doc/javadoc/resources/
db/src/net/sourceforge/pain/util/
gui/
gui/lib/
gui/src/net/sourceforge/pain/tools/guitool/dbbrowse/
gui/src/net/sourceforge/pain/tools/guitool/dialog/
gui/src/net/sourceforge/pain/tools/guitool/menu/
gui/src/net/sourceforge/pain/tools/guitool/resources/
gui/src/net/sourceforge/pain/tools/guitool/resources/images/
gui/src/net/sourceforge/pain/tools/guitool/resources/images/explorer/
tests/
tests/src/
tests/src/net/sourceforge/pain/db/data/
package net.sourceforge.pain.network.guitool;

import net.sourceforge.pain.util.*;

import java.io.*;
import java.net.*;
import java.util.*;

public final class GuiToolConnection implements Runnable {

    private GuiToolConnectionServer server;
    private final ObjectOutputStream os;
    private final ObjectInputStream is;
    private boolean forcedClose;
    private boolean lostLink;

    public Object guiAdminId = null;

    public final LinkedList inputEvents = new LinkedList();
    private final LinkedList outputEvents = new LinkedList();

    Socket socket;
    long sessionStartTime;

    private final Object sendMonitor = new Object();
    private Flusher flusher;

    public GuiToolConnection(GuiToolConnectionServer server, Socket socket) throws IOException {
        this.server = server;
        this.socket = socket;
        os = new ObjectOutputStream(socket.getOutputStream());
        is = new ObjectInputStream(socket.getInputStream());
        sessionStartTime = System.currentTimeMillis();
    }

    public void run() {
        forcedClose = false;
        flusher = new Flusher();
        flusher.start();
        try {
            do {
                try {
                    GTNetPacket inPacket = (GTNetPacket) is.readObject();
                    Log.debug("GTC: new event:" + inPacket.eventClassName);
                    inputEvents.add(inPacket);
                } catch (InterruptedIOException e) {
                    break;
                } catch (IOException e) {
                    if (!forcedClose) {
                        Log.error(e.getMessage(), e);
                        lostLink = true;
                    }
                    break;
                } catch (Exception e) {
                    Log.error(e.getMessage(), e);
                }
            } while (!forcedClose && !lostLink);
        } catch (Exception e) {
            Log.error(e);
        } finally {
            flusher.die();
            server.onClose(this);
            try {
                socket.close();
            } catch (Exception ignored) {
            }
        }
    }


    public void forceClose() {
        Log.debug("GTC:force close!");
        forcedClose = true;
    }

    public void send(GTNetPacket packet) {
        synchronized (sendMonitor) {
            outputEvents.add(packet);
            sendMonitor.notify();
        }
    }


    private final class Flusher extends Thread {
        private boolean isAlive = true;

        public Flusher() {
            setDaemon(true);
        }

        public void run() {
            while (isAlive) {
                if (outputEvents.isEmpty()) {
                    synchronized (sendMonitor) {
                        try {
                            sendMonitor.wait(50);
                        } catch (InterruptedException e) {
                            Log.error(e);
                        }
                    }
                    continue;
                }
                // ok we really have somethong to send 
                while (!outputEvents.isEmpty()) {
                    GTNetPacket packet;
                    synchronized (sendMonitor) {
                        packet = (GTNetPacket) outputEvents.removeFirst();
                    }
                    try {
                        os.writeObject(packet);
                    } catch (IOException e) {
                        Log.error(e);  // do nothing, main thread will catch IO by itself
                    }
                }
                Log.debug("GTC: flushing");
                try {
                    os.flush();
                } catch (IOException e) {
                    Log.error(e);  // do nothing, main thread will catch IO by itself
                }
            }
        }

        public void die() {
            isAlive = false;
            synchronized (sendMonitor) {
                sendMonitor.notify();
            }
        }
    }
}