/**
   * Processes each keypress associated with the chat tool window. In the current implementation,
   * any key pressed while pressing and holding down the "Ctrl key" is treated as not being
   * associated with turn-construction and is instead relayed to the TaskController (e.g
   * ClientMazeGameComms if it exists).
   *
   * @param e
   */
  public void keyPressFilter(KeyEvent e) {

    try {
      if (cts.cteh != null && cts.cteh instanceof ClientMazeGameComms) {
        ((ClientMazeGameComms) cts.cteh).relayKeypressToMazeFrame(e);
      }

      int i = e.getKeyCode();
      if (i == 17) {
        this.participantIsEnteringControlCode = true;
        this.jcf.setEditable(false);
      }
      if (this.participantIsEnteringControlCode) {
        if (i == 37 || i == 38 || i == 39 || i == 40) {}

      } else if (!participantIsEnteringControlCode) {
        if (!startOfTypingHasBeenRecorded) {
          startOfTypingHasBeenRecorded = true;
          startOfTyping = new Date().getTime();
        }

        Keypress kp = new Keypress(i, new Date().getTime());
        keyspressedSinceLastTextEntry.addElement(kp);

        cts.sendClientIsTyping(kp, this.jcf.getTextEnteredInField().replaceAll("\\p{Cntrl}", ""));
        // cts.sendClientIsTyping(kp, ".....");
      }
    } catch (Exception e2) {
      cts.sendErrorMessage(e2);
    }
  }
  /**
   * Retrieves text from chat window's text-entry field, does preliminary removal of white space,
   * appends it to the local client's chat window, sends the text to {@link ConnectionToServer} in
   * order to be sent to the server, clears the local timing / and keypress information associated
   * with the turn and then clears the text-entry field.
   */
  public void returnPressed() {
    // System.out.println("return pressed");

    // System.err.println("THE CONTENTS ARE:"+jcf.getContentsOfWindow(0));
    // System.err.println("---------------------------");

    String[] priorChatText = {"", "", ""};

    String text = jcf.getTextEnteredInField();
    text = text.replaceAll("\\p{Cntrl}", "");
    if (jcf instanceof JChatFrameMultipleWindowsWithSendButtonWidthByHeight) {
      jcf.appendWithCaretCheck(
          "", cts.getUsername() + ": ", true, text, jcf.getParticipantsOwnWindow(), "SELF");
    }

    cts.sendChatText(
        (text),
        startOfTyping,
        currentTurnBeingConstructedHasBeenBlocked,
        keyspressedSinceLastTextEntry,
        priorChatText);
    currentTurnBeingConstructedHasBeenBlocked = false;
    jcf.clearTextEntryField(true);
    clearKeypresses();
  }
 /**
  * Invoked by the WYSIWYG interface when text is deleted at the specified offset/length
  *
  * @param offset
  * @param length
  */
 public void wYSIWYGDocumentHasChangedRemove(
     int offset, int length, String textInTextEntryWindow) {
   try {
     String[] priorChatText = {"", "", ""};
     cts.sendWYSIWYGDocumentHasChangedRemove(offset, length, textInTextEntryWindow, priorChatText);
     // System.out.println("WYSIWYGIN CLEVENTHANDLER2");
   } catch (Exception e) {
     cts.sendErrorMessage(e);
   }
 }
 public void wYSIWYGDocumentHasChanged(String textAtEndOfString, int offset) {
   try {
     // System.out.println("WYSIWYGCLEVENTHANDLER1");
     String[] priorChatText = {"", "", ""};
     cts.sendChatTextWYSIWYG(textAtEndOfString, offset, priorChatText);
     // System.out.println("WYSIWYGIN CLEVENTHANDLER2");
   } catch (Exception e) {
     // EMUI.println(cts.getUsername(),"ERROR IN CLEVENTHANDLER");
   }
   // clearKeypresses();
 }
  /**
   * Retrieves text from chat window's text-entry field, does preliminary removal of white space,
   * appends it to the local client's chat window, sends the text to {@link ConnectionToServer} in
   * order to be sent to the server, clears the local timing / and keypress information associated
   * with the turn and then clears the text-entry field.
   */
  public void sendButtonPressed() {

    String[] priorChatText = {"", "", ""};
    String text = jcf.getTextEnteredInField();
    text = text.replaceAll("\n", "");
    if (jcf instanceof JChatFrameMultipleWindowsWithSendButtonWidthByHeight) {
      jcf.appendWithCaretCheck(
          "", cts.getUsername() + ": ", true, text, jcf.getParticipantsOwnWindow(), "SELF");
    }

    cts.sendChatText(
        text,
        startOfTyping,
        currentTurnBeingConstructedHasBeenBlocked,
        keyspressedSinceLastTextEntry,
        priorChatText);
    currentTurnBeingConstructedHasBeenBlocked = false;
    jcf.clearTextEntryField(true);
    clearKeypresses();
  }
  /**
   * Detects whether the key being released is the "Ctrl" key. If yes, the control sequence being
   * relayed to the TaskController (e.g. ClientMazeGameComms) is terminated.
   *
   * @param e
   */
  public void keyReleaseFilter(KeyEvent e) {
    try {
      if (cts.cteh != null && cts.cteh instanceof ClientMazeGameComms) {
        ((ClientMazeGameComms) cts.cteh).relayKeyReleaseFilterToMazeFrame(e);
      }

      if (e.getKeyCode() == 17) {
        participantIsEnteringControlCode = false;
        this.jcf.setEditable(true);
        // System.out.println("go"+e.getKeyCode());

      }
      if (e.getKeyCode() == 10) {
        returnPressed();
      }
    } catch (Exception e2) {
      cts.sendErrorMessage(e2);
    }
  }
 /** Dissociate all players with this connection */
 public synchronized void removeConnection(ConnectionToServer c) {
   principals.remove(c);
   c.setWorld(null);
 }
  /**
   * TODO deprecate strings in favour of certificates XXX currently we only support a single player
   * per connection.
   *
   * @param player the player trying to connect
   * @return true if the connection was successfully identified with the specified player
   */
  public synchronized boolean addConnection(ConnectionToServer c, Player player, byte[] signature) {
    logger.log(Level.INFO, "Authenticating player " + player.getName());

    /* determine whether this identity already exists */
    NonNullElements i =
        new NonNullElements(KEY.PLAYERS, serverGameEngine.getWorld(), Player.AUTHORITATIVE);

    while (i.next()) {
      Player p = (Player) i.getElement();

      if (p.getName().equals(player.getName())) {
        /* this player already exists */
        /* is this identity already connected ? */
        if (principals.containsValue(p)) {
          logger.log(Level.INFO, "Player " + p.getName() + " is already" + " connected");

          return false;
        }

        /* is this player the same as the one which previously
         * connected under the same name? */
        logger.log(Level.FINE, "Verifying player " + p + " with " + player);

        if (!p.verify(player, signature)) {
          logger.log(Level.WARNING, "Couldn't verify signature of player " + p.getName());

          return false;
        }

        principals.put(c, p);

        /* set the connection world */
        if (c instanceof LocalConnection) {
          // don't create a WorldView, since the local client needs
          // to synchronize against the world object itself.
          c.setWorld(serverGameEngine.getWorld());
        } else {
          c.setWorld(new WorldView(serverGameEngine.getWorld(), p.getPrincipal()));
        }

        return true;
      }
    }

    /* this player does not already exist */
    logger.log(
        Level.INFO, "Adding player " + player.getName() + " to " + serverGameEngine.getWorld());

    MoveConfirmer mc =
        new MoveConfirmer(serverGameEngine.getMoveExecuter(), serverGameEngine.getMoveChainFork());
    AddPlayerMove m = new AddPlayerMove(serverGameEngine.getWorld(), player);
    MoveStatus ms = mc.confirmMove(m, null);

    assert ms == MoveStatus.MOVE_OK;

    /*
     * get the newly created player-with-principal
     */
    World w = serverGameEngine.getWorld();
    assert (w != null);
    player =
        (Player)
            w.get(KEY.PLAYERS, w.size(KEY.PLAYERS, Player.AUTHORITATIVE) - 1, Player.AUTHORITATIVE);

    principals.put(c, player);

    /* Perform any moves necessary for adding a new player */
    serverGameEngine
        .getMoveExecuter()
        .processMove(statGatherer.generateNewPlayerMove(player.getPrincipal()), c);
    serverGameEngine
        .getMoveExecuter()
        .processMove(scenario.getSetupMoves(serverGameEngine.getWorld(), player.getPrincipal()), c);

    /* set the connection world */
    c.setWorld(new WorldView(serverGameEngine.getWorld(), player.getPrincipal()));
    return true;
  }