Coverage Summary for Class: PlayerTUI (it.polimi.ingsw.view.TUI)

Class Method, % Line, %
PlayerTUI 0% (0/45) 0% (0/463)
PlayerTUI$1 0% (0/1) 0% (0/1)
Total 0% (0/46) 0% (0/464)


 package it.polimi.ingsw.view.TUI;
 
 import it.polimi.ingsw.view.*;
 
 import it.polimi.ingsw.chat.ReceiveChat;
 import it.polimi.ingsw.chat.SendChat;
 import it.polimi.ingsw.controller.*;
 import it.polimi.ingsw.model.*;
 
 import java.awt.*;
 import java.awt.image.BufferedImage;
 import java.io.*;
 import java.net.Socket;
 import java.rmi.NotBoundException;
 import java.rmi.RemoteException;
 import java.rmi.registry.LocateRegistry;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 
 import java.util.Date;
 
 /**
  * class which represent the player on the client side, mutable,
  * implements Serializable because it will be sent in the socket network
  * @author Ettori Faccincani
  */
 public class PlayerTUI extends Player implements Serializable, PlayerI {
     private transient Thread chatThread = null;
     private final transient BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
     private transient GameI server;
     /**
      * constructor that copies a generic Player object inside a new PlayerTUI object
      * @param p the Player object to copy, received by the server
      */
     public PlayerTUI(Player p) throws RemoteException {
         super();
         name = p.getName();
         isChairMan = p.getIsChairMan();
         library = new Library(p.library);
         objective = p.getPrivateObjective();
         pointsUntilNow = p.pointsUntilNow;
         board = new Board(p.board);
         librariesOfOtherPlayers = new ArrayList<>(p.librariesOfOtherPlayers);
         CO_1_Done = p.getCO_1_Done();
         CO_2_Done = p.getCO_2_Done();
         fullChat = p.getFullChat();
         chairmanName = p.chairmanName;
         activeName = p.activeName;
         numPlayers = p.numPlayers;
         endGame = p.getEndGame();
         pointsMap = p.pointsMap;
     }
     /**
      * standard constructor, starts the main game process on the client side
      * @param mode type of the network chosen by the user
      * @author Ettori
      */
     public PlayerTUI(NetMode mode, String opt) throws RemoteException {
         super();
         System.setProperty("java.rmi.server.hostname", IP.activeIP);
         uiMode = UIMode.TUI;
         netMode = mode;
         System.out.println("\nSoon you will need to enter your nickname for the game");
         try {
             mySocket = new Socket(IP.activeIP, Initializer.PORT);
             outStream = new ObjectOutputStream(mySocket.getOutputStream());
             inStream = new ObjectInputStream(mySocket.getInputStream());
             outStream.flush();
             if(!opt.equals("yes")){
                 outStream.writeObject(false);
             }
         }catch (Exception e){System.out.println("\nServer is inactive, try later"); connectionLost(e);}
         System.out.println("\nClient connected \n\n");
         int width = 200;
         int height = 30;
 
         BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
         Graphics g = image.getGraphics();
         g.setFont(new Font("SansSerif", Font.BOLD, 24));
 
         Graphics2D graphics = (Graphics2D) g;
         graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
         graphics.drawString("My Shelfie", 10, 20);
 
         for (int y = 0; y < height; y++) {
             StringBuilder sb = new StringBuilder();
             for (int x = 0; x < width; x++)
                 sb.append(image.getRGB(x, y) == -16777216 ? " " : "$");
             if (sb.toString().trim().isEmpty())
                 continue;
             System.out.println(sb);
         }
         System.out.println("\n\n");
         chooseUserName();
     }
 
     /**
      * Clone the player on the client in the player on the server
      * @author Ettori
      * @param p the Player that will be cloned in the current Object
      */
     @Override
     public void clone(PlayerTUI p){
         name = p.name;
         isChairMan = p.isChairMan;
         library = new Library(p.library);
         objective = p.objective;
         pointsUntilNow = p.pointsUntilNow;
         board = new Board(p.board);
         librariesOfOtherPlayers = new ArrayList<>(p.librariesOfOtherPlayers);
         CO_1_Done = p.CO_1_Done;
         CO_2_Done = p.CO_2_Done;
         fullChat = p.fullChat;
         chairmanName = p.chairmanName;
         activeName = p.activeName;
         numPlayers = p.numPlayers;
         endGame = p.endGame;
         pointsMap = p.pointsMap;
     }
     /**
      * method for choosing the nickname of the player for the future game
      * @author Ettori
      */
     private void chooseUserName(){
         NameStatus status = null;
         while(true){
             System.out.print("\nInsert your name: ");
             try {
                 name = br.readLine();
             } catch (IOException e) {
                 System.out.println("errore");
                 connectionLost(e);
             }
             if(name.length() == 0 || name.charAt(0) == '@' || name.equals("exit") || name.equals("all") || name.equals("...") || name.equals("names")){
                 System.out.println("Name invalid, choose another name");
                 continue;
             }
             try {
                 outStream.writeObject(name);
                 status = (NameStatus) inStream.readObject();
             }catch(Exception e){connectionLost(e);}
 
             if(status == NameStatus.NOT_TAKEN) {
                 System.out.println("\nName: '" + name + "' accepted by the server!");
                 break;
             }
             if(status == NameStatus.OLD){
                 System.out.println("\nName: '" + name + " was found in a previous game");
                 break;
             }
             if(status == NameStatus.NOT_FOUND){
                 System.out.println("\nAnother game is running and your name was not found...\n");
                 System.exit(0);
             }
             if(status == NameStatus.FOUND){
                 getPreviousState();
                 return;
             }
             System.out.println("Name Taken, choose another name\n");
         }
         getInitialState();
     }
     /**
      * Receive the status of the player (previously disconnected) from the server and restart the game
      * @author Ettori Faccincani
      */
     private void getPreviousState(){
         PlayerTUI p;
         try {
             System.out.println("\nReconnecting to the running game...");
             p = new PlayerTUI((Player)inStream.readObject());
             clone(p);
             drawAll();
             if(netMode == NetMode.RMI)
                 new Thread(this::listenForEndGame).start();
             System.out.println("List of the commands of the chat\n@all for message to everyone\n@\"name\" for private message\n@names to see the nicknames of all the players\n@exit to close the game\n");
         }catch(Exception e){connectionLost(e);}
         try {
             server = (GameI)LocateRegistry.getRegistry(IP.activeIP, Initializer.PORT_RMI).lookup("Server");
         } catch (RemoteException | NotBoundException e) {
             connectionLost(e);
         }
         if(netMode == NetMode.RMI) {
             try {
                 server.addClient(name, this);
             } catch (RemoteException e) {
                 connectionLost(e);
             }
         }
         try {
             outStream.writeObject(true);
         } catch (IOException e) {
             connectionLost(e);
         }
         if(netMode == NetMode.SOCKET)
             new Thread(this::ping).start();
         else
             new Thread(this::pingRMI).start();
         startChatSendThread();
         if(netMode == NetMode.SOCKET) {
             waitForEvents();
         }
     }
     /**
      * Receive the status of the player from the server and attend the start of the game
      * @author Ettori Faccincani
      */
     private void getInitialState(){
         PlayerTUI p;
         try {
             System.out.println("\nBe patient, the game will start soon...");
             p = new PlayerTUI((Player)inStream.readObject());
             clone(p);
             activeName = chairmanName;
             drawAll();
             if(netMode == NetMode.RMI)
                 new Thread(this::listenForEndGame).start();
             System.out.println("List of the commands of the chat\n@all for message to everyone\n@\"name\" for private message\n@names to see the nicknames of all the players\n@exit to close the game");
         }catch(Exception e){connectionLost(e);}
         try {
             server = (GameI)LocateRegistry.getRegistry(IP.activeIP, Initializer.PORT_RMI).lookup("Server");
         } catch (RemoteException | NotBoundException e) {
             connectionLost(e);
         }
         if(netMode == NetMode.RMI) {
             try {
                 server.addClient(name, this);
             } catch (RemoteException e) {
                 connectionLost(e);
             }
         }
         try {
             outStream.writeObject(true);
         } catch (IOException e) {
             connectionLost(e);
         }
         if(netMode == NetMode.SOCKET)
             new Thread(this::ping).start();
         else
             new Thread(this::pingRMI).start();
         if(name.equals(chairmanName)) {
             if(netMode == NetMode.SOCKET) {
                 startChatReceiveThread();
             }
             waitForMove();
         }
         else {
             startChatSendThread();
             if(netMode == NetMode.SOCKET) {
                 waitForEvents();
             }
         }
     }
     /**
      * add a string (chat message) to the full chat of the game
      * @author Ettori
      * @param s the message received, it will be added to the fullChat attribute
      */
     public void addToFullChat(String s){fullChat += s;}
     /**
      * function  used to wait for notification from the server while the player is NON active
      * @author Ettori Faccincani
      */
     private void waitForEvents(){
         boolean flag; //used to indicate that this player has become the active one
         while(true){
             flag = false;
             try {
                 Message msg = (Message) inStream.readObject();
                 switch (msg.getType()) {
                     case YOUR_TURN -> {handleYourTurnEvent(); flag = true;}
                     case CHANGE_TURN -> handleChangeTurnEvent(msg);
                     case UPDATE_UNPLAYABLE -> handleUpdateUnplayableEvent(msg);
                     case UPDATE_GAME -> handleUpdateGameEvent(msg);
                     case FINAL_SCORE -> handleFinalScoreEvent(msg);
                     case CHAT -> handleChatEvent(msg);
                     case CO_1 -> handleCO_1Event(msg);
                     case CO_2 -> handleCO_2Event(msg);
                     case LIB_FULL -> handleLibFullEvent(msg);
                     case DISCONNECTED -> handleDisconnectedEvent(msg);
                     case LOST_CLIENT -> handleLostClientEvent(msg);
                     case SHOW_EVENT -> handleShowEvent(msg);
                 }
                 if(flag)
                     break;
             }catch(Exception e){
                 connectionLost(e);
             }
         }
         waitForMove();
     }
     /**
      * helper function for handling the show event notification from the server
      * @author Ettori
      * @param msg the message containing the necessary information for reacting to the event
      */
     private void handleShowEvent(Message msg){
         if(msg.getAuthor() != null && msg.getAuthor().equals("win")){
             System.out.println("\n" + msg.getContent());
             Game.waitForSeconds(Game.waitTimer);
             System.exit(0);
         }
         System.out.println("\n" + msg.getContent());
     }
     /**
      * helper function for handling the client (not active) disconnection notification from the server
      * @author Ettori
      * @param msg the message containing the necessary information for reacting to the event
      */
     public void handleLostClientEvent(Message msg){
         System.out.println("\nPlayer " + msg.getAuthor() + " disconnected from the game");
     }
     /**
      * helper function for handling the turn event notification from the server
      * @author Ettori
      */
     private void handleYourTurnEvent(){
         activeName = name;
         drawAll();
         stopChatThread();
         if(netMode == NetMode.SOCKET) {
             startChatReceiveThread();
         }
         turnThread = new Thread(() ->{
             try {
                 Thread.sleep(1000 * 60 * 5);
             } catch (InterruptedException e) {
                 return;
             }
             if(activeName.equals(name))
                 sendDoneMove();
         });
         turnThread.start();
     }
     /**
      * helper function for handling the change event notification from the server
      * @author Ettori
      * @param msg the message containing the necessary information for reacting to the event
      */
     private void handleChangeTurnEvent(Message msg){
         startChatSendThread();
         activeName = (String) msg.getContent();
         drawAll();
     }
     /**
      * helper function for handling the unplayble board fixing event notification from the server
      * @author Ettori
      * @param msg the message containing the necessary information for reacting to the event
      */
     private void handleUpdateUnplayableEvent(Message msg){
         board = (Board) msg.getContent();
         drawAll();
         System.out.println("\nBoard updated because it was unplayable");
     }
     /**
      * helper function for handling the update game notification from the server
      * @author Ettori
      * @param msg the message containing the necessary information for reacting to the event
      */
     private void handleUpdateGameEvent(Message msg){
         stopChatThread();
         if(netMode == NetMode.SOCKET)
             sendToServer(new Message(MessageType.STOP, null, null)); // send this message on your Socket (to yourself)
         PlayerSend p = (PlayerSend) msg.getContent();
         board = p.board;
         for(int i = 0; i < numPlayers - 1; i++){
             if(librariesOfOtherPlayers.get(i).name.equals(msg.getAuthor()))
                 librariesOfOtherPlayers.set(i, p.library);
         }
         pointsMap.put(msg.getAuthor(), p.pointsUntilNow);
         if(endGame)
             drawAll();
         System.out.println("\nPlayer " + msg.getAuthor() + " made his move, now wait for the turn to change...");
     }
     /**
      * helper function for handling the final score calculation event notification from the server
      * @author Ettori
      * @param msg the message containing the necessary information for reacting to the event
      */
     private void handleFinalScoreEvent(Message msg){
         System.out.println("\nThe game is finished, this is the final scoreboard:\n\n" + msg.getContent());
         Game.waitForSeconds(Game.showTimer);
         System.exit(0);
     }
     /**
      * helper function for handling the chat message event notification from the server
      * @author Ettori
      * @param msg the message containing the necessary information for reacting to the event
      */
     private void handleChatEvent(Message msg){
         fullChat += msg.getContent();
         if(activeName.equals(name))
             System.out.println(msg.getContent());
         else
             drawAll();
     }
     /**
      * helper function for handling the achievement of the first common objective event notification from the server
      * @author Ettori
      * @param msg the message containing the necessary information for reacting to the event
      */
     private void handleCO_1Event(Message msg){
         System.out.println(msg.getAuthor() + " completed the first common objective getting " + msg.getContent() + " points");
         Game.waitForSeconds(Game.waitTimer);
     }
     /**
      * helper function for handling the achievement of the second common objective event notification from the server
      * @author Ettori
      * @param msg the message containing the necessary information for reacting to the event
      */
     private void handleCO_2Event(Message msg){
         System.out.println(msg.getAuthor() + " completed the second common objective getting " + msg.getContent() + " points");
         Game.waitForSeconds(Game.waitTimer);
     }
     /**
      * helper function for handling the completion of the library event notification from the server
      * @author Ettori
      * @param msg the message containing the necessary information for reacting to the event
      */
     private void handleLibFullEvent(Message msg){
         System.out.println(msg.getAuthor() + " completed the library, the game will continue until the next turn of " + chairmanName);
         Game.waitForSeconds(Game.waitTimer);
         endGame = true;
     }
     /**
      * helper function for handling the disconnection event notification from the server (of the active client)
      * @author Ettori
      * @param msg the message containing the necessary information for reacting to the event
      */
     private void handleDisconnectedEvent(Message msg){
         System.out.println("\nThe active player (" + msg.getAuthor() + ") disconnected from the game");
         if(netMode == NetMode.SOCKET)
             sendToServer(new Message(MessageType.STOP, null, null));
     }
     /**
      * method which waits for the current player's move, checks it and, then, send it to all other users (it also updates the library of this player)
      * @author Ettori Faccincani
      */
     private void waitForMove(){
         if(board.isBoardUnplayable())
             fixUnplayableBoard();
 
         ArrayList<Integer> coords = selectOrder(selectCards());
         int col = selectColumn(coords.size() / 2);
         pickCards(coords, col);
 
         drawAll();
 
         boolean change_1 = checkCO();
         boolean change_2 = checkLibFull();
         if(change_1 || change_2)
             drawAll();
 
         stopChatThread();
         sendDoneMove();
     }
     /**
      * helper method used for getting the cards chosen by the user (coordinates)
      * @author Ettori
      * @return the list og the cards chosen by the player
      */
     private ArrayList<Integer> selectCards(){
         String coordString = "";
         String[] rawCoords;
         ArrayList<Integer> coords;
         while(true){
             System.out.print("\nInsert coordinates of the cards to pick (or @ for chat):\n");
             try {
                 coordString = br.readLine();
             } catch (IOException e) {
                 continue;
             }
             if(coordString.length() == 0)
                 continue;
             rawCoords = coordString.split(" ");
 
             if(coordString.charAt(0) == '@'){
                 sendChatMsg(coordString);
                 continue;
             }
             if(!checkRawCoords(rawCoords)){
                 System.out.println("\nInvalid selection");
                 continue;
             }
             coords = new ArrayList<>();
             for(int i = 0; i < rawCoords.length; i += 2){
                 coords.add(Integer.parseInt(rawCoords[i]) - 1);
                 coords.add(Integer.parseInt(rawCoords[i + 1]) - 1);
             }
             if(board.areCardsPickable(coords) && library.maxCardsInsertable() >= coords.size() / 2)
                 break;
             System.out.println("\nInvalid selection");
         }
         return coords;
     }
     /**
      * helper method for letting the user select the order of the cards chosen before
      * @author Ettori
      * @param coords the coordinates of the cards chosen
      * @return the list of the cards in the right order
      */
     private ArrayList<Integer> selectOrder(ArrayList<Integer> coords){
         String coordOrder = "";
         int temp_1, temp_2, index_1, index_2;
         while(true){
             printCurOrder(coords);
             if(coords.size() == 2)
                 break;
             System.out.print("\nInsert which cards to switch (-1 for exit) (or @ for chat):\n");
             try {
                 coordOrder = br.readLine();
             } catch (IOException e) {
                 continue;
             }
             if(coordOrder.length() == 0)
                 continue;
             if(coordOrder.equals("-1"))
                 break;
             if(coordOrder.charAt(0) == '@'){
                 sendChatMsg(coordOrder);
                 continue;
             }
             try {
                 index_1 = Character.getNumericValue(coordOrder.charAt(0)) - 1;
                 index_2 = Character.getNumericValue(coordOrder.charAt(2)) - 1;
             }catch (Exception e){System.out.println("\nInvalid selection"); continue;}
             if(coordOrder.length() != 3 || !isCharValid(index_1, index_2, coords.size() / 2)){
                 System.out.println("\nInvalid selection");
                 continue;
             }
             index_1 *= 2;
             index_2 *= 2;
             temp_1 = coords.get(index_1);
             temp_2 = coords.get(index_1 + 1);
             coords.set(index_1, coords.get(index_2));
             coords.set(index_1 + 1, coords.get(index_2 + 1));
             coords.set(index_2, temp_1);
             coords.set(index_2 + 1, temp_2);
         }
         return coords;
     }
     /**
      * helper method useful for getting the column chosen by the user (where tha cards will be placed)
      * @author Ettori
      * @return the column chosen by the player
      */
     private int selectColumn(int size){
         int col;
         String column = "";
         while(true){
             System.out.print("\nInsert the column where you wish to put the cards (or @ for chat):\n");
             try {
                 column = br.readLine();
             } catch (IOException e) {
                 continue;
             }
             if(column.length() == 0)
                 continue;
             if(column.charAt(0) == '@'){
                 sendChatMsg(column);
                 continue;
             }
             col = Integer.parseInt(column) - 1;
             if(library.checkCol(col, size))
                 break;
             System.out.println("\nInvalid selection");
         }
         return col;
     }
     /**
      * method that checks if some of the common objectives where achieved by the current player, and in that case points will be added
      * @author Ettori
      * @return true iff at least one objective was completed
      */
     private boolean checkCO(){
         int points, lastIndex;
         boolean change = false;
         try {
             if (board.commonObjective_1.algorithm.checkMatch(library.gameLibrary) && !CO_1_Done && board.pointsCO_1.size() > 0) { // you can't take another time the CO if you already did
                 lastIndex = board.pointsCO_1.size() - 1;
                 points = board.pointsCO_1.get(lastIndex);
                 board.pointsCO_1.remove(lastIndex);
                 pointsUntilNow += points;
                 CO_1_Done = true;
                 sendToServer(new Message(MessageType.CO_1, name, Integer.toString(points)));
                 System.out.println("\nWell done, you completed the first common objective and you gain " + points + " points...");
                 Game.waitForSeconds(Game.showTimer);
                 change = true;
             }
             if (board.commonObjective_2.algorithm.checkMatch(library.gameLibrary) && !CO_2_Done && board.pointsCO_2.size() > 0) {
                 lastIndex = board.pointsCO_2.size() - 1;
                 points = board.pointsCO_2.get(lastIndex);
                 board.pointsCO_2.remove(lastIndex);
                 pointsUntilNow += points;
                 CO_2_Done = true;
                 sendToServer(new Message(MessageType.CO_2, name, Integer.toString(points)));
                 System.out.println("\nWell done, you completed the second common objective and you gain " + points + " points...");
                 Game.waitForSeconds(Game.showTimer);
                 change = true;
             }
         }catch(Exception e){connectionLost(e);}
         return change;
     }
     /**
      * method that checks if the current player completed his library, and in that case notify all the other players (and add 1 point)
      * @author Ettori
      * @return true iff the library was completed
      */
     private boolean checkLibFull(){
         try {
             if (library.isFull() && !endGame) {
                 endGame = true;
                 pointsUntilNow++;
                 sendToServer(new Message(MessageType.LIB_FULL, name, null));
                 System.out.println("\nWell done, you are the first player to complete the library, the game will continue until the next turn of " + chairmanName + "...");
                 Game.waitForSeconds(Game.showTimer);
                 return true;
             }
         }catch (Exception e){connectionLost(e);}
         return false;
     }
     /**
      * helper method which update the board when it becomes unplayable (also notify other players)
      * @author Ettori
      */
     private void fixUnplayableBoard(){
         board.fillBoard(numPlayers);
         drawAll();
         System.out.println("\nBoard updated because it was unplayble");
         try {
             sendToServer(new Message(MessageType.UPDATE_UNPLAYABLE, name, new Board(board)));
         }catch (Exception e){connectionLost(e);}
     }
     /**
      * method that sends the last move done by the current player to all other clients (after the move is done on this player)
      * @author Ettori
      */
     private void sendDoneMove(){
         System.out.println("You made your move, now wait for other players to acknowledge it...");
         sendToServer(new Message(MessageType.UPDATE_GAME, name, new PlayerSend(this)));
         if(netMode == NetMode.SOCKET) {
             Game.waitForSeconds(Game.fastTimer);
             waitForEvents();
         }
         turnThread.interrupt();
     }
     /**
      * stops all the thread interaction related to the chat (should be only ReceiveChat)
      * @author Ettori
      */
     private void stopChatThread(){
         if(chatThread == null){
             return;
         }
         try {
             chatThread.interrupt();
         }catch (Exception e){connectionLost(e);}
     }
     /**
      * starts all the threads that listen for chat message from other clients (receiving)
       @author Ettori
      */
     private void startChatReceiveThread(){
         stopChatThread();
         chatThread = new ReceiveChat(this);
         chatThread.start();
     }
 
     /**
      * starts all the threads that listen for chat message from the user (sending)
       @author Ettori
      */
     private void startChatSendThread(){
         stopChatThread();
         chatThread = new SendChat(this, br);
         chatThread.start();
     }
     /**
      * Check if the index to switch are valid
      * @param index_1 first card
      * @param index_2 second card
      * @param size  number of switch
      * @return true if the index are valid
      * @author Ettori Faccincani
      */
     private boolean isCharValid(int index_1, int index_2, int size){
         return index_1 >= 0 && index_1 < size && index_2 > 0 && index_2 < size;
     }
     /**
      * Return to the player the current order of the cards to be placed
      * @param arr list of the cards
      * @author Ettori Faccincani
      */
     private void printCurOrder(ArrayList<Integer> arr){
         System.out.println("\nThe current order of your cards is: ");
         for(int i = 0; i < arr.size(); i += 2) {
             board.getGameBoard()[arr.get(i)][arr.get(i + 1)].draw();
             System.out.print(" ");
         }
         System.out.println();
     }
     /**
      * Send with socket network the message of the chat to the right players
      * @param msg content of the message
      * @author Ettori
      */
     public boolean sendChatMsg(String msg){
         if(msg.length() == 0)
             return false;
         if(msg.equals("@exit")){
             System.out.println("\nThe game is exiting...");
             Game.waitForSeconds(Game.fastTimer * 2);
             System.exit(0);
         }
 
 
         if(msg.charAt(0) != '@')
             return false;
         if(!msg.contains(" ")){
             if(msg.substring(1).equals("names"))
                 showAllNames();
             return false; //return false because isn't a message to other player
         }
         String dest = msg.substring(1, msg.indexOf(' '));
         msg = msg.substring(msg.indexOf(' '));
         msg = name + " says:" + msg + " (to " + dest + ") at " + new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").format(new Date()) + "\n";
 
         if(!doesPlayerExists(dest) && !dest.equals("all")) {
             System.out.println("\nThe name chosen does not exists");
             return false;
         }
         if(dest.equals(name)){
             System.out.println("\nYou can't send chat messages to yourself");
             return false;
         }
         fullChat += msg;
         try{
             sendToServer(new Message(MessageType.CHAT, dest, msg));
         }catch(Exception e){connectionLost(e);}
         return true;
     }
     /**
      * prints the name of all the players in the terminal, so that the user can choose the receiver of the chat messages
      * @author Ettori
      */
     private void showAllNames(){
         System.out.print("\nThe active players of this game are: ");
         for(Library lib : librariesOfOtherPlayers) {
             if(lib.name.equals(name))
                 continue;
             System.out.print(lib.name + " ");
         }
         System.out.println("and you");
     }
     /**
      * print the name of the active player, the 2 CO, the PO, the board, the libraries,
      * and then prints spaces before the next execution of drawAll. It also prints general (useful) information
      * @author Gumus
      */
     public void drawAll(){
         clearScreen();
         if(activeName.equals(name)){
             System.out.println("Your turn is now started, play your move !");
         }else{
             System.out.println("Now " + activeName + " is playing his turn...");
         }
         board.draw();
         System.out.println("\nThere are " + (endGame ? "0" : "1") + " points available for completing the library");
         objective.draw();
         library.draw();
         for(int i = 0; i < numPlayers - 1; i++)
             librariesOfOtherPlayers.get(i).draw("\nLibrary of " + librariesOfOtherPlayers.get(i).name + " (" + pointsMap.get(librariesOfOtherPlayers.get(i).name) + " points)");
 
         //points of CO are always even and other type of points are add at the end of the game
         if(pointsUntilNow % 2 == 1){
             System.out.println("\nYou have achieved " + (pointsUntilNow - 1) + " points from the common objectives (until now)");
             System.out.println("You also achieved 1 point for being the first player to complete the library");
         }else{
             System.out.println("\nYou have achieved " + pointsUntilNow + " points from the common objectives (until now)");
         }
         if(isChairMan)
             System.out.println("\nYou are the Chairman on this game!");
         else
             System.out.println("\nThe chairman of this game is: " + chairmanName);
         System.out.println("\nGame Chat: \n" + fullChat);
     }
     /**
      * prints 12 spaces (rows) to simulate the flush of the terminal
      * @author Gumus
      */
     private void clearScreen(){
         for(int i = 0; i < 12; i++){
             System.out.println();
         }
     }
     /**
      * function that handle the eventual disconnection
      * @param e the exception to throw
      * @author Ettori
      */
     public void connectionLost(Exception e){
         if(closed)
             return;
         closed = true;
         if(Player.showErrors)
             throw new RuntimeException(e);
         else
             System.out.println("\nThe connection was lost and the application is disconnecting...\n");
         Game.waitForSeconds(Game.waitTimer);
         System.exit(0);
     }
     /**
      * method that periodically pings the server from socket client
      * @author Ettori
      */
     public void ping(){
         while(true){
             Game.waitForSeconds(Game.waitTimer * 2);
             try {
                 outStream.writeObject(new Message(MessageType.PING, null, null));
             } catch (IOException e) {
                 connectionLost(e);
             }
         }
     }
     /**
      * method that periodically pings the server from RMI client
      * @author Ettori
      */
     public void pingRMI(){
         while(true){
             Game.waitForSeconds(Game.waitTimer * 2);
             try {
                 server.ping();
             } catch (RemoteException e) {
                 connectionLost(e);
             }
         }
     }
     /********************************************* RMI ***************************************************************/
     /**
      * method (called from remote) that is the equivalent of wait for events of the socket version
      * @param msg the message received from the server
      * @author Ettori
      */
     public void receivedEventRMI(Message msg){
         switch (msg.getType()) {
             case YOUR_TURN -> {handleYourTurnEvent(); waitForMove();}
             case CHANGE_TURN -> handleChangeTurnEvent(msg);
             case UPDATE_UNPLAYABLE -> handleUpdateUnplayableEvent(msg);
             case UPDATE_GAME -> handleUpdateGameEvent(msg);
             case FINAL_SCORE -> handleFinalScoreEvent(msg);
             case CHAT -> handleChatEvent(msg);
             case CO_1 -> handleCO_1Event(msg);
             case CO_2 -> handleCO_2Event(msg);
             case LIB_FULL -> handleLibFullEvent(msg);
             case DISCONNECTED -> handleDisconnectedEvent(msg);
             case LOST_CLIENT -> handleLostClientEvent(msg);
             case SHOW_EVENT -> handleShowEvent(msg);
         }
     }
     /**
      * general method to send a message to the server, it chooses the right network connection of the player
      * @author Ettori
      * @param msg the message that must be sent
      */
     public void sendToServer(Message msg){
 
         if(netMode == NetMode.SOCKET) {
             try {
                 outStream.writeObject(msg);
             } catch (IOException e) {
                 connectionLost(e);
             }
         }
         else{
             try {
                 server.redirectToClientRMI(msg);
             } catch (RemoteException e) {
                 connectionLost(e);
             }
         }
     }
     /**
      * method that listen for the final score of the game, for RMI clients
      * @author Ettori
      */
     private void listenForEndGame(){
         Message msg = null;
         while(true){
             try {
                 msg = (Message) inStream.readObject();
             } catch (IOException | ClassNotFoundException e) {
                 connectionLost(e);
             }
             if(msg == null)
                 connectionLost(new NullPointerException());
             if(msg.getType() != MessageType.FINAL_SCORE)
                 connectionLost(new RuntimeException("listenForEndGame method in TUI received a message different than FINAL_SCORE"));
             handleFinalScoreEvent(msg);
         }
     }
     /**
      * method that allow the server ping the RMI client
      * @author Ettori
      */
     public void pingClient(){}
 }