package bmsi.fsp;

import java.awt.*;
import java.awt.image.*;
import java.awt.peer.*;
import java.awt.event.*;
import java.awt.datatransfer.Clipboard;
import java.io.IOException;
import java.net.Socket;
import java.net.ServerSocket;
import java.util.Vector;
import java.util.Properties;
import bmsi.tui.TUIColorModel;
import bmsi.tui.ColorModelPeer;
import bmsi.tui.TUIFileDialog;
import bmsi.tui.TUIFontMetrics;

/** Implementation of java.awt.Toolkit.  This class is abstract so that
   it will compile in JDK1.1 or Java 2.  FSToolkit1 will compile in
   JDK1.1 only.  FSToolkit2 will compile in Java 2 only.
   @author Stuart D. Gathman
   Copyright (C) 2000 Business Management Systems, Inc.
 */
public abstract class FSToolkit extends Toolkit implements Runnable {
  ColorModelPeer colorModel = new TUIColorModel();
  private PScreen ps;
  PWinMgr wm;
  private Focus hasFocus;	// FIXME: move to PWinMgr
  FSWindow activeWin;
  EventQueue theQueue;
  Dimension scale = new Dimension(5,5);
  private Vector fontvect;
  private String[] fontlist = { "Terminal" };
  private Thread eventThread = new Thread(this,"FSToolkitEvents");
  { eventThread.setDaemon(true); }
  private boolean active = true;
  private Socket sock;
  FSSync syncit = new FSSync(this);

  synchronized void setFocus(Focus c) {
    if (hasFocus != null)
      hasFocus.loseFocus();
    hasFocus = c;
    c.gainFocus();
  }

  synchronized void removeFocus(Focus c) {
    if (hasFocus == c)
      hasFocus = null;
  }

  synchronized void setActive(FSWindow w) {
    if (activeWin != null)
      activeWin.deactivate();
    activeWin = w;
    w.activate();
  }

  public FSToolkit() throws IOException {
    Runtime rt = Runtime.getRuntime();
    ServerSocket server = new ServerSocket(7112);
    if (false) {
      String cmd = "/bms/obj/panel/proxy -a "
	  + "localhost:" + server.getLocalPort();
      Process prog = rt.exec(cmd);
    //Process prog = rt.exec(new String[] { "sh", "-c", cmd });
    //Process prog = rt.exec("telnet " + "localhost " + server.getLocalPort());
    }
    else {
      System.err.println("telnet to port "+server.getLocalPort()+
      	" to continue");
    }
    Socket sock = server.accept();
    server.close();
    init(sock);
  }

  private void init(Socket sock) throws IOException {
    this.sock = sock;
    //sock.setTcpNoDelay(true);
    ps = new PScreen("wy60",sock);
    theQueue = new EventQueue();
    wm = new PWinMgr(ps);
    eventThread.start();
  }

  public FSToolkit(Socket sock) throws IOException {
    init(sock);
  }

  public void dispose() {
    active = false;
    try {
      ps.close();
      sock.close();
    }
    catch (IOException x) { }
  }

  public void run() {
    Keyboard keyb = ps.getKeyboard();
    try {
      while (active) {
	int k = keyb.readKey();
	if (k == TI.KEY_EXIT + 256) {	// exit JVM
	  dispose();
	  // EventQueue thread is non-daemon and never terminates :-(
	  System.exit(0);
	}
	// translate to KeyEvent
	if (k == keyb.UNDEF) {
	  ps.beep(0);
	  continue;
	}
	Focus hasFocus = this.hasFocus;
	if (hasFocus != null)
	  hasFocus.postKey(k);
      }
    }
    catch (IOException x) {
      throw new AWTError("IO Exception reading keyboard");
    }
  }

  protected ButtonPeer createButton(Button b) { return new FSButton(b,this); }
  protected TextFieldPeer createTextField(TextField t) {
    return null;
  }
  protected LabelPeer createLabel(Label lbl) { return new FSLabel(lbl,this); }
  protected ListPeer createList(List lst) { return null; }
  protected TextAreaPeer createTextArea(TextArea t) {
    return null;
  }
  public FontMetrics getFontMetrics(Font f) {
    return new TUIFontMetrics(f,scale);
  }
  public ColorModel getColorModel() { return colorModel; }

  // how to create various peer objects  -

  protected CheckboxPeer createCheckbox(Checkbox cb) {
    return null;
  }
  protected ScrollbarPeer createScrollbar(Scrollbar s) {
    return null;
  }
  protected ChoicePeer createChoice(Choice c) { return null; }
  protected FramePeer createFrame(Frame f) { return new FSFrame(f,this); }
  protected CanvasPeer createCanvas(Canvas c) { return null; }
  protected PanelPeer createPanel(Panel p) { return null; }
  protected WindowPeer createWindow(Window w) { return new FSWindow(w,this); }
  protected DialogPeer createDialog(Dialog dlg) {
    return null;
  }
  protected MenuBarPeer createMenuBar(MenuBar mnu) {
    return new FSMenuBar(mnu,this);
  }
  protected MenuPeer createMenu(Menu mnu) { return null; }
  protected MenuItemPeer createMenuItem(MenuItem mi) {
    return null;
  }

  protected FileDialogPeer createFileDialog(FileDialog dlg) {
    return new TUIFileDialog(dlg);
  }

  protected CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem mi) {
    // work around AWT bug
    //MenuComponentPeer p = mi.getPeer();
    //if (p != null)
    //  return (CheckboxMenuItemPeer)p;
    return null;
  }

  protected PopupMenuPeer createPopupMenu(PopupMenu target) {
    return null;
  }

  /** Helper function to calculate scaled insets. */
  Insets getInsets() {
    Insets insets = new Insets(1,1,1,1);
    Dimension s = scale;
    insets.left *= s.width;
    insets.right *= s.width;
    insets.top *= s.height;
    insets.bottom *= s.height;
    return insets;
  }

  // TUI's can't reasonably support Image.  Always fail -
  //  However, we might want to support in memory text arrays as
  //  a Canvas with no parent.

  public Image getImage(String name) { return null; }
  public Image getImage(java.net.URL url) { return null; }
  public boolean prepareImage(Image img,int w,int h,ImageObserver obs) {
    return false;
  }
  public int checkImage(Image img,int w,int h,ImageObserver obs) {
    return ImageObserver.ERROR | ImageObserver.ABORT;
  }
  public Image createImage(ImageProducer p) { return null; }
  public Image createImage(byte[] data,int offset,int len) { return null; }

  // Java 2 features compatible with JDK 1.1
  public Image createImage(java.net.URL u) { return null; }
  public Image createImage(String s) { return null; }

  // JDK 1.1 features -

  protected EventQueue getSystemEventQueueImpl() { return theQueue; }

  /** Anybody can beep! */
  public void beep() {
    try {
      ps.beep(0);
    }
    catch (IOException x) { }
  }

  /** This JDK1.1 feature has no documentation! This seems to be a placeholder
      that is not yet used for anything.
   */
  protected FontPeer getFontPeer(String name, int style) {
    //debug("FontPeer needed");
    return null;
  }

  /** TUI's have a clipboard, but we haven't finished this JDK1.1 feature. */
  public Clipboard getSystemClipboard() {
    //debug("ClipBoard needed");
    return null;
  }

  /** TUI's have printers, but we haven't finished this JDK1.1 feature. */
  public PrintJob getPrintJob(Frame frame, String jobtitle, Properties props) {
    //debug("PrintJob needed");
    return null;
  }

  /** TUI's have ScrollPanes, but we haven't finished this JDK1.1 feature. */
  protected ScrollPanePeer createScrollPane(ScrollPane target) {
    //debug("ScrollPane needed");
    return null;
  }

  Dimension scale(Dimension s) {
    s.width *= scale.width;
    s.height *= scale.height;
    return s;
  }

  public Dimension getScreenSize() {
    return scale(new Dimension(ps.getCols(),ps.getRows()));
  }

  public int getScreenResolution() { return 10; } // "pixels"/inch

  public synchronized String[] getFontList() {
    if (fontvect != null) {
      fontlist = new String[fontvect.size()];
      fontvect.copyInto(fontlist);
      fontvect = null;
    }
    return fontlist;
  }

  public void sync() {
    try {
      wm.sync();
      ps.flush();
    }
    catch (IOException x) {
      throw new AWTError(x.toString());
    }
  }

  /** Create an instance of FSGraphics compatible with this Toolkit.
   */
  abstract FSGraphics createGraphics(FSComponent comp);
}
