/
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.console;


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

import java.util.*;

public final class ConsoleManager extends PeriodOfTimeListener implements LogicReloadListener {

    public static final int DEFAULT_PORT = 7777;

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

    private static final int CHECK_PERIOD_IN_PULSE = 10;

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

    public ConsoleManager() {
        this(DEFAULT_PORT);
    }

    public ConsoleManager(int port) {
        super(CHECK_PERIOD_IN_PULSE, PERIOD_IN_PULSE);
        this.port = port;
        Core.getLogicLoader().addLogicReloadListener(this);
    }

    public void init() {
        if (server != null) {
            throw new RuntimeException("CONSOLE_MANAGER:already inited");
        }
        server = new TelnetConsoleServer(port);
    }

    protected synchronized Console register(ConsoleAdapter adapter) {
        Console console = new Console(adapter);
        consoles.add(console);
        return console;
    }

    protected synchronized void onPeriod(int time) throws Exception {
        Console console;
        int nCons = consoles.size();
        if (EVENT_PROMPT_CLASS == null) {
            initEventClasses();
        }
        for (int i = 0; i < nCons; i++) {
            console = (Console) consoles.get(i);
            boolean wasPrompt = false;
            if (console.state == Console.STATE_ACTIVE) {
                if (console.input.size() > 0) {
                    try {
                        console.newLineProcessingStarted = true;
                        Core.processEvent(EVENT_CONSOLE_INPUT_CLASS, console);
                    } catch (Exception e) {
                        Log.error(e);
                        console.popInputLine();// removing this error line from out queue
                    }
                    if (console.state == Console.STATE_ACTIVE) { // Note: console could be marked inactive during event processing!
                        console.expireTime = time + Console.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 {
                            Core.processEvent(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 != Console.STATE_SYSTEM_CLOSED) {
                                closeConsole(console);
                            }
                        }
                    }
                }
                if (console.state == Console.STATE_ACTIVE) {
                    if (console.hasBufferedOutput) {
                        if (!wasPrompt && console.isCommandMode()) {
                            actPrompt(console);
                        }
                        console.flushOutput();
                    }
                }
            } else if (console.state == Console.STATE_NEW) {
                try {
                    Core.processEvent(EVENT_NEW_CONNECTION_CLASS, console);
                } catch (Exception e) {
                    Log.error(e);
                }
                console.expireTime = time + Console.MAX_INACTIVE_TIME;
                console.state = Console.STATE_ACTIVE;
            } else if (console.state == Console.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 == Console.STATE_REMOTE_CLOSED_1) {
                console.state = Console.STATE_REMOTE_CLOSED_2;
                try {
                    Core.processEvent(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!!
            }
        }
    }

    public static synchronized void closeConsole(Console console) {
        Log.debug("CONSOLE_MANAGER:manual close!");
        if (console.state == Console.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 == Console.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 = Console.STATE_SYSTEM_CLOSED;
    }

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

    private static void actPrompt(Console console) {
        try {
            if (EVENT_PROMPT_CLASS==null) {
                initEventClasses();
            }
            Core.processEvent(EVENT_PROMPT_CLASS, console);
        } catch (Exception e) {
            Log.error(e.getMessage(), e);
        }
    }

    public synchronized Set consoles() {
        return new HashSet(consoles);
    }


    private static void initEventClasses() throws Exception {
        LogicLoadingManager llm = Core.getLogicLoader();
        EVENT_CONSOLE_INPUT_CLASS = llm.provideEventClass("console.ConsoleInputEvent");
        EVENT_CONSOLE_EXPIRED_CLASS = llm.provideEventClass("console.ConsoleExpiredEvent");
        EVENT_NEW_CONNECTION_CLASS = llm.provideEventClass("console.LoginEvent");
        EVENT_CONSOLE_DISCONNECT_CLASS = llm.provideEventClass("console.ConnectionLostEvent");
        EVENT_PROMPT_CLASS = llm.provideEventClass("console.ShowPrompt");
    }

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