/
codebase/src/net/sourceforge/pain/admin/console/command/
codebase/src/net/sourceforge/pain/data/role/
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/util/
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/
mudlibs/tinylib/
mudlibs/tinylib/area/
mudlibs/tinylib/etc/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/data/affect/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/data/prototype/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/data/trigger/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/affect/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/event/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/event/deploy/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/event/guitool/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/event/guitool/event/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/fn/util/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/trigger/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/trigger/impl/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/plugin/command/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/plugin/reset/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/plugin/shutdown/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/plugin/social/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/util/
tests/
tests/src/
tests/src/net/sourceforge/pain/db/data/
package net.sourceforge.pain.network.console;

import net.sourceforge.pain.*;
import net.sourceforge.pain.logic.*;
import net.sourceforge.pain.network.console.telnet.*;
import net.sourceforge.pain.util.*;

import java.util.*;

/**
 * Network console management system. Implementors should supply
 * events handling routines only.
 */
public abstract class AbstractConsoleManager extends PulsePeriodListener implements LogicReloadListener {

    protected ArrayList consoles = new ArrayList();
    private TelnetConsoleServer server = null;
    protected int port;

    Class EVENT_CONSOLE_INPUT_CLASS;
    Class EVENT_CONSOLE_EXPIRED_CLASS;
    Class EVENT_NEW_CONNECTION_CLASS;
    Class EVENT_CONSOLE_DISCONNECT_CLASS;
    Class EVENT_PROMPT_CLASS;

    private static final int CHECK_PERIOD_IN_PULSE = 10;
    private String logName;
    private ConsoleFactory cf;


    public AbstractConsoleManager(String logName, int port, ConsoleFactory cf) {
        super(CHECK_PERIOD_IN_PULSE, PERIOD_IN_PULSE);
        this.logName = logName;
        this.cf = cf;
        this.port = port;
    }


    public void start() {
        Codebase.getLogicLoader().addLogicReloadListener(this);
        Codebase.getPulse().addListener(this);
        server = new TelnetConsoleServer(port, this);
    }

    public boolean isStarted() {
        return server != null;
    }

    public void stop() {
        Codebase.getLogicLoader().removeReloadLogicListener(this);
        Codebase.getPulse().removeListener(this);
        server.stop();
        server = null;
    }


    protected synchronized void onPeriod(int time) throws Exception {
        if (EVENT_PROMPT_CLASS == null) {
            initEventClasses();
        }
        BasicConsole console;
        int nCons = consoles.size();
        for (int i = 0; i < nCons; i++) {
            console = (BasicConsole) consoles.get(i);
            boolean wasPrompt = false;
            if (console.state == BasicConsole.STATE_ACTIVE) {
                if (console.input.size() > 0) {
                    try {
                        console.newLineProcessingStarted = true;
                        emitEvent(EVENT_CONSOLE_INPUT_CLASS, console);
                    } catch (Exception e) {
                        Log.error(e);
                        console.popInputLine();// removing this error line from out queue
                    }
                    if (console.state == BasicConsole.STATE_ACTIVE) { // Note: console could be marked inactive during event processing!
                        console.expireTime = time + BasicConsole.MAX_INACTIVE_TIME;
                        if (console.isCommandMode()) {
                            actPrompt(console);
                            wasPrompt = true;
                            if (console.input.size() > 0 && console.isCommandMode()) {
                                console.out(ConsoleAdapter.NEW_LINE);
                            }
                        }
                    }
                } else {
                    if (time > console.expireTime) {
                        try {
                            emitEvent(EVENT_CONSOLE_EXPIRED_CLASS, console);
                        } catch (Exception e) { // if error occured we will force to close console
                            Log.error(e.getMessage(), e);
                        } finally {
                            if (console.state != BasicConsole.STATE_SYSTEM_CLOSED) {
                                closeConsole(console);
                            }
                        }
                    }
                }
                if (console.state == BasicConsole.STATE_ACTIVE) {
                    if (console.hasBufferedOutput) {
                        if (!wasPrompt && console.isCommandMode()) {
                            actPrompt(console);
                        }
                        console.flushOutput();
                    }
                }
            } else if (console.state == BasicConsole.STATE_NEW) {
                try {
                    emitEvent(EVENT_NEW_CONNECTION_CLASS, console);
                } catch (Exception e) {
                    Log.error(e);
                    if (console.state != BasicConsole.STATE_SYSTEM_CLOSED) {
                        closeConsole(console);
                    }
                }
                if (console.state == BasicConsole.STATE_NEW) {
                    console.expireTime = time + BasicConsole.MAX_INACTIVE_TIME;
                    console.state = BasicConsole.STATE_ACTIVE;
                } else {
                    // console was closed..
                }
            } else if (console.state == BasicConsole.STATE_SYSTEM_CLOSED) {
                if (console.adapter != null) { // if was not closed remotely (disconnected)
                    console.adapter.forceClose();
                }
                consoles.remove(i);
                i--;
                nCons--;
            } else if (console.state == BasicConsole.STATE_REMOTE_CLOSED_1) {
                console.state = BasicConsole.STATE_REMOTE_CLOSED_2;
                try {
                    emitEvent(EVENT_CONSOLE_DISCONNECT_CLASS, console);
                } catch (Exception e) {
                    Log.error(e.getMessage(), e);
                    closeConsole(console);
                }
            } else {
                // we do nothing with REMOTE closed consoles here
                // system MUST close it from it's side -> console should become STATE_SYSTEM_CLOSED!!
            }
        }
    }

    private void actPrompt(BasicConsole console) {
        try {
            if (EVENT_PROMPT_CLASS == null) {
                initEventClasses();
            }
            emitEvent(EVENT_PROMPT_CLASS, console);
        } catch (Exception e) {
            Log.error(e.getMessage(), e);
        }
    }


    protected synchronized BasicConsole register(ConsoleAdapter adapter) {
        BasicConsole console = cf.provideConsole(adapter);
        consoles.add(console);
        return console;
    }


    public synchronized void closeConsole(BasicConsole console) {
        Log.debug(logName + ":manual close!");
        if (console.state == BasicConsole.STATE_NEW) {
            // This state is possible since we allow
            // to get a consoles Set copy by consoles() method for outer code
            console.flushOutput();
        } else if (console.state == BasicConsole.STATE_ACTIVE) {
            console.flushOutput();
        } else {
            // console also could have STATE_REMOTE_CLOSE_2 here
            // we should not do any special in this case
        }
        console.state = BasicConsole.STATE_SYSTEM_CLOSED;
    }

    protected synchronized void onRemoteClose(BasicConsole console) {
        Log.debug(logName + ":remote close!");
        if (console.state == BasicConsole.STATE_NEW) {
            consoles.remove(console);
        } else if (console.state == BasicConsole.STATE_ACTIVE) {
            console.adapter = null;
            console.state = BasicConsole.STATE_REMOTE_CLOSED_1;
        }
    }

    public synchronized List consoles() {
        return Collections.unmodifiableList(consoles);
    }

    public void onLogicReloading() {
        EVENT_CONSOLE_INPUT_CLASS = null;
        EVENT_CONSOLE_EXPIRED_CLASS = null;
        EVENT_NEW_CONNECTION_CLASS = null;
        EVENT_CONSOLE_DISCONNECT_CLASS = null;
        EVENT_PROMPT_CLASS = null;
    }

    protected abstract void emitEvent(Class eventClass, BasicConsole c) throws Exception;

    protected abstract void initEventClasses() throws Exception;

}