
// GUIOverTelnet.java
// Martin Berglund, 2020
// Modified by Andrew Davison, ad@coe.psu.ac.th, March 2023

/* Fires up a TelnetTerminalServer, and then waits for
   a connection from a telnet client. The client
   is a GUI window containing:
      * a button that shows a simple message

      * a multiline TextBox that displays user input

      * a custom component with displays the
        character typed into it
  and
     * a GUI close button

  The window uses a vertical LinearLayout

  -------------------
  The original threading code for processing
  multiple clients has been removed.
    
   Uses Lanterna 3
   https://github.com/mabe02/lanterna

   Usage (Windows):
     > compile.bat GUIOverTelnet.java
     > run.bat GUIOverTelnet

   Usage (Linux):
     > ./compile.sh GUIOverTelnet.java
     > ./run.sh GUIOverTelnet


  -------------------
  Two ways to create a server-client:

   1. Start the server in a command line window on Windows. 
      Now start a Putty client using the settings: 
           localhost, 1024, telnet
      *and* uncheck the Putty telnet setting:
        "Return key sends Telnet New Line instead of ^M"
or
  2. Start the server in a window on Linux, and start a
     telnet client by typing:
           telnet localhost 1024
     in another window.
*/

import java.io.*;
import java.net.*;
import java.util.*;
import java.nio.charset.Charset;

import com.googlecode.lanterna.*;
import com.googlecode.lanterna.input.*;
import com.googlecode.lanterna.gui2.*;
import com.googlecode.lanterna.screen.*;
import com.googlecode.lanterna.terminal.*;
import com.googlecode.lanterna.terminal.ansi.*;


public class GUIOverTelnet
{
  public static final int LISTEN_PORT = 1024;

  private static final List<TextBox> textBoxes = new ArrayList<>();



  @SuppressWarnings({"unchecked"})
  public static void main(String[] args) 
                        //     throws IOException
  {
    Screen screen = null;
    try {
      TelnetTerminalServer ttServer = new TelnetTerminalServer(LISTEN_PORT, Charset.forName("utf8"));
	  
      System.err.println("Listening on port " + LISTEN_PORT);
	  
      TelnetTerminal tt = ttServer.acceptConnection();
      System.err.println("Accepted connection from " + 
                             tt.getRemoteSocketAddress());
	  
      /* build screen, gui, window for the 
         client who has just been accepted
      */
      screen = new TerminalScreen(tt);
      screen.startScreen();
      MultiWindowTextGUI gui = 
                 new MultiWindowTextGUI(screen);
      BasicWindow window = 
                 new BasicWindow("Text GUI over Telnet");
	  
      Panel p = new Panel();
      p.setLayoutManager(new LinearLayout(Direction.VERTICAL));
	  
      // button
      p.addComponent( new Button("Button", () -> {
        BasicWindow msgBox = new BasicWindow("Response");
        msgBox.setComponent(Panels.vertical(
                    new Label("Hello!"),
                    new Button("Close", msgBox::close)));
        gui.addWindow(msgBox);
      }).withBorder(Borders.singleLine("This is a button")));
	  
	  // text editing box
      TextBox textBox = new TextBox(new TerminalSize(20, 4)) {
        public Result handleKeyStroke(KeyStroke ks)
        {
          try {
            return super.handleKeyStroke(ks);
          }
          finally {
            for(TextBox box: textBoxes)
              if (this != box)
                box.setText(getText());
          }
        } /* handleKeyStroke */
      };
	  
      textBoxes.add(textBox);
      p.addComponent(textBox.withBorder(Borders.singleLine("Text editor")));
	  
      // a custom component
      p.addComponent(new AbstractInteractableComponent() {
        String text = "Press any key";
	  
        protected InteractableRenderer createDefaultRenderer() 
        {
          return new InteractableRenderer() {
            public TerminalSize getPreferredSize(Component comp) 
            {   return new TerminalSize(30, 1); }
	  
            public void drawComponent(TextGUIGraphics tgg, Component comp) 
            {  tgg.putString(0, 0, text);  }
	  
            public TerminalPosition getCursorLocation(Component comp) 
            {   return TerminalPosition.TOP_LEFT_CORNER; }
          };
        }
	  
        public Result handleKeyStroke(KeyStroke ks) 
        {
          if ((ks.getKeyType() == KeyType.Tab) ||
             (ks.getKeyType() == KeyType.ReverseTab) )
            return super.handleKeyStroke(ks);
	  
          if (ks.getKeyType() == KeyType.Character)
            text = "Character: " + ks.getCharacter() +
                     (ks.isCtrlDown() ? " (ctrl)" : "") +
                     (ks.isAltDown() ? " (alt)" : "");
          else
            text = "Key: " + ks.getKeyType() +
                     (ks.isCtrlDown() ? " (ctrl)" : "") +
                     (ks.isAltDown() ? " (alt)" : "");
	  
          return Result.HANDLED;
        }
      }.withBorder(Borders.singleLine("Custom comp")));
	  
      // the close button
      p.addComponent(new Button("Close", window::close));
	  
      // link panel, window, and gui
      window.setComponent(p);
      gui.addWindowAndWait(window);
    }
    catch(SocketException e)
    {  System.err.println(e);  }
    catch(IOException e)
    {  System.err.println(e);  }

    Utils.close(screen);
  } /* runGUI */


} // end of GUIOverTelnet class
