/* -*-mode:java; c-basic-offset:2; -*- */
/* JCTerm
 * Copyright (C) 2002 ymnk, JCraft,Inc.
 *
 * Written by: 2002 ymnk<ymnk@jcaft.com>
 *
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public License
 * as published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package com.jcraft.jcterm;

import java.awt.AWTEvent;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dialog;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Label;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Proxy;
import com.jcraft.jsch.ProxyHTTP;
import com.jcraft.jsch.ProxySOCKS5;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;

public class JCTermAWT extends Panel implements KeyListener, ActionListener,
        Runnable, Term {
    private static final int SHELL = 0;
    private static final int SFTP = 1;
    private static final int EXEC = 2;

    private int mode = SHELL;

    private OutputStream out;
    private InputStream in;

    private Image img;
    private Image background;
    private Graphics cursor_graphics;
    private Graphics graphics;
    private java.awt.Color bground = Color.white;
    private java.awt.Color fground = Color.black;
    private java.awt.Component term_area = null;
    private java.awt.Font font;

    private int term_width = 80;
    private int term_height = 24;

    private int x = 0;
    private int y = 0;
    private int descent = 0;

    private int char_width;
    private int char_height;

    private String xhost = "127.0.0.1";
    private int xport = 0;
    private boolean xforwarding = false;
    private String user = System.getProperty("user.name");
    private String host = "127.0.0.1";

    private String proxy_http_host = null;
    private int proxy_http_port = 0;

    private String proxy_socks5_host = null;
    private int proxy_socks5_port = 0;

    private Session session = null;
    private Proxy proxy = null;

    private boolean antialiasing = true;
    // private int line_space=0;
    private int line_space = -2;
    private int compression = 0;

    private Splash splash = null;

    public JCTermAWT() {
        enableEvents(AWTEvent.KEY_EVENT_MASK);
    }

    void initGraphics() {

        font = java.awt.Font.decode("Monospaced-14");
        img = createImage(1, 1);
        graphics = img.getGraphics();
        graphics.setFont(font);
        {
            FontMetrics fo = graphics.getFontMetrics();
            descent = fo.getDescent();
            // System.out.println(fo.getDescent());
            // System.out.println(fo.getAscent());
            // System.out.println(fo.getLeading());
            // System.out.println(fo.getHeight());
            // System.out.println(fo.getMaxAscent());
            // System.out.println(fo.getMaxDescent());
            // System.out.println(fo.getMaxDecent());
            // System.out.println(fo.getMaxAdvance());
            char_width = (int) (fo.charWidth((char) '@'));
            char_height = (int) (fo.getHeight()) + (line_space * 2);
            // descent+=line_space;
        }
        img.flush();
        graphics.dispose();

        background = createImage(char_width, char_height);

        {
            Graphics foog = background.getGraphics();
            foog.setColor(bground);
            foog.fillRect(0, 0, char_width, char_height);
            foog.dispose();
        }

        img = createImage(getTermWidth(), getTermHeight());
        graphics = img.getGraphics();
        graphics.setFont(font);

        if (splash != null)
            splash.draw(img, getTermWidth(), getTermHeight());
        else
            clear();

        cursor_graphics = (img.getGraphics());
        cursor_graphics.setColor(fground);
        cursor_graphics.setXORMode(bground);

        // setAntiAliasing(antialiasing);

        term_area = this;

        Panel panel = this;
        panel.setSize(getTermWidth(), getTermHeight());
        panel.setFocusable(true);
        // panel.enableInputMethods(true);

        // panel.setFocusTraversalKeysEnabled(false);
        // panel.setOpaque(true);
    }

    public void setFrame(java.awt.Component term_area) {
        this.term_area = term_area;
    }

    private Thread thread = null;

    public void kick() {
        this.thread = new Thread(this);
        this.thread.start();
    }

    MyUserInfo ui = null;

    private Emulator emulator = null;

    public void run() {
        JSch jsch = new JSch();
        while (thread != null) {
            try {

                try {
                    session = jsch.getSession(user, host, 22);
                    session.setProxy(proxy);

                    ui = new MyUserInfo();
                    session.setUserInfo(ui);

                    java.util.Properties config = new java.util.Properties();
                    if (compression == 0) {
                        config.put("compression.s2c", "none");
                        config.put("compression.c2s", "none");
                    } else {
                        config.put("compression.s2c", "zlib,none");
                        config.put("compression.c2s", "zlib,none");
                    }
                    session.setConfig(config);

                    session.connect();
                } catch (Exception e) {
                    // System.out.println(e);
                    break;
                }

                Channel channel = null;

                if (mode == SHELL) {
                    channel = session.openChannel("shell");
                    if (xforwarding) {
                        session.setX11Host(xhost);
                        session.setX11Port(xport + 6000);
                        channel.setXForwarding(true);
                    }

                    out = channel.getOutputStream();
                    in = channel.getInputStream();

                    channel.connect();
                } else if (mode == SFTP) {

                    out = new PipedOutputStream();
                    in = new PipedInputStream();

                    channel = session.openChannel("sftp");

                    // out=channel.getOutputStream();
                    // in=channel.getInputStream();

                    channel.connect();

                    (new Sftp((ChannelSftp) channel,
                            (InputStream) (new PipedInputStream(
                                    (PipedOutputStream) out)),
                            new PipedOutputStream((PipedInputStream) in)))
                            .kick();
                }

                requestFocus();

                emulator = new EmulatorVT100(this, in);
                emulator.reset();
                emulator.start();
            } catch (Exception e) {
                // e.printStackTrace();
            }
            break;
        }

        thread = null;

        if (session != null) {
            session.disconnect();
            session = null;
        }

        if (splash != null)
            splash.draw(img, getTermWidth(), getTermHeight());
        else
            clear();

        redraw(0, 0, getTermWidth(), getTermHeight());
    }

    public void paintComponent(Graphics g) {
        // System.out.println("paintComponent");
        g.drawImage(img, 0, 0, term_area);
    }

    public void update(Graphics g) {
        // System.out.println("update");
        g.drawImage(img, 0, 0, term_area);
        super.update(g);
    }

    public void paint(Graphics g) {
        // System.out.println("paint");
        g.drawImage(img, 0, 0, term_area);
        super.paint(g);
    }

    public void processKeyEvent(KeyEvent e) {
        // System.out.println(e);
        int id = e.getID();
        if (id == KeyEvent.KEY_PRESSED) {
            keyPressed(e);
        } else if (id == KeyEvent.KEY_RELEASED) { /* keyReleased(e); */
        } else if (id == KeyEvent.KEY_TYPED) {
            keyTyped(e);/* keyTyped(e); */
        }
        e.consume(); // ??
    }

    byte[] obuffer = new byte[3];

    public void keyPressed(KeyEvent e) {
        int keycode = e.getKeyCode();
        byte[] code = null;
        switch (keycode) {
        case KeyEvent.VK_CONTROL:
        case KeyEvent.VK_SHIFT:
        case KeyEvent.VK_ALT:
        case KeyEvent.VK_CAPS_LOCK:
            return;
        case KeyEvent.VK_ENTER:
            code = emulator.getCodeENTER();
            break;
        case KeyEvent.VK_UP:
            code = emulator.getCodeUP();
            break;
        case KeyEvent.VK_DOWN:
            code = emulator.getCodeDOWN();
            break;
        case KeyEvent.VK_RIGHT:
            code = emulator.getCodeRIGHT();
            break;
        case KeyEvent.VK_LEFT:
            code = emulator.getCodeLEFT();
            break;
        case KeyEvent.VK_F1:
            code = emulator.getCodeF1();
            break;
        case KeyEvent.VK_F2:
            code = emulator.getCodeF2();
            break;
        case KeyEvent.VK_F3:
            code = emulator.getCodeF3();
            break;
        case KeyEvent.VK_F4:
            code = emulator.getCodeF4();
            break;
        case KeyEvent.VK_F5:
            code = emulator.getCodeF5();
            break;
        case KeyEvent.VK_F6:
            code = emulator.getCodeF6();
            break;
        case KeyEvent.VK_F7:
            code = emulator.getCodeF7();
            break;
        case KeyEvent.VK_F8:
            code = emulator.getCodeF8();
            break;
        case KeyEvent.VK_F9:
            code = emulator.getCodeF9();
            break;
        case KeyEvent.VK_F10:
            code = emulator.getCodeF10();
            break;
        }
        if (code != null) {
            try {
                out.write(code, 0, code.length);
                out.flush();
            } catch (Exception ee) {
            }
            return;
        }

        char keychar = e.getKeyChar();
        if ((keychar & 0xff00) == 0) {
            obuffer[0] = (byte) (e.getKeyChar());
            try {
                out.write(obuffer, 0, 1);
                out.flush();
            } catch (Exception ee) {
            }
        }
    }

    public void keyTyped(KeyEvent e) {
        char keychar = e.getKeyChar();
        if ((keychar & 0xff00) != 0) {
            char[] foo = new char[1];
            foo[0] = keychar;
            try {
                byte[] goo = new String(foo).getBytes("EUC-JP");
                out.write(goo, 0, goo.length);
                out.flush();
            } catch (Exception eee) {
            }
        }
    }

    public int getTermWidth() {
        return char_width * term_width;
    }

    public int getTermHeight() {
        return char_height * term_height;
    }

    public int getCharWidth() {
        return char_width;
    }

    public int getCharHeight() {
        return char_height;
    }

    public int getColumnCount() {
        return term_width;
    }

    public int getRowCount() {
        return term_height;
    }

    public void clear() {
        graphics.setColor(bground);
        graphics.fillRect(0, 0, char_width * term_width, char_height
                * term_height);
        graphics.setColor(fground);
    }

    public void setCursor(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void draw_cursor() {
        cursor_graphics.fillRect(x, y - char_height, char_width, char_height);
        // term_area.repaint(x, y-char_height, char_width, char_height);
        repaint(x, y - char_height, char_width, char_height);
    }

    public void redraw(int x, int y, int width, int height) {
        // term_area.repaint(x, y, width, height);
        repaint(x, y, width, height);
    }

    public void clear_area(int x1, int y1, int x2, int y2) {
        for (int i = y1; i < y2; i += char_height) {
            for (int j = x1; j < x2; j += char_width) {
                graphics.drawImage(background, j, i, term_area);
            }
        }
    }

    public void scroll_area(int x, int y, int w, int h, int dx, int dy) {
        graphics.copyArea(x, y, w, h, dx, dy);
    }

    public void drawBytes(byte[] buf, int s, int len, int x, int y) {
        // System.out.println("drawBytes: "+new String(buf, s,
        // len)+" "+graphics);
        // clear_area(x, y, x+len*char_width, y+char_height);
        // graphics.setColor(fground);
        graphics.drawBytes(buf, s, len, x, y - (descent + line_space));
    }

    public void drawString(String str, int x, int y) {
        // System.out.println("drawString: "+str);
        // clear_area(x, y, x+str.length()*char_width, y+char_height);
        // graphics.setColor(fground);
        graphics.drawString(str, x, y - (descent + line_space));
    }

    public void beep() {
        Toolkit.getDefaultToolkit().beep();
    }

    public class MyUserInfo implements UserInfo {
        public boolean promptYesNo(String str) {
            // System.out.println(str);
            PromptDialog dialog = new PromptDialog("Warning", str);
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                }
                if (!dialog.isVisible()) {
                    break;
                }
            }
            return dialog.result;
        }

        String passwd = null;
        String passphrase = null;

        public String getPassword() {
            return passwd;
        }

        /**
         * 
         * @uml.property name="passphrase"
         */
        public String getPassphrase() {
            return passphrase;
        }

        public boolean promptPassword(String message) {
            InputDialog dialog = new InputDialog(message, "", true);
            passwd = dialog.getText();
            return passwd != null;
        }

        public boolean promptPassphrase(String message) {
            InputDialog dialog = new InputDialog(message, "", true);
            passphrase = dialog.getText();
            return passphrase != null;
        }

        public void showMessage(String message) {
            MessageDialog msg = new MessageDialog("", message);
        }
    }

    /** Ignores key released events. */
    public void keyReleased(KeyEvent event) {
    }

    // public void keyPressed(KeyEvent event){}

    public void setProxyHttp(String host, int port) {
        proxy_http_host = host;
        proxy_http_port = port;
        if (proxy_http_host != null && proxy_http_port != 0) {
            proxy = new ProxyHTTP(proxy_http_host, proxy_http_port);
        } else {
            proxy = null;
        }
    }

    public String getProxyHttpHost() {
        return proxy_http_host;
    }

    public int getProxyHttpPort() {
        return proxy_http_port;
    }

    public void setProxySOCKS5(String host, int port) {
        proxy_socks5_host = host;
        proxy_socks5_port = port;
        if (proxy_socks5_host != null && proxy_socks5_port != 0) {
            proxy = new ProxySOCKS5(proxy_socks5_host, proxy_socks5_port);
        } else {
            proxy = null;
        }
    }

    public String getProxySOCKS5Host() {
        return proxy_socks5_host;
    }

    public int getProxySOCKS5Port() {
        return proxy_socks5_port;
    }

    public void setSplash(Splash foo) {
        this.splash = foo;
    }

    public void setXHost(String xhost) {
        this.xhost = xhost;
    }

    public void setXPort(int xport) {
        this.xport = xport;
    }

    public void setXForwarding(boolean foo) {
        this.xforwarding = foo;
    }

    public void setLineSpace(int foo) {
        this.line_space = foo;
    }

    public void setAntiAliasing(boolean foo) {
        /*
         * if(graphics==null) return; antialiasing=foo; java.lang.Object
         * mode=foo? RenderingHints.VALUE_TEXT_ANTIALIAS_ON:
         * RenderingHints.VALUE_TEXT_ANTIALIAS_OFF; RenderingHints hints= new
         * RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, mode);
         * graphics.setRenderingHints(hints);
         */
    }

    public void setCompression(int compression) {
        if (compression < 0 || 9 < compression)
            return;
        this.compression = compression;
    }

    public int getCompression() {
        return compression;
    }

    public void setUserHost(String userhost) {
        try {
            String _user = userhost.substring(0, userhost.indexOf('@'));
            String _host = userhost.substring(userhost.indexOf('@') + 1);
            this.user = _user;
            this.host = _host;
        } catch (Exception e) {
        }
    }

    public void openSession() {
        kick();
    }

    public void setPortForwardingL(int port1, String host, int port2) {
        try {
            session.setPortForwardingL(port1, host, port2);
        } catch (JSchException e) {
        }
    }

    public void setPortForwardingR(int port1, String host, int port2) {
        try {
            session.setPortForwardingR(port1, host, port2);
        } catch (JSchException e) {
        }
    }

    Dialog dialog = null;
    TextField textf = null;
    Button ok = null;
    Label label = null;

    private Dialog getDialog() {
        if (dialog == null) {
            dialog = new Dialog(new Frame(), "", true);
            ok = new Button("OK");
            Button cancel = new Button("CANCEL");
            textf = new TextField(20);
            dialog.setLayout(new FlowLayout());
            dialog.setLocation(100, 50);
            ok.addActionListener(this);
            cancel.addActionListener(this);
            dialog.add(textf);
            dialog.add(ok);
            dialog.add(cancel);
            dialog.pack();
        }
        textf.setEchoChar((char) 0);
        return dialog;
    }

    public void actionPerformed(ActionEvent e) {
        String action = e.getActionCommand();
        if (action.equals("Open SHELL Session...")
                || action.equals("Open SFTP Session...")) {
            if (thread == null) {
                if (action.equals("Open SHELL Session...")) {
                    mode = SHELL;
                } else if (action.equals("Open SFTP Session...")) {
                    mode = SFTP;
                }
                while (true) {
                    InputDialog dialog = new InputDialog(
                            "Enter username@hostname", "", false);
                    try {
                        String _host = dialog.getText();
                        if (_host == null)
                            return;
                        String _user = _host.substring(0, _host.indexOf('@'));
                        _host = _host.substring(_host.indexOf('@') + 1);
                        if (_host == null || _host.length() == 0) {
                            return;
                        }
                        user = _user;
                        host = _host;
                        openSession();
                        return;
                    } catch (Exception ee) {
                    }
                }
            }
        } else if (action.equals("HTTP...")) {
            String foo = getProxyHttpHost();
            int bar = getProxyHttpPort();

            InputDialog dialog = new InputDialog(
                    "HTTP proxy server (hostname:port)",
                    ((foo != null && bar != 0) ? foo + ":" + bar : ""), false);
            String proxy = dialog.getText();
            if (proxy == null)
                return;
            if (proxy.length() == 0) {
                setProxyHttp(null, 0);
                return;
            }
            try {
                foo = proxy.substring(0, proxy.indexOf(':'));
                bar = Integer.parseInt(proxy.substring(proxy.indexOf(':') + 1));
                if (foo != null) {
                    setProxyHttp(foo, bar);
                }
            } catch (Exception ee) {
            }

        } else if (action.equals("SOCKS5...")) {
            String foo = getProxySOCKS5Host();
            int bar = getProxySOCKS5Port();

            InputDialog dialog = new InputDialog(
                    "SOCKS5 server (hostname:1080)",
                    ((foo != null && bar != 0) ? foo + ":" + bar : ""), false);
            String proxy = textf.getText();
            if (proxy == null)
                return;
            if (proxy.length() == 0) {
                setProxySOCKS5(null, 0);
                return;
            }
            try {
                foo = proxy.substring(0, proxy.indexOf(':'));
                bar = Integer.parseInt(proxy.substring(proxy.indexOf(':') + 1));
                if (foo != null) {
                    setProxySOCKS5(foo, bar);
                }
            } catch (Exception ee) {
            }
        }
        /*
         * else if(action.equals("X11 Forwarding...")){ String display=null;
         * display=JOptionPane.showInputDialog(this,
         * "XDisplay name (hostname:0)", (xhost==null)? "": (xhost+":"+xport));
         * try{ if(display!=null){ xhost=display.substring(0,
         * display.indexOf(':'));
         * xport=Integer.parseInt(display.substring(display.indexOf(':')+1));
         * xforwarding=true; } } catch(Exception ee){ xforwarding=false;
         * xhost=null; } }
         */
        /*
         * else if((action.equals("AntiAliasing"))){
         * setAntiAliasing(!antialiasing); }
         */
        else if (action.equals("About...")) {
            MessageDialog msg = new MessageDialog("About...", JCTerm.COPYRIGHT);
        } else if (action.equals("Compression...")) {
            InputDialog dialog = new InputDialog("Compression level(0-9)",
                    new Integer(compression).toString(), false);

            String foo = dialog.getText();
            try {
                if (foo != null) {
                    compression = Integer.parseInt(foo);
                }
            } catch (Exception ee) {
            }
        } else if (action.equals("Line Space...")) {
            InputDialog dialog = new InputDialog("Line Space", new Integer(
                    line_space).toString(), false);

            String foo = dialog.getText();
            try {
                if (foo != null) {
                    setLineSpace(Integer.parseInt(foo));
                }
            } catch (Exception ee) {
            }
        } else if ((action.equals("Local Port..."))
                || (action.equals("Remote Port..."))) {
            if (session == null) {
                // JOptionPane.showMessageDialog(this,
                // "Establish the connection before this setting.");
                return;
            }

            try {
                String title = "";
                if (action.equals("Local Port...")) {
                    title += "Local port forwarding";
                } else {
                    title += "remote port forwarding";
                }
                title += "(port:host:hostport)";

                InputDialog dialog = new InputDialog(title, "", false);

                String foo = dialog.getText();
                if (foo == null)
                    return;
                int port1 = Integer
                        .parseInt(foo.substring(0, foo.indexOf(':')));
                foo = foo.substring(foo.indexOf(':') + 1);
                String host = foo.substring(0, foo.indexOf(':'));
                int port2 = Integer
                        .parseInt(foo.substring(foo.indexOf(':') + 1));

                if (action.equals("Local Port...")) {
                    setPortForwardingL(port1, host, port2);
                } else {
                    setPortForwardingR(port1, host, port2);
                }
            } catch (Exception ee) {
            }
        } else if (action.equals("Quit")) {
            quit();
        } else if (action.equals("CANCEL")) {
            dialog.setVisible(false);
        }
        /*
         * else if (action.equals("passwd")){ ui.passwd=textf.getText();
         * dialog.setVisible(false); return; } else if
         * (action.equals("passphrase")){ ui.passphrase=textf.getText();
         * dialog.setVisible(false); return; } else if
         * (action.equals("SOCKS5... return")){ String proxy=textf.getText();
         * if(proxy.length()==0){ setProxySOCKS5(null, 0);
         * dialog.setVisible(false); return; } try{ String
         * foo=proxy.substring(0, proxy.indexOf(':')); int
         * bar=Integer.parseInt(proxy.substring(proxy.indexOf(':')+1));
         * if(foo!=null){ setProxySOCKS5(foo, bar); dialog.setVisible(false); }
         * } catch(Exception ee){ } }
         * 
         * else if ((action.equals("Local Port... return")) ||
         * (action.equals("Remote Port... return"))){ String
         * foo=textf.getText(); int port1=Integer.parseInt(foo.substring(0,
         * foo.indexOf(':'))); foo=foo.substring(foo.indexOf(':')+1); String
         * host=foo.substring(0, foo.indexOf(':')); int
         * port2=Integer.parseInt(foo.substring(foo.indexOf(':')+1));
         * 
         * if(action.equals("Local Port...")){ setPortForwardingL(port1, host,
         * port2); } else{ setPortForwardingR(port1, host, port2); }
         * dialog.setVisible(false); } else if
         * (action.equals("HTTP... return")){ String proxy=textf.getText();
         * if(proxy.length()==0){ setProxyHttp(null, 0);
         * dialog.setVisible(false); return; } try{ String
         * foo=proxy.substring(0, proxy.indexOf(':')); int
         * bar=Integer.parseInt(proxy.substring(proxy.indexOf(':')+1));
         * if(foo!=null){ setProxyHttp(foo, bar); dialog.setVisible(false); } }
         * catch(Exception ee){ } } else if
         * (action.equals("Open SHELL Session... return") ||
         * action.equals("Open SFTP Session... return") ){ try{ String
         * _host=textf.getText(); String _user=_host.substring(0,
         * _host.indexOf('@')); _host=_host.substring(_host.indexOf('@')+1);
         * if(_host==null || _host.length()==0){ return; } user=_user;
         * host=_host; dialog.setVisible(false); openSession(); }
         * catch(Exception ee){ } }
         */
    }

    public MenuBar getMenuBar() {
        MenuBar mb = new MenuBar();
        Menu m;
        MenuItem mi;

        m = new Menu("File");
        mi = new MenuItem("Open SHELL Session...");
        mi.addActionListener(this);
        // mi.setActionCommand("Open SHELL Session...");
        m.add(mi);
        mi = new MenuItem("Open SFTP Session...");
        mi.addActionListener(this);
        // mi.setActionCommand("Open SFTP Session...");
        m.add(mi);
        mi = new MenuItem("Quit");
        mi.addActionListener(this);
        // mi.setActionCommand("Quit");
        m.add(mi);
        mb.add(m);

        m = new Menu("Proxy");
        mi = new MenuItem("HTTP...");
        mi.addActionListener(this);
        // mi.setActionCommand("HTTP...");
        m.add(mi);
        mi = new MenuItem("SOCKS5...");
        mi.addActionListener(this);
        // mi.setActionCommand("SOCKS5...");
        m.add(mi);
        mb.add(m);

        m = new Menu("PortForwarding");
        mi = new MenuItem("Local Port...");
        mi.addActionListener(this);
        // mi.setActionCommand("Local Port...");
        m.add(mi);
        mi = new MenuItem("Remote Port...");
        mi.addActionListener(this);
        // mi.setActionCommand("Remote Port...");
        m.add(mi);
        /*
         * mi=new MenuItem("X11 Forwarding..."); mi.addActionListener(this);
         * mi.setActionCommand("X11 Forwarding..."); m.add(mi); mb.add(m);
         */

        m = new Menu("Etc");
        // mi=new MenuItem("AntiAliasing");
        // mi.addActionListener(this);
        // mi.setActionCommand("AntiAliasing");
        // m.add(mi);
        mi = new MenuItem("Compression...");
        mi.addActionListener(this);
        mi.setActionCommand("Compression...");
        m.add(mi);
        // mi=new MenuItem("Line Space...");
        // mi.addActionListener(this);
        // mi.setActionCommand("Line Space...");
        // m.add(mi);
        mb.add(m);

        m = new Menu("Etc");
        mi = new MenuItem("About...");
        mi.addActionListener(this);
        mi.setActionCommand("About...");
        m.add(mi);
        mb.add(m);

        return mb;
    }

    public static void main(String[] arg) {
        JCTermAWT term = new JCTermAWT();
        Frame frame = new Frame("JCTermAWT");

        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

        MenuBar mb = term.getMenuBar();
        frame.setMenuBar(mb);

        frame.setSize(term.getTermWidth(), term.getTermHeight());
        frame.add("Center", term);

        frame.pack();
        term.setVisible(true);
        frame.setVisible(true);

        term.initGraphics();

        frame.setResizable(true);

        {
            Insets insets = frame.getInsets();
            int foo = term.getTermWidth();
            int bar = term.getTermHeight();
            foo += (insets.left + insets.right);
            bar += (insets.top + insets.bottom);
            frame.setSize(foo, bar);
        }
        frame.setResizable(false);

        term.setFrame(frame);
    }

    public void quit() {
        thread = null;
        if (session != null) {
            session.disconnect();
            session = null;
        }
    }

    public void setFGround(Object f) {
        if (f instanceof String) {
            fground = java.awt.Color.getColor((String) f);
        }
        if (f instanceof java.awt.Color) {
            fground = (java.awt.Color) f;
        }
        graphics.setColor(fground);
    }

    public void setBGround(Object b) {
        if (b instanceof String) {
            bground = java.awt.Color.getColor((String) b);
        }
        if (b instanceof java.awt.Color) {
            bground = (java.awt.Color) b;
        }
        Graphics2D foog = (Graphics2D) (background.getGraphics());
        foog.setColor(bground);
        foog.fillRect(0, 0, char_width, char_height);
        foog.dispose();
    }

    public Object getFGround() {
        return fground;
    }

    public Object getBGround() {
        return bground;
    }

    class InputDialog implements ActionListener {
        String result = null;
        Dialog dialog = null;
        TextField textf = null;

        InputDialog(String title, String text, boolean passwd) {
            super();
            dialog = new Dialog(new Frame(), title, true);
            Button ok = new Button("OK");
            Button cancel = new Button("CANCEL");
            textf = new TextField(20);
            textf.setText(text);
            if (passwd) {
                textf.setEchoChar('*');
            }
            dialog.setLayout(new FlowLayout());
            dialog.setLocation(100, 50);
            ok.addActionListener(this);
            cancel.addActionListener(this);
            dialog.add(textf);
            dialog.add(ok);
            dialog.add(cancel);
            dialog.pack();
            dialog.setVisible(true);
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (Exception ee) {
                }
                if (!dialog.isVisible()) {
                    break;
                }
            }
        }

        public void actionPerformed(ActionEvent e) {
            String action = e.getActionCommand();
            if (action.equals("OK")) {
                result = textf.getText();
            } else if (action.equals("CANCEL")) {
            }
            dialog.setVisible(false);
            return;
        }

        String getText() {
            return result;
        }
    }

    class PromptDialog implements ActionListener {
        boolean result = false;
        Dialog dialog = null;

        PromptDialog(String title, String msg) {
            super();
            dialog = new Dialog(new Frame(), title, true);
            Button ok = new Button("YES");
            Button cancel = new Button("NO");
            dialog.setLayout(new FlowLayout());
            dialog.setLocation(100, 50);
            ok.addActionListener(this);
            cancel.addActionListener(this);
            TextArea text = new TextArea(msg);
            dialog.add(text);
            dialog.add(ok);
            dialog.add(cancel);
            dialog.pack();
            dialog.setVisible(true);
        }

        boolean isVisible() {
            return dialog.isVisible();
        }

        public void actionPerformed(ActionEvent e) {
            String action = e.getActionCommand();
            if (action.equals("YES")) {
                result = true;
            }
            dialog.setVisible(false);
        }
    }

    class MessageDialog implements ActionListener {
        Dialog dialog = null;

        MessageDialog(String title, String msg) {
            super();
            dialog = new Dialog(new Frame(), title, true);
            Button ok = new Button("OK");
            dialog.setLayout(new FlowLayout());
            dialog.setLocation(100, 50);
            ok.addActionListener(this);
            TextArea text = new TextArea(msg);
            dialog.add(text);
            dialog.add(ok);
            dialog.pack();
            dialog.setVisible(true);
        }

        boolean isVisible() {
            return dialog.isVisible();
        }

        public void actionPerformed(ActionEvent e) {
            String action = e.getActionCommand();
            dialog.setVisible(false);
        }
    }

}
