/* will create new Client object and add it to the 'clients' list
   * and will also register it's socket channel with 'readSelector'.
   * Use 'sendBufferSize' to specify socket's send buffer size. */
  public static Client addNewClient(SocketChannel chan, Selector readSelector, int sendBufferSize) {

    Client client = new Client(chan);
    clients.add(client);

    // register the channel with the selector
    // store a new Client as the Key's attachment
    try {
      chan.configureBlocking(false);
      chan.socket().setSendBufferSize(sendBufferSize);
      // ***chan.socket().setSoTimeout(TIMEOUT_LENGTH); -> this doesn't seem to have an effect with
      // java.nio
      client.selKey = chan.register(readSelector, SelectionKey.OP_READ, client);
    } catch (ClosedChannelException cce) {
      killClient(client);
      return null;
    } catch (IOException ioe) {
      killClient(client);
      return null;
    } catch (Exception e) {
      killClient(client);
      return null;
    }

    return client;
  }
  /* this method disconnects and removes client from the clients list.
   * Also cleans up after him (channels, battles) and notifies other
   * users of his departure. "reason" is used with LEFT command to
   * notify other users on same channel of this client's departure
   * reason (it may be left blank ("") to give no reason). */
  public static boolean killClient(Client client, String reason) {
    int index = clients.indexOf(client);
    if (index == -1) return false;
    if (!client.alive) return false;
    client.disconnect();
    clients.remove(index);
    client.alive = false;
    if (reason.trim().equals("")) reason = "Quit";

    // let's remove client from all channels he is participating in:
    client.leaveAllChannels(reason);

    if (client.battleID != -1) {
      Battle bat = Battles.getBattleByID(client.battleID);
      if (bat == null) {
        System.out.println("Serious error occured: Invalid battle ID. Server will now exit!");
        TASServer.closeServerAndExit();
      }
      Battles.leaveBattle(
          client, bat); // automatically checks if client is founder and closes the battle
    }

    if (client.account.accessLevel() != Account.NIL_ACCESS) {
      sendToAllRegisteredUsers("REMOVEUSER " + client.account.user);
      if (TASServer.DEBUG > 0) System.out.println("Registered user killed: " + client.account.user);
    } else {
      if (TASServer.DEBUG > 0) System.out.println("Unregistered user killed");
    }

    if (TASServer.LAN_MODE) {
      Accounts.removeAccount(client.account);
    }

    return true;
  }
 /* notifies client of all statuses, including his own (but only if they are different from 0) */
 public static void sendInfoOnStatusesToClient(Client client) {
   for (int i = 0; i < clients.size(); i++) {
     if (clients.get(i).account.accessLevel() < Account.NORMAL_ACCESS) continue;
     if (clients.get(i).status
         != 0) // only send it if not 0. User assumes that every new user's status is 0, so we
               // don't need to tell him that explicitly.
     client.sendLine("CLIENTSTATUS " + clients.get(i).account.user + " " + clients.get(i).status);
   }
 }
 /* sends a list of all users connected to the server to client (this list includes
  * the client itself, assuming he is already logged in and in the list) */
 public static void sendListOfAllUsersToClient(Client client) {
   for (int i = 0; i < clients.size(); i++) {
     if (clients.get(i).account.accessLevel() < Account.NORMAL_ACCESS) continue;
     client.sendLine(
         "ADDUSER "
             + clients.get(i).account.user
             + " "
             + clients.get(i).country
             + " "
             + clients.get(i).cpu);
   }
 }