public class StatusActionPanel extends JPanel{

    private Icon[] mode_icons = {
        new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/player_status_ready_small.png")),
        new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/player_status_reset_small.png")),
    };

    private JButton action_button=new JButton();

    private boolean is_ready_button;

    private boolean button_mode=true;//true-> status on (ready/reset), false-> well not !

    public StatusActionPanel(boolean is_ready_button){

        this.add(action_button);

        this.is_ready_button= is_ready_button;

        if(is_ready_button){
            action_button.setText(Language.getString(31));
            action_button.setToolTipText(Language.getString(32));
            action_button.setIcon(mode_icons[0]);
        }else{
            action_button.setText(Language.getString(35));
            action_button.setToolTipText(Language.getString(36));
            action_button.setIcon(mode_icons[1]);
        }
        
        action_button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                buttonClicked();
            }
        });
    }

    //change the mode of the button
    public void setToMode(boolean button_mode){
        this.button_mode=button_mode;
        if(is_ready_button){
            if(button_mode){
                action_button.setText(Language.getString(31));
                action_button.setToolTipText(Language.getString(32));
            }else{
                action_button.setText(Language.getString(64));
                action_button.setToolTipText(Language.getString(73));
            }
        }else{
            if(button_mode){
                action_button.setText(Language.getString(35));
                action_button.setToolTipText(Language.getString(36));
            }else{
                action_button.setText(Language.getString(64));
                action_button.setToolTipText(Language.getString(65));
            }
        }
    }

    public void buttonClicked(){
        if(button_mode){
            if(is_ready_button){
                Main.connection.send(new STATUSDatagram(Status.READY).toString());
            }else{
                Main.connection.send(new STATUSDatagram(Status.RESET).toString());
            }

        }else{
            Main.connection.send(new STATUSDatagram(Status.IDLE).toString());
        }
        setToMode(!button_mode);
    }
} public class TimePanel extends JPanel{

    TimeInterpolator interpolator=null;

    JProgressBar timeProgress = new JProgressBar();
    JLabel timeLabel = new JLabel();
    
    public Icon[] clocks = {new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/clock.png")),
                            new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/clock_nb.png"))};

    private JLabel clock;
            
    public TimePanel(){
        
        timeLabel.setText("0:00");
        timeLabel.setForeground(Color.WHITE);

        timeProgress.setMaximum(200);
        timeProgress.setToolTipText(Language.getString(20));
        timeProgress.setOpaque(false);
        clock=new JLabel();
        clock.setIcon(clocks[0]);

        this.setLayout(new BorderLayout());
        this.add(clock,BorderLayout.WEST);
        this.add(timeProgress,BorderLayout.CENTER);
        this.add(timeLabel,BorderLayout.EAST);
     
        this.setOpaque(false);
    }

    /**
     * Recall the time with the one received from the server
     * @param rem remaining time
     * @param total total time
     */
    public void setServerTime(int rem,int total){
        clock.setIcon(clocks[0]);
        if(interpolator != null){
            interpolator.stopInterpolation();
        }
        interpolator=new TimeInterpolator(this,rem,total);
        interpolator.start();
    }

    /**
     * Set the time and progress
     * @param rem remaining time
     * @param total total time
     */
    void setTime(int rem,int total){
        int percent=200*rem/total;
        timeProgress.setValue(percent);
        int min = rem/60;
        int sec = rem%60;
        String time="";
        if(sec<10){
            time=min+":0"+sec;
        }else{
            time=min+":"+sec;
        }
        timeLabel.setText(time);
    }

    /**
     * Reset display by showing 0:00, stop interpolation and display a nb clock
     */
    public void resetTimer(){
        if(interpolator != null){
            interpolator.stopInterpolation();
        }
        timeLabel.setText("0:00");
        timeProgress.setValue(0);
        clock.setIcon(clocks[1]);
    }

} public class WordEntryPanel extends JPanel{

    private JTextField word_field = new JTextField();
    private String previousWord="";
    
    public WordEntryPanel(){

        this.setLayout(new BorderLayout());
       
        word_field.setFont(new Font("Serial", Font.BOLD, 30));
        word_field.setHorizontalAlignment(JTextField.CENTER);
        word_field.setToolTipText(Language.getString(23));
        word_field.addKeyListener(new java.awt.event.KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                keyPressedAction(e);
            }
        });

        //handling escape key in word field
        this.word_field.getInputMap().put(KeyStroke.getKeyStroke("ESCAPE"), "actionName");
        this.word_field.getActionMap().put("actionName", new AbstractAction("actionName") {
            public void actionPerformed(ActionEvent evt) {
                Main.mainFrame.setState(JFrame.ICONIFIED);
            }
        });
        //handling up and down key in word field
        this.word_field.getInputMap().put(KeyStroke.getKeyStroke("UP"), "up");
        this.word_field.getActionMap().put("up", new AbstractAction("up") {
            public void actionPerformed(ActionEvent evt) {
               word_field.setText(previousWord);
            }
        });
        this.word_field.getInputMap().put(KeyStroke.getKeyStroke("DOWN"), "down");
        this.word_field.getActionMap().put("down", new AbstractAction("down") {
            public void actionPerformed(ActionEvent evt) {
               if(word_field.getText().trim().equals(previousWord)){
                   word_field.setText("");
               }
            }
        });

        //this.add(mode,BorderLayout.WEST);
        this.add(word_field, BorderLayout.CENTER);


    }

    

    private void keyPressedAction(KeyEvent e){
        if(e.getModifiers()==KeyEvent.SHIFT_MASK) {
            switch(e.getKeyCode()) {
                case (KeyEvent.VK_ENTER)://set ready status
                    Main.connection.send(new STATUSDatagram(Status.READY).toString());
                    break;
                case (KeyEvent.VK_LEFT)://turn grid
                    Main.mainFrame.roomPane.boardPane.rotateGrid(false);
                    break;
                case (KeyEvent.VK_RIGHT)://turn grid
                    Main.mainFrame.roomPane.boardPane.rotateGrid(true);
                    break;
                case (KeyEvent.VK_BACK_SPACE)://set/unsey reset status
                    if(Main.mainFrame.roomPane.playersPane.getPlayerStatus(Main.connection.my_id)==Status.RESET){
                        Main.connection.send(new STATUSDatagram(Status.IDLE).toString());
                    }else{
                        Main.connection.send(new STATUSDatagram(Status.RESET).toString());
                    }
                    break;
            }
        }else{
            char t = e.getKeyChar();
            if(this.word_field.getText().length()>=2){
                Main.mainFrame.roomPane.wordStatusPane.reset();
            }
            if(t=='\n'){
                sendWord(false);
            }
        }
    }

   

    /**
     * Gives the focus to the word entry field
     */
    public void giveFocus(){
        word_field.grabFocus();
        //word_field.requestFocus();
    }

    /**
     * Add some the text at the end of the field
     * @param s
     */
    public void addText(String s){
        word_field.setText(word_field.getText()+s);
        if(word_field.getText().length()>=3){
            Main.mainFrame.roomPane.wordStatusPane.reset();
        }
    }

    public void sendWord(boolean forceWord){

        String wordToSend = word_field.getText().trim();
        previousWord = wordToSend;
        
        if(Main.connection.in_game){
            if(!forceWord && Datagram.isChatMessage(wordToSend)){
                Main.connection.send(new CHATDatagram(Datagram.replaceAccents(wordToSend)).toString());
            }else{
                // check locally if the word has not already been found
                if(Main.mainFrame.roomPane.wordsFoundPane.contains(wordToSend)){
                    Main.mainFrame.roomPane.wordStatusPane.setWord(wordToSend.toUpperCase(), Words.ALREADY_FOUND);
                }else if(wordToSend.length()<3){//check that the word is not too short (<3)
                    Main.mainFrame.roomPane.wordStatusPane.setWord(wordToSend.toUpperCase(), Words.SHORT);
                }else{//send it to server
                    Main.connection.send(new WORDDatagram(Datagram.removeAccents(wordToSend)).toString());
                }
            }
        }else{//not in game -> it's a chat message
            Main.connection.send(new CHATDatagram(Datagram.replaceAccents(wordToSend)).toString());
        }
        //reset field and dices
        Main.mainFrame.roomPane.boardPane.resetDicesStatus();
        word_field.setText("");
    }
    

} public class WordsFoundPanel extends JPanel{

    private JTextPane already_found = new JTextPane();
    private JProgressBar total_gauge = new JProgressBar();

    private JLabel rules_label=new JLabel();

    private int total_points=0;
    private int max_points=0;
    
    private Icon[] language_icons = {
        new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/fr.png")),
        new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/en.png")),
    };
   
    public WordsFoundPanel(){

        super();
        
        Font F=new Font("Serial", Font.PLAIN, 9);
        rules_label.setFont(F);
        rules_label.setVerticalAlignment(SwingConstants.CENTER);
        rules_label.setHorizontalAlignment(SwingConstants.CENTER);

        already_found.setText(" ");
        already_found.setEditable(false);
        already_found.setForeground(Color.BLACK);
        already_found.setBackground(Color.WHITE);
        already_found.setFont(new Font("Serial", Font.PLAIN, 10));
        JScrollPane alreadyFoundScrollPane = new JScrollPane(already_found);
        
        Dimension d=new Dimension(1000,10);
        total_gauge.setPreferredSize(d);
        total_gauge.setValue(0);

        setLayout(new BorderLayout());
        add(rules_label,BorderLayout.NORTH);
        add(alreadyFoundScrollPane,BorderLayout.CENTER);
        add(total_gauge,BorderLayout.SOUTH);
        
        this.setBorder(BorderFactory.createTitledBorder(""));
        this.setPreferredSize(new Dimension(100,200));
    }

    public void setMaxPoints(int max){
        max_points=max;
    }

    public void resetWordsFound(){
        already_found.setText("");
        total_points=0;
        total_gauge.setValue(0);
        total_gauge.setToolTipText("0/"+max_points);
    }

    public void addWord(String word){
        already_found.setText(" "+word.toUpperCase()+" "+already_found.getText());
        total_points+=Solver.getPoints(word,Main.connection.REWARD_BIG_WORDS);
        int pourcent=(100*total_points)/max_points;
        total_gauge.setValue(pourcent);
        total_gauge.setToolTipText(total_points+"/"+max_points);
    }

    public boolean contains(String text){
        return already_found.getText().contains(" "+text.toUpperCase()+" ");
    }

    public void setMinWordLength(int min_length){
        String s=min_length+" lettres minimum";
        rules_label.setText(s);
    }

    public void setLanguage(String lang){
        int i=0;
        if(lang.equals("fr")){
            i=0;
        }else if(lang.equals("en")){
            i=1;
        }
        rules_label.setIcon(language_icons[i]);
    }
    
    public void setGameMode(String mode){
        if(mode.equals("trad")){
            rules_label.setToolTipText(Language.getString(74));
        }else if(mode.equals("all")){
            rules_label.setToolTipText(Language.getString(14));
        }
    }
    
    public void disableAll(){
        already_found.setEnabled(false);
    }

    public void enableAll(){
        already_found.setEnabled(true);
    }
} public class ChatPanel extends JPanel{

    static int size=16;
    private int offset=0;
    JPanel center = new JPanel();

    int last_author=-1;
    OneChatPane[] list = new OneChatPane[size];
    LinkedList<ChatBlock> blockList = new LinkedList<ChatBlock>();
    int pointeur=0;//pointeur vers le block du bas

    public MainFrame root;

    public ChatPanel(){
        super();
        
        this.setLayout(new GridLayout(0,1));
        this.setBorder(BorderFactory.createTitledBorder(""));
        for(int k=size-1 ; k>=0 ; k--){
            list[k]=new OneChatPane(this);
            this.add(list[k]);
        }
        
        addMouseWheelListener(new java.awt.event.MouseWheelListener() {
            public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) {
                mouseWheelMovedAction(evt);
            }
        });
        
        setMinimumSize(new Dimension(350,10));
        setPreferredSize(new Dimension(350,10));
    }

    public void scroll(int dist){
        offset+=dist;
        if(offset>=(blockList.size()-size)){
            offset=blockList.size()-size;
        }
        if(offset<0){
            offset=0;
        }
        reAssign();
    }

    public void addServerInfo(String info){
        if(last_author==0){
            blockList.addFirst(ChatBlock.ServerBlock(info));
        }else{
            blockList.addFirst(ChatBlock.ServerBlock(info));
            last_author=0;
        }
        offset=0;
        reAssign();
    }

    public void addMessage(int id,String message){
        String name = Main.connection.players_id_name.get(id);
        String avatar = Main.connection.players_id_avatar.get(id);
        if( name != null && avatar != null){
            if(id == last_author){
                blockList.addFirst(ChatBlock.ClientBlock("", avatar, message));
            }else{
                blockList.addFirst(ChatBlock.ClientBlock(name, avatar, message));
                last_author=id;
            }
            offset=0;
            reAssign();
        }
    }

    public void disableAll(){
        for(OneChatPane p : list){
           p.disableAll();
        }
    }
    
    public void enableAll(){
        for(OneChatPane p : list){
            p.refresh();
        }
    }
    
    public void eraseAll(){
        blockList=new LinkedList<ChatBlock>();
        last_author=-1;
        pointeur=0;
        reAssign();
    }
    
    private void reAssign(){
        int i=offset;
        boolean top=false;
        boolean bottom=false;
        for(int k =0 ; k<size ;k++){
            if(k==0 && i!=0){
                bottom=true;
            }
            if(k==size-1 && offset < blockList.size()-size){
                top =true;
            }
            if(i<blockList.size()){
                list[k].setBlock(blockList.get(i),top,bottom);
            }else{
                list[k].setBlock(null,false,false);
            }
            list[k].erase();
            top=false;
            bottom=false;
            i++;
        }
        repaint();
        for(int k =0 ; k<size ;k++){
            list[k].refresh();
        }
    }

    private void mouseWheelMovedAction(java.awt.event.MouseWheelEvent evt){
        if(blockList.size()<=size){
            offset=0;
            return;
        }
        offset-=2*evt.getWheelRotation();
        if(offset>=(blockList.size()-size)){
            offset=blockList.size()-size;
        }
        if(offset<0){
            offset=0;
        }
        reAssign();
    }
} public class PlayersPanel extends JPanel {

    private JList playersList;
    private DefaultListModel playersListModel;
    
    
    private BotPanel botPane = new BotPanel();

    private Lock m=new ReentrantLock();

    public MainFrame root;

    public PlayersPanel(){
        
        playersListModel = new DefaultListModel();
        playersList = new JList(playersListModel);
        playersList.setCellRenderer(new ImageListCellRenderer());
        playersList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        playersList.setLayoutOrientation(JList.VERTICAL);
        playersList.setFixedCellHeight(40);
        playersList.setBackground(Color.WHITE);

        // put our JList in a JScrollPane
        JScrollPane playersListScrollPane = new JScrollPane(playersList);
        playersListScrollPane.setMinimumSize(new Dimension(150, 50));
        
        this.setLayout(new BorderLayout());
        this.setBorder(BorderFactory.createTitledBorder(""));
        this.setMinimumSize(new Dimension(240,2000));
        this.setPreferredSize(new Dimension(240,2000));

        JPanel listPlusBot=new JPanel(new BorderLayout());
        listPlusBot.setBackground(Color.WHITE);
        listPlusBot.add(playersListScrollPane,BorderLayout.CENTER);
        listPlusBot.add(botPane,BorderLayout.NORTH);
        this.add(listPlusBot,BorderLayout.CENTER);
    }

    /**
     * Add a player in the list
     * @param id
     * @param name
     * @param avatar
     */
    public void addPlayer(int id, String name, String avatar){
        OnePlayerPane player = new OnePlayerPane(id,name,avatar);
        m.lock();
        try{
            playersListModel.addElement(player);
        }catch (Exception ex){
            ex.printStackTrace();
        }finally{
            m.unlock();
        }
        updateBotPaneStatus();
    }

    /**
     * Remove a player from the list
     * @param id the id of the player to remove
     */
    public void removePlayer(int id){
        OnePlayerPane toRemove = getPlayer(id);
        if(toRemove != null){
            m.lock();
            try{
                playersListModel.removeElement(toRemove);
            }catch (Exception ex){
                ex.printStackTrace();
            }finally{
                m.unlock();
            }
        }
        updateBotPaneStatus();
    }

    /**
     * Remove all the players from the list
     */
    public void removeAllPlayers(){
        m.lock();
        try{
            playersListModel.removeAllElements();
        }catch (Exception ex){
            ex.printStackTrace();
        }finally{
            m.unlock();
        }
        repaint();
    }


    /**
     * Get the status of a given player
     * @param id
     * @return
     */
    public Status getPlayerStatus(int id){
        OnePlayerPane p = getPlayer(id);
        if(p!=null){
            return p.status;
        }else{
            return Status.IDLE;
        }
    }

    /**
     * Update the status of bot panel from the status of all the players of the list
     */
    public void updateBotPaneStatus(){
        int na=0;
        int nt=0;
        m.lock();
        try{
            nt=playersListModel.getSize();
            for(Enumeration e=playersListModel.elements(); e.hasMoreElements();){
                OnePlayerPane opp = (OnePlayerPane) e.nextElement();
                if(opp.status!=Status.PAUSE){
                    na++;
                }
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }finally{
           m.unlock();
        }
        if(nt<=1){
            botPane.tryToShow();
        }else if(na<=1){
            OnePlayerPane me = getPlayer(Main.connection.my_id);
            if(me!=null){
                if(me.status != Status.PAUSE){
                    botPane.tryToShow();
                }else{
                    botPane.tryToHide();
                }
            }
        }else{
            botPane.tryToHide();
        }
        repaint();
    }

    /**
     * Uupdate the status of a given player
     * @param id the id of the player
     * @param st the status of the player
     */
    public void updateStatus(int id, Status st){
        OnePlayerPane p = getPlayer(id);
        if(p!=null){
            p.updateStatus(st);
        }
        updateBotPaneStatus();
        repaint();
    }

    /**
     * Reset all the gauges of the players
     */
    public void resetAllGauges() {
        m.lock();
        try{
            for(Enumeration e=playersListModel.elements(); e.hasMoreElements() ;){
                OnePlayerPane opp = (OnePlayerPane) e.nextElement();
                opp.progress.setValue(0);
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }finally{
            m.unlock();
        }
        repaint();
    }

    /**
     * Set the gauge of a given player to the specified value
     * @param id the id of the player
     * @param value the value of the gauge (0-100)
     */
    public void setGauge(int id,int value) {
        OnePlayerPane p = getPlayer(id);
        if(p!=null){
            p.setProgress(value);
        }
        repaint();
    }

    /**
     * Set the total score of a given player to the specified value
     * @param id the id of the player
     * @param score the total score of the player
     */
    public void setTotalScore(int id,int score) {
        OnePlayerPane p = getPlayer(id);
        if(p!=null){
            p.setTotalScore(score);
        }
        repaint();
    }

    /**
     * Get the pane corresponding to a given player id
     * @param id the id of the player
     * @return the player pane
     */
    private OnePlayerPane getPlayer(int id){
        OnePlayerPane r=null;
        m.lock();
        try{
            for(Enumeration e=playersListModel.elements(); e.hasMoreElements();){
                OnePlayerPane opp = (OnePlayerPane) e.nextElement();
                if(opp.id==id){
                    r=opp;
                    break;
                }
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }finally{
            m.unlock();
        }
        return r;
    }

    /**
     * Enable all the components of the players pane
     */
    public void enableAll(){
    }

    /**
     * Disable all the components of the players pane
     */
    public void disableAll(){
        removeAllPlayers();
    }

    /**
     * Give the the number of connected players
     * @return the number of players connected
     */
    public int getNumberOfPlayers(){
        return playersListModel.size();
    }

    public int getBotLevel(){
        return botPane.getLevel();
    }
    
    public void removeBot(){
        this.botPane.switchToStartMode();
    }
} public class Language {

    static String[] tooltip_fr = new String[]{
        "Lister les serveurs sur le réseau officiel",//0
        "Lister les serveurs en réseau local",//1
    };
    static String[] tooltip_en = new String[]{
        "List servers of the official network",//0
        "List servers on the local network",//1
    };
   
    static String[] fr = new String[] {
        "Protégé par un mot de passe",//0
        "Serveur:","Port:","Connecter",//1
        "Vous devez choisir un pseudo:",//4
        "Le port doit être un entier.",//5
        "Erreur",//6
        "Connexion au serveur...",//7
        "B@ggle, connecté sur ",//8
        "J'ai lancé un serveur",//9
        "Avatar:","Pseudo:","Scan du réseau local...",//10
        "Récupération de la liste des salons...",//13
        "Tous les mots trouvés comptent",//14
        "Rejoindre une partie","Connexion manuelle",//15
        "Mode barre intelligente","Mode jeu uniquement","Mode discussion uniquement",//17
        "Temps restant à jouer pour cette partie",//20
        "Joueurs","Chat",//21
        "Saisir un mot",//23
        "(click ou Shift-Enter pour changer de mode)",//24
        "Mots trouvés",//25
        "Rechercher une définition",//26
        "Impossible de lancer un navigateur internet.",//27
        "À propos de b@ggle",//28
        "Se déconnecter de ce salon",//29
        "Impossible d'envoyer un mot, pas de partie en cours.",//30
        "Je suis prêt","Signaler au serveur que vous êtes prêt à jouer (SHIFT-Enter)",//31
        "Faire une petite pause.","Revenir dans le jeu.","Changer de grille",//33
        "Signaler au serveur que vous voulez changer de grille (SHIFT-Backspace)",//36
        "Nombre de mots que "," a trouvé par rapport au nombre total de mots trouvés",//37
        " joueurs","Entrez le mot de passe pour ce salon:",//39
        "Résultats",//41
        "Impossible de se connecter à internet.","Connexion bloquée par un proxy ou un firewall",//42
        "Choisir un salon depuis la liste",//44
        "Nom d'hôte inconnu.",//45
        "Serveur injoignable sur ce port.\n\nÊtes vous bien connectés au reseau ?\nLe serveur est il bien lancé sur le port ",//46
        " ?\nLe port est il ouvert sur le firewall de la machine serveur ?",//47
        "Numéro de port invalide.",//48
        "La partie va commencer...","Nouvelle grille !",//49
        "Impossible de se connecter à ce salon.",//51
        "La connexion avec le serveur a été perdue",//52
        "Password incorrect !",//53
        "Mot à chercher:",//54
        "Aller voir le tableau des scores","Impossible de lancer un navigateur internet, rendez-vous manuellement sur "+Main.OFFICIAL_WEBSITE+"/scores.php",//55
        "Tourner la grille dans le sens horaire (SHIFT-DROITE)","Tourner la grille dans le sens anti-horaire (SHIFT-GAUCHE)",//57
        "Modifier la taille de la grille",//59
        "Pas de réponse de la part du server principal",//60
        "inconnue",//61
        "Ajouter un robot","Deconnecter le robot",//62
        "Finalement, non !","Annuler la demande de changement de grille (SHIFT-Backspace)",//64
        "Mot valide","Le mot est trop court","Le mot n'est pas dans la grille","Le mot n'est pas dans le dictionnaire","Le mot a été filtré par le controle parental",//66
        "Me voilà !","à bientôt",//71
        "Signaler au serveur que vous n'êtes pas prêt à jouer",//73
        "Seuls les mots que je suis seul à trouver comptent",//74
        "est disponible","Aller à la page de téléchargement",//75
        "La nouvelle version peut être téléchargée sur",//77
        "Pas de partie en cours","Cliquer sur 'Je suis prêt' pour jouer",//78
        "Obtenir plus d'informations sur les règles dans ce salon","Règles",//80
        "Réseau officiel","Réseau local",//82
        "Il n'y a plus de place dans ce salon.",//84
        "Palmarès"//85,
       
    };

    static String[] en = new String[] {
        "Protected by a password",
        "Server:",
        "Port:",
        "Connect",
        "You must choose a nick:",
        "The port number must be an integer",
        "Error",
        "Connecting to server...",
        "B@ggle, connected on ",
        "I started a server",
        "Avatar:",
        "Nick:",
        "Local network auto scan...",
        "Collecting rooms list...",
        "Each word found earn points",
        "Join a game",
        "Manual connection",
        "Smart field mode",
        "Game Only Mode ",
        "Chat Only Mode",
        "Time left for this game",
        "Players",
        "Chat",
        "Enter a word",
        "(click or shift-enter to change mode)",
        "Found words",
        "Look for a definition",
        "Error while starting an internet browser",
        "About b@ggle...",
        "Disconnect from this room",
        "Unable to send word, no game running now",
        "I'm ready",
        "Notify server you're ready to play (SHIFT-Enter)",
        "Have a break",
        "Resume game",
        "Change grid",
        "Tell the server that you want to play with a new grid (SHIFT-Backspace)",
        "Number of words ",
        "has found compared to the total number of words found by all the players.",
        "players",
        "Enter a password for this room: ",
        "Results",
        "Impossible to connect to the internet",
        "Connection may be locked by a proxy or a firewall",
        "Pick a room from the list",//44
        "Unknown host name",
        "Server unreachable on this port.\n\nAre you connected to the network ?\nIs the server listenning on port ",
        "?\nIs the port opened on the firewall of the server machine ?",
        "Invalid port number",
        "The game is about to start...",
        "New grid !",
        "Impossible to connect to this room",
        "Lost server connection",
        "Wrong password !",
        "Word to find:",//54,
        "Go to the hall of fame","Error while starting an internet browser, go to "+Main.OFFICIAL_WEBSITE+"/scores.php",//55
        "Turn the grid clockwise (SHIFT-RIGHT)","Turn the grid counter-clockwise (SHIFT-LEFT)",//57
        "Modify grid size",//59
        "No response from master server",//60
        "unknown",//61
        "Connect a robot","Disconnect bot",//62
        "Well... finally, no !","Cancel grid change request (SHIFT-Backspace)",//63
        "Word accepted","This word is too short","This word is not in the grid","This word is not in the dictionnary","This word has been filtered",//66
        "Here I am !","Good bye",//71
        "Tell the server that you're not so ready to play",//73
        "Words that I'm the only one to find earn points",//74
        "is out","Go to download page",//75
        "The new version can be downloaded at",//77
        "No game in progress","Click on 'I'm ready' to play",//78
        "Know more about the rules in this room","Rules",//80
        "Official network","Local network",//82
        "Maximum number of players has been reached, try another room",//84
        "Ranking"//85
       
    };

    public static String getString(int id){
        String a="###";
        try{
            if(Main.LOCALE.equals("fr")){
                a=fr[id];
            }else if(Main.LOCALE.equals("en")){
                a=en[id];
            }
        }catch(Exception ex){
            ex.printStackTrace();
        }finally{
            return a;
        }
    }

    public static String getToolTip(int id){
        String a="###";
        try{
            if(Main.LOCALE.equals("fr")){
                a=tooltip_fr[id];
            }else if(Main.LOCALE.equals("en")){
                a=tooltip_en[id];
            }
        }catch(Exception ex){
            ex.printStackTrace();
        }finally{
            return a;
        }
    }
   
    public static String getAboutMessage(){
        String s;
        if(Main.LOCALE.equals("fr")){
            s="B@ggle version "+  Main.VERSION + "\n\n"+
            "B@ggle est un logiciel libre (license GPLv3) principalement écrit par Edouard de Labareyre.\n"+
            "- Le dictionnaire français est régulièrement mis à jour par Bernard Javerliat\n"+ 
            "- La liste des mots du filtre parental a été constituée par Ersatz.\n"+
            "- L'excellente structure de stockage du dictionnaire (DAWG) est de JohnPaul Adamovsky.\n"+
            "  http://pathcom.com/~vadco/dawg.html\n\n"+
            "Si vous ne connaissez pas les règles du jeu de boggle, il est possible de les afficher\n"+
            "une fois que vous êtes connectés à un salon de jeu.\n\n"+
            "Pour plus d'informations, visitez le site "+Main.OFFICIAL_WEBSITE;
        }else{
            s="B@ggle version "+  Main.VERSION + "\n\n"+
            "B@ggle is a free software (GPLv3 license) mainly developed by Edouard de Labareyre.\n"+
            "- The french dictionnary is continuously updated by Bernard Javerliat\n"+  
            "- The list of french words for parental filter has been made by Ersatz.\n"+ 
            "- The awesome storage structure for dictionnary (DAWG) is from JohnPaul Adamovsky.\n"+
            "  http://pathcom.com/~vadco/dawg.html\n\n"+
            "If you don't know boggle rules, you can display them when you are connected to a room.\n\n"+
            "For more information you can visit the website at "+Main.OFFICIAL_WEBSITE;
        }
        return s;
    }
   
    public static String[] getRules(){
       
        String[] rules = new String[11];
       
        if(Main.LOCALE.equals("fr")){
            rules[0]= "Règles génériques";
            rules[1]="Le but du boggle est de former des mots à partir des lettres "+
              "de la grille, sachant que les lettres doivent se toucher (sur le coté ou en diagonale).\n"+
              "Les mots doivent être dans le dictionnaire, mais peuvent être mis au pluriel, "+
              "conjugués, accordés en genre et en nombre...";
            rules[2]="Exemple: on peut trouver le mot TRIA dans cette grille (du verbe trier).";
            rules[3]="Attention, un même dé ne peut pas être utilisé pour un mot donné.";
            rules[4]="Exemple: on peut former le mot SERRA (du verbe serrer), mais pas PAVA !";
            rules[5]="Règles spécifiques à ce salon";
            rules[6]="Dans ce salon c'est la règle officielle qui s'applique. Ainsi ne rapportent "+
                    "des points que les mots qu'un joueur est le seul à trouver. ";
            rules[7]="Dans ce salon, la règle qui s'applique est un dérivé de la règle officielle. Tous "+
                    "les mots comptent, sachant que plus ils sont longs plus ils rapportent de points. ";
            rules[8]="Les mots doivent comporter au minimum ";
            rules[9]=" lettres pour être acceptés. ";
            rules[10]="En cas de problème n'hésitez pas à demander de l'aide via le chat !";
        }else{
            rules[0]= "Generic rules";
            rules[1]="The purpose of boggle is to form words from the letters of the grid,\n"+
                     "knowing that the letters must touch (on the side or diagonally)."+
                     "Words must be in the dictionary, but may be plural, conjugated\n"+
                     "granted in gender and number...";
            rules[2]="Example: you can find the word CORE in this grid.";
            rules[3]="Note that a dice cannot be used twice in the same word.";
            rules[4]="Example: you cannot find the word CANCEL in this grid because C cannot be used twice !";
            rules[5]="Specific rules for this room";
            rules[6]="In this room the official boggle rule is used. It means that you have to be the only"+
                     "player who finds a word in order to earn points with this word.";
            rules[7]="In this room, the rule is a derivate from the official rule. All the words "+
                     "count, and the longer they are, the more points you win. ";
            rules[8]="Words shall contain at least ";
            rules[9]=" letters to be valid. ";
            rules[10]="If you have troubles to play, feel free to ask fro help in the chat !";
        }
       
        return rules;
    }
   
} public class BoardPanel extends JComponent{

    
    //internal constants, rebuilt only on board resize
    int board_size;
    int component_width;
    int component_height;
    int dices_size=0;
    int dice_width;
    int x0,xf,y0,yf;
    int X0,Y0;
    int board_margin;
    int radius_pow2;
    
    boolean dimensions_init=false;

    private final static int border_ratio=5;//pourcentage de la taille de la bordure par rapport à la taille totale
    private final static int i=1;//taille inter-dé
    
    boolean surlign=false;
    int rotation=0;
    int zone=0;
    static int sb=8;
    static int style=Font.BOLD;
    
    int SIZE = 4;
    gDe[][] des=new gDe[SIZE][SIZE];
    
    int select_mode = 0;//0->idle, 1->start,2->incertain,3->click,4->drag
    boolean resizing=false;
    boolean vertical_resize;
    int[] previous_dice={-1,-1};
    int offset_x_mem, offset_y_mem;
    
    Color boardColor = ColorFactory.BROWN_BOARD;//0->marron, 1-> bleu , 2-> vert
    
    private Image[] icons = new Image[3];

    public BoardPanel(){
        this.board_size = Main.configuration.BOARD_WIDTH;
        setSize(400, 200);
        
        try{
            icons[0] = ImageIO.read(getClass().getResource("/inouire/baggle/client/icons/resize.png"));
            icons[1] = ImageIO.read(getClass().getResource("/inouire/baggle/client/icons/turn_counterclockwise.png"));
            icons[2] = ImageIO.read(getClass().getResource("/inouire/baggle/client/icons/turn_clockwise.png"));
        }catch(IOException ioe){
            SimpleLog.logger.warn("Impossible to load rotate and resize icons on grid");
        }
        
        des=new gDe[SIZE][SIZE];
        for(int k=0;k<SIZE;k++){
            for(int l=0;l<SIZE;l++){
                des[k][l]=new gDe(0, 0,"-",0);
            }
        }
        
        this.addMouseListener(new MouseListener() {
            @Override
            public void mouseClicked(MouseEvent arg0) {
                mouseClickedAction(arg0);
            }

            @Override
            public void mousePressed(MouseEvent arg0) {
                mousePressedAction(arg0);
            }

            @Override
            public void mouseReleased(MouseEvent arg0) {
                mouseReleasedAction(arg0);
            }

            @Override
            public void mouseEntered(MouseEvent arg0) {
                //do nothing
            }

            @Override
            public void mouseExited(MouseEvent arg0) {
                zone=0;
                setCursor(Cursor.getDefaultCursor());
            }
        });
        
        this.addMouseMotionListener(new MouseMotionListener() {
            @Override
            public void mouseDragged(MouseEvent arg0) {
                mouseDraggedAction(arg0);
            }

            @Override
            public void mouseMoved(MouseEvent arg0) {
                mouseMovedAction(arg0);
            }
        });
    }
                
    public void updateConstants(int new_board_size){
        updateConstants(new_board_size, this.getWidth(), this.getHeight());
    }
    
    public void updateConstants(int new_component_width, int new_component_height){
        updateConstants(this.board_size, new_component_width, new_component_height);
    }
    
    public void updateConstants(int new_board_size,int new_component_width, int new_component_height){
        
        int component_size = Math.min(new_component_width, new_component_height);
        board_size = Value.bound(new_board_size, 75, component_size - 30);
        component_width = new_component_width;
        component_height = new_component_height;
        
        X0 = (this.component_width  - board_size)/2;
        Y0 = (this.component_height - board_size)/2;
        
        board_margin = board_size * border_ratio / 100;
        
        x0 = X0 + board_margin;
        y0 = Y0 + board_margin;
        xf = X0 + board_size - board_margin;
        yf = Y0 + board_size - board_margin;
        
        dices_size = xf - x0;
        dice_width = (board_size-2*board_margin-(SIZE-1)*i)/SIZE;
        
        int radius_ratio=75;
        radius_pow2 = (int) Math.pow(radius_ratio * dice_width / 200,2);
        
        gDe.updateConstants(dice_width);
    }
    
    private int[] discretizePoint(int x, int y){
        //check that we are in the grid zone
        if( x>xf || x < x0 || y > yf || y < y0){
            return null;
        }
        //get grid coordinate
        int ix = SIZE * (x - x0)/dices_size;
        int jy = SIZE * (y - y0)/dices_size;

        return new int[]{ix,jy};
    }
    
    private int[] roundDiscretizePoint(int x, int y){
        
        // get discrete reference
        int[] ref = discretizePoint(x, y);
        
        if(ref!=null){
            // compute corresponding coordinates
            int xref = x0 + ref[0] * dice_width + dice_width/2;
            int yref = y0 + ref[1] * dice_width + dice_width/2;

            // compute distante^2 between ref and actual point
            int distance_2 = (int)(Math.pow(x-xref,2) + Math.pow(y-yref,2));

            // check that distance is lower than radius
            if(distance_2 < radius_pow2){
                return ref;
            }
        }
        return null;
    }
        
    /*
     * Change the size of the board between big or normal board
     */
    public void setBigBoard(boolean bigBoard){
        if(bigBoard){
            SIZE=5;
        }else{
            SIZE=4;
        }
        des=new gDe[SIZE][SIZE];
        for(int k=0;k<SIZE;k++){
            for(int l=0;l<SIZE;l++){
                des[k][l]=new gDe(0, 0,"-",0);
            }
        }
        updateConstants(board_size);
    }

    /**
     * Action when a click is detected on board
     * @param arg0 
     */
    private void mouseClickedAction(MouseEvent arg0){
        if(zone==2){ 
            rotateGrid(false);
        }else if(zone==3){
            rotateGrid(true);
        }
        Main.mainFrame.roomPane.wordEntryPane.giveFocus();
    }
    
    /**
     * Action when mouse is pressed
     * @param arg0 
     */
    private void mousePressedAction(MouseEvent arg0){
        
        int x = arg0.getX();
        int y = arg0.getY();
        
        if(zone==1){//resize button
            offset_x_mem = x - X0-board_size;
            offset_y_mem = y - Y0-board_size;
            resizing=true;
            int a = Math.abs(x-(component_width/2));
            if(a<(board_size/2)-2){
                vertical_resize=true;
            }else{
                vertical_resize=false;
            }
        }else if(zone==4 && Main.connection.in_game && select_mode==0){//on a dice
            this.select_mode=1;//start mode: we don't know which type of selection yet
            
            int[] coord = discretizePoint(x, y);
            if(coord == null){
                return;
            }
            int k = coord[0];
            int l = coord[1];
            
            //Set the dice as selected, and all the dices around as highlighted
            des[k][l].setSelected();
            for(int m=0 ; m<SIZE ; m++){
                for(int n=0;n<SIZE;n++){
                    if(m<=k+1 && m>=k-1 && n<=l+1 && n>=l-1){
                       des[m][n].setHighlighted();
                    }
                }
            }
            previous_dice[0]=k;
            previous_dice[1]=l;
            Main.mainFrame.roomPane.wordEntryPane.addText(""+Main.connection.grid.charAt(SIZE*l+k));
            repaint();
        }
    }
    
    /**
     * Action when mouse boutton is released on the grid
     * @param arg0 
     */
    private void mouseReleasedAction(MouseEvent arg0){
        if(resizing){//if we were in rezise of the grid, stop resizing
            resizing=false;
        }else if(select_mode==1 || select_mode==2){//we were in start mode or uncertain mode, now we know that we should go in click mode
            select_mode=3;//click mode
        }else if(select_mode==3 || select_mode==4){
            select_mode=0;//go back to idle mode
            Main.mainFrame.roomPane.wordEntryPane.sendWord(true);//send word
            resetDicesStatus();
        }
        repaint();
    }
   
    /**
     * Action when mouse is dragged
     * @param arg0 
     */
    private void mouseDraggedAction(MouseEvent arg0){
        int x = arg0.getX();
        int y = arg0.getY();
        if(resizing){//if we are resizing the grid
            int new_board_size;
            if(vertical_resize){
                new_board_size=Math.abs(2*(y-(component_height/2)))-offset_y_mem;
            }else{
                new_board_size=Math.abs(2*(x-(component_width/2)))-offset_x_mem;
            }
            updateConstants(new_board_size);
            repaint();
        }else if(select_mode==1 || select_mode==2 || select_mode==4){

            int[] coord = roundDiscretizePoint(x, y);
            if(coord == null){
                return;
            }
            int k = coord[0];
            int l = coord[1];

            if(trackDiceChanging(k,l)){
                des[k][l].setSelected();
                des[k][l].setConnector(gDe.computeConnector(previous_dice[0],previous_dice[1],k,l));
                for(int m=0;m<SIZE;m++){
                    for(int n=0;n<SIZE;n++){
                       des[m][n].setUnhighlighted();
                    }
                }
                for(int m=0;m<SIZE;m++){
                    for(int n=0;n<SIZE;n++){
                        if(m<=k+1 && m>=k-1 && n<=l+1 && n>=l-1){
                           des[m][n].setHighlighted();
                        }
                    }
                }
                previous_dice[0]=k;
                previous_dice[1]=l;
                Main.mainFrame.roomPane.wordEntryPane.addText(""+Main.connection.grid.charAt(SIZE*l+k));
                repaint();
                if(select_mode==1){
                    select_mode=2;
                }else if(select_mode==2){
                    select_mode=4;
                }else if(select_mode==4){
                    //do nothing
                }
            }
        }
    }
    
    /**
     * Action when mouse is moved
     * @param arg0 
     */
    private void mouseMovedAction(MouseEvent arg0){

        int x = arg0.getX();
        int y = arg0.getY();
        
        //track the zone where the pointer is
        if(!resizing){
            zone = getZone(x,y);
            if(zone==4){
                zone=4;//on one of the square
                setToolTipText(null);
            }else if(zone==1){
                setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) );
                setToolTipText(Language.getString(59));
            }else if(zone==2){
                setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) );
                setToolTipText(Language.getString(58));//turn grid
            }else if(zone==3){
                setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) );
                setToolTipText(Language.getString(57));//turn grid
            }else{
                setCursor(Cursor.getDefaultCursor());
                setToolTipText(null);
                repaint();
            }
        }
        if(select_mode==3){//we are in click mode, track a dice changing
            
            int[] coord = roundDiscretizePoint(x, y);
            if(coord == null){
                return;
            }
            int k = coord[0];
            int l = coord[1];

            if(trackDiceChanging(k,l)){
                des[k][l].setSelected();
                des[k][l].setConnector(gDe.computeConnector(previous_dice[0],previous_dice[1],k,l));
                for(int m=0;m<SIZE;m++){
                    for(int n=0;n<SIZE;n++){
                       des[m][n].setUnhighlighted();
                    }
                }
                for(int m=0;m<SIZE;m++){
                    for(int n=0;n<SIZE;n++){
                        if(m<=k+1 && m>=k-1 && n<=l+1 && n>=l-1){
                           des[m][n].setHighlighted();
                        }
                    }
                }
                previous_dice[0]=k;
                previous_dice[1]=l;
                Main.mainFrame.roomPane.wordEntryPane.addText(""+Main.connection.grid.charAt(SIZE*l+k));
                repaint();
            }
        }
    }
        
    private boolean trackDiceChanging(int k, int l){
        if(previous_dice[0]!=k || previous_dice[1]!=l){
            if(k>=SIZE || k<0 || l>=SIZE || l<0){
                return false;
            }
            if(des[k][l].state!=2){
                return false;
            }
            return true;
        }else{
            return false;
        }
    }
    
    private int getZone(int x, int y){
        int Z;
        if(inZone(x, y, x0, y0, xf, yf)){
            Z=4;//on one of the square
            setToolTipText(null);
        }else if(inZone(x,y,
                        X0+board_size, Y0+board_size,
                        X0+board_size+16, Y0+board_size+16)){
            Z=1;
            setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) );
            setToolTipText(Language.getString(59));
        }else if(inZone(x,y,
                        X0-15, Y0-10,
                        X0+4, Y0+6)){
            setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) );
            setToolTipText(Language.getString(58));//turn grid
            Z=2;
        }else if(inZone(x, y,
                        X0+board_size-3, Y0-10,
                        X0+board_size+16, Y0+6)){
            setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) );
            setToolTipText(Language.getString(57));//turn grid
            Z=3;
        }else{
            Z=0;
            setCursor(Cursor.getDefaultCursor());
            setToolTipText(null);
            repaint();
        }
        return Z;
    }
    
    public void setBoardColor(Color board_color){
        boardColor=board_color;
        repaint();
    }
        
    /**
     * Makes the grid rotate, clockwise or counter clockwise
     * @param clockwise
     */
    public void rotateGrid(final boolean clockwise){
        Thread s = new Thread() {
            @Override
            public void run() {
                try {
                    if(clockwise){
                        for(int k=0;k<90;k+=10){
                            rotation=k;
                            repaint();
                            sleep(30);
                        }
                    }else{
                        for(int k=0;k>-90;k-=10){
                            rotation=k;
                            repaint();
                            sleep(30);
                        }
                    }
                    rotation = 0;
                    repaint();
                } catch (InterruptedException ex) {
                    SimpleLog.logger.warn("Error while rotating grid");
                }finally{
                    turnGrid(clockwise);
                    repaint();
                }
            }
        };
        s.start();
    }

    /**
     * Reset the status of all dices (selected, disable...)
     */
    public void resetDicesStatus(){
        for(int k=0;k<SIZE;k++){
            for(int l=0;l<SIZE;l++){
                des[k][l].resetStatus();
            }
        }
        select_mode=0;
        repaint();
    }

    public void disableAll() {
        for(int k=0;k<SIZE;k++){
            for(int l=0;l<SIZE;l++){
                des[k][l].setDisabled();
            }
        }
        repaint();
    }

    public void enableAll(){
        resetDicesStatus();
        repaint();
    }

    private boolean inZone(int x,int y,int A,int B,int C,int D){
        if( x>= A && x <= C && y >= B && y<= D){
            return true;
        }else{
            return false;
        }
    }

    public void turnGrid(boolean clockwise){
        
        int [][] bkp= new int[SIZE][SIZE];
        
        for(int k=0;k<SIZE;k++){
           for(int l=0;l<SIZE;l++){
               bkp[k][l]=this.des[k][l].state;
           }
        }
        
        int next_at_x_is_now_at,next_at_y_is_now_at;
        String new_grid_string="";
            
        for(int y=0;y<SIZE;y++){
            for(int x=0;x<SIZE;x++){
                if(clockwise){
                    next_at_x_is_now_at=y;
                    next_at_y_is_now_at=SIZE-1-x;
                }else{
                   next_at_x_is_now_at=SIZE-1-y;
                   next_at_y_is_now_at=x;
                }
               
                new_grid_string+=Main.connection.grid.charAt( SIZE*next_at_y_is_now_at + next_at_x_is_now_at );
                des[x][y].state=bkp[next_at_x_is_now_at][next_at_y_is_now_at];
            }
        }

        Main.connection.grid = new_grid_string;
        Main.mainFrame.roomPane.refreshCenter();
    }

    public void animateShuffle(){
        Thread s = new Thread() {
            @Override
            public void run() {
                try {
                    for(int k=0;k<180;k+=10){
                        rotation=k;
                        repaint();
                        sleep(20);
                    }
                    rotation = 0;
                    repaint();
                } catch (InterruptedException ex) {
                }finally{
                    repaint();
                }
            }
        };
        s.start();
    }
    
    @Override
    public void paintComponent(Graphics g) {
        
        int actual_width  = this.getWidth();
        int actual_height = this.getHeight();
        
        // check first init
        if(!dimensions_init){
            updateConstants(board_size, actual_width, actual_height);
            dimensions_init = true;
        }

        // check if component size has changed
        if( actual_width != component_width || actual_height != component_height){
            updateConstants(actual_width, actual_height);
        }
                
        // init graphical component
        Graphics2D g2 = (Graphics2D)g;
        RenderingHints rh = new RenderingHints(
        RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setRenderingHints(rh);
        super.paintComponent(g);

        // handle rotation cases
        if(rotation!=0){
            AffineTransform saveXform = g2.getTransform();
            AffineTransform AA = new AffineTransform();
            AA.rotate(Math.toRadians(rotation), X0+(board_size/2), Y0+(board_size/2));
            g2.transform(AA);
            g2.setColor(boardColor);
            g2.fillRect(X0, Y0, board_size,board_size);
            int d=(board_size-2*board_margin-(SIZE-1)*i)/SIZE;
            for(int k=0;k<SIZE;k++){
                for(int l=0;l<SIZE;l++){
                    if(!resizing){
                        des[k][l].reAssign(X0+board_margin+k*(d+i),Y0+board_margin+l*(d+i),"",0);
                        des[k][l].paintDe(g);
                    }
                }
            }
            g2.transform(saveXform);
            return;
        }
        
        // paint board
        g.setColor(boardColor);
        g.fillRect(X0, Y0, board_size,board_size);
        
        //compute font size
        // TODO do it in update constants
        int m=10;
        int d=(board_size-2*board_margin-(SIZE-1)*i)/SIZE;
        int target=d;
        Font F=new Font("Serial", style, m);
        while(g.getFontMetrics(F).getHeight()<target){
            m+=1;
            F=new Font("Serial", style, m);
        }

        // draw dices
        String grid = Main.connection.grid;
        for(int k=0;k<SIZE;k++){
            for(int l=0;l<SIZE;l++){
                if(!resizing){
                    des[k][l].reAssign(X0+board_margin+k*(d+i),Y0+board_margin+l*(d+i),grid.charAt(SIZE*l+k)+"",m);
                    des[k][l].paintDe(g);
                }
            }
        }
        for(int k=0;k<SIZE;k++){
            for(int l=0;l<SIZE;l++){
                if(!resizing){
                    des[k][l].paintConnector(g);
                }
            }
        }

        //draw icons
        g.drawImage(icons[0], X0+board_size, Y0+board_size, null);
        g.drawImage(icons[1], X0-15, Y0-10, null);
        g.drawImage(icons[2], X0+board_size-3, Y0-10, null);

    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(400,400);
    }
    
    public int getBoardSize(){
        return board_size;
    }
} public class ResultsPanel extends JPanel{

    private MiniBoardPanel miniboard = new MiniBoardPanel();
    private PodiumPanel podium = new PodiumPanel();
    private PlayersResultsPanel all_results = new PlayersResultsPanel(false);

    private String grid;
    
    public ResultsPanel(StatusActionPanel sap){
        this.setLayout(new BorderLayout());

        JButton display_all_button = new JButton("Toutes les solutions");
        display_all_button.setIcon(new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/star_small.png")));
        
        JPanel grid_panel = new JPanel(new BorderLayout());
        grid_panel.add(miniboard,BorderLayout.CENTER);
        grid_panel.add(display_all_button,BorderLayout.NORTH);
        
        JPanel top = new JPanel(new BorderLayout());
        top.add(podium,BorderLayout.CENTER);
        top.add(grid_panel,BorderLayout.EAST);

        this.add(top,BorderLayout.NORTH);
        this.add(all_results,BorderLayout.CENTER);
        this.add(sap,BorderLayout.SOUTH);
        
        all_results.addComponentListener(new ComponentListener() {
            @Override
            public void componentResized(ComponentEvent e) {
                all_results.notifyResize();
            }
            @Override
            public void componentMoved(ComponentEvent e) {}

            @Override
            public void componentShown(ComponentEvent e) {}

            @Override
            public void componentHidden(ComponentEvent e) {}
        });
        
        display_all_button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                allSolutionsClicked();
            }
        });

    }

    public void clearResults(){
        all_results.clearResults();
        all_results.notifyResize();
        podium.resetPodium();
    }
    
    public void addResult(RESULTDatagram resultD){
        int score=resultD.score;
        String name=Main.connection.players_id_name.get(resultD.id);
        
        //add the player to the podium if needed
        if(resultD.rank!=null){
            podium.setPlayer(resultD.rank,name,score);
        }
        
        //add the player to the overall table
        all_results.addResult(name,score, resultD.words);
    }
    
   
    public void setGrid(String grid){
        this.grid=grid;
        miniboard.updateGrid(grid);
    }
    
    
    public void allSolutionsClicked() {
        try{
            SolutionsFrame solutions = new SolutionsFrame(grid);
            solutions.setVisible(true);
        }catch(Exception ex){
            //display error message: impossible to load dictionnary
        }
    }

} public class RulesPane extends JPanel{

    private JTextPane specificRulesPane;
    private JButton exitButton;
    
    public RulesPane(){
        
        String[] rules = Language.getRules();
                
        Font title_font = new Font("Serial", Font.BOLD, 14);
        
        Insets marge = new Insets(2,2,2,2);
        
        //prepare gui elements
        
        JLabel general_rules_title = new JLabel(rules[0]);
        general_rules_title.setFont(title_font);
        general_rules_title.setForeground(ColorFactory.RED_BOARD);
        
        JTextPane general_rules_text = new JTextPane();
        general_rules_text.setText(rules[1]);
        general_rules_text.setEditable(false);
        general_rules_text.setOpaque(false);
        
        JLabel example_1_image = new JLabel();
        if(Main.LOCALE.equals("fr")){
            example_1_image.setIcon(new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/regle_exemple1.png")));
        }else{
            example_1_image.setIcon(new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/rule_example1.png")));
        }
        
        
        JTextPane example_1_text =  new JTextPane();
        example_1_text.setText(rules[2]);
        example_1_text.setEditable(false);
        example_1_text.setOpaque(false);
        
        JTextPane dice_rules_text = new JTextPane();
        dice_rules_text.setText(rules[3]);
        dice_rules_text.setEditable(false);
        dice_rules_text.setOpaque(false);
        
        JLabel example_2_image = new JLabel();
        if(Main.LOCALE.equals("fr")){
            example_2_image.setIcon(new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/regle_exemple2.png")));
        }else{
            example_2_image.setIcon(new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/rule_example2.png")));
        }
        
        JTextPane example_2_text = new JTextPane();
        example_2_text.setText(rules[4]);
        example_2_text.setEditable(false);
        example_2_text.setOpaque(false);
        
        JLabel specific_rules_title = new JLabel(rules[5]);
        specific_rules_title.setFont(title_font);
        specific_rules_title.setForeground(ColorFactory.RED_BOARD);
        
        specificRulesPane  = new JTextPane();
        specificRulesPane.setEditable(false);
        specificRulesPane.setOpaque(false);
        
        exitButton=new JButton();
        exitButton.setText("Revenir au jeu");
        exitButton.setIcon(new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/player_status_ready_small.png")));
        exitButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                Main.mainFrame.roomPane.showPrevious();
            }
        });
        
        this.setLayout(new GridBagLayout());
        
        GridBagConstraints g = new GridBagConstraints();
        
        g.gridx=0;
        g.gridy=0;
        g.gridwidth=GridBagConstraints.REMAINDER;
        g.gridheight=1;
        g.fill=GridBagConstraints.NONE;
        g.anchor=GridBagConstraints.LINE_START;
        g.weightx=0;
        g.weighty=0;
        g.insets=marge;
        this.add(general_rules_title,g);
        
        g.gridx=0;
        g.gridy=1;
        g.gridwidth=GridBagConstraints.REMAINDER;
        g.gridheight=1;
        g.fill=GridBagConstraints.BOTH;
        g.anchor=GridBagConstraints.NORTH;
        g.weightx=1;
        g.weighty=0;
        g.insets=marge;
        this.add(general_rules_text,g);
        
        g.gridx=0;
        g.gridy=2;
        g.gridwidth=1;
        g.gridheight=1;
        g.fill=GridBagConstraints.NONE;
        g.anchor=GridBagConstraints.CENTER;
        g.weightx=0;
        g.weighty=0;
        g.insets=marge;
        this.add(example_1_image,g);
        g.gridx=1;
        g.gridy=2;
        g.gridwidth=GridBagConstraints.REMAINDER;
        g.gridheight=1;
        g.fill=GridBagConstraints.HORIZONTAL;
        g.anchor=GridBagConstraints.WEST;
        g.weightx=0;
        g.weighty=0;
        g.insets=marge;
        this.add(example_1_text,g);
        
        g.gridx=0;
        g.gridy=3;
        g.gridwidth=GridBagConstraints.REMAINDER;
        g.gridheight=1;
        g.fill=GridBagConstraints.HORIZONTAL;
        g.anchor=GridBagConstraints.CENTER;
        g.weightx=0;
        g.weighty=0;
        g.insets=marge;
        this.add(dice_rules_text,g);
        
        g.gridx=0;
        g.gridy=4;
        g.gridwidth=1;
        g.gridheight=1;
        g.fill=GridBagConstraints.NONE;
        g.anchor=GridBagConstraints.CENTER;
        g.weightx=0;
        g.weighty=0;
        g.insets=marge;
        this.add(example_2_image,g);
        g.gridx=1;
        g.gridy=4;
        g.gridwidth=GridBagConstraints.REMAINDER;
        g.gridheight=1;
        g.fill=GridBagConstraints.HORIZONTAL;
        g.anchor=GridBagConstraints.LINE_START;
        g.weightx=0;
        g.weighty=0;
        g.insets=marge;
        this.add(example_2_text,g);
        
        g.gridx=0;
        g.gridy=5;
        g.gridwidth=GridBagConstraints.REMAINDER;
        g.gridheight=1;
        g.fill=GridBagConstraints.NONE;
        g.anchor=GridBagConstraints.LINE_START;
        g.weightx=0;
        g.weighty=0;
        g.insets=marge;
        this.add(specific_rules_title,g);
        
        g.gridx=0;
        g.gridy=6;
        g.gridwidth=GridBagConstraints.REMAINDER;
        g.gridheight=1;
        g.fill=GridBagConstraints.HORIZONTAL;
        g.anchor=GridBagConstraints.NORTH;
        g.weightx=0;
        g.weighty=0;
        g.insets=marge;
        this.add(specificRulesPane,g);

        g.gridx=0;
        g.gridy=7;
        g.gridwidth=GridBagConstraints.REMAINDER;
        g.gridheight=1;
        g.fill=GridBagConstraints.NONE;
        g.anchor=GridBagConstraints.CENTER;
        g.weightx=0;
        g.weighty=1;
        g.insets=marge;
        this.add(exitButton,g);
                
    }
    
    public void updateRules(ACCEPTDatagram acceptD){
        
        String specific="";
        String[] rules = Language.getRules();
        
        //mode de jeu
        if(acceptD.mode.equals("trad")){
            specific+=rules[6];
        }else{
            specific+=rules[7];
        }
        
        //nombre de lettres
        specific+=rules[8]+acceptD.min+rules[9];
        
        specificRulesPane.setText(specific);
    }

} public class TopBarPanel extends JPanel {
    
    private JButton logout_button = new JButton();
    private JButton rules_button = new JButton();
    
    private JButton scores_button = new JButton();
    
    private JTextField search_field = new JTextField();
    public TimePanel time_pane = new TimePanel();
    
   
    public TopBarPanel(TimePanel time_pane) {
        super();
                       
        search_field.setOpaque(true);
        search_field.addKeyListener(new KeyListener() {
            public void keyTyped(KeyEvent ke) {
                if(ke.getKeyChar()=='\n'){
                    searchWordAction();
                }
            }
            public void keyPressed(KeyEvent ke) {}
            public void keyReleased(KeyEvent ke) {}
        });
        
        JLabel search_label = new JLabel();
        search_label.setIcon(new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/search.png")));
        search_label.addMouseListener(new MouseListener() {
            public void mouseClicked(MouseEvent me) {
                searchWordAction();
            }
            public void mousePressed(MouseEvent me) {}

            public void mouseReleased(MouseEvent me) {}

            public void mouseEntered(MouseEvent me) {}

            public void mouseExited(MouseEvent me) {}
        });
        JPanel search_panel = new JPanel(new BorderLayout());
        search_panel.setOpaque(false);
        search_panel.setPreferredSize(new Dimension(120,32));
        search_panel.setMinimumSize(new Dimension(80,32));
        search_panel.add(search_label,BorderLayout.WEST);
        search_panel.add(search_field,BorderLayout.CENTER);
        
        this.time_pane=time_pane;
        time_pane.setPreferredSize(new Dimension(300,32));
        time_pane.setMinimumSize(new Dimension(200,32));
        
        logout_button.setIcon(new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/back.png")));
        logout_button.setToolTipText(Language.getString(29));
        logout_button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                logoutAction();
            }
        });
        
        rules_button.setIcon(new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/info_small.png")));
        rules_button.setText(Language.getString(81));
        rules_button.setToolTipText(Language.getString(80));
        rules_button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                rulesAction();
            }
        });
        
        scores_button.setIcon(new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/medal.png")));
        scores_button.setToolTipText(Language.getString(55));
        scores_button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                scoresAction();
            }
        });
        
        this.setLayout(new GridBagLayout());
        this.setBackground(ColorFactory.BLUE_BOARD);
        
        GridBagConstraints g = new GridBagConstraints();
        
        g.gridx=0;
        g.gridy=0;
        g.gridwidth=1;
        g.gridheight=1;
        g.fill=GridBagConstraints.NONE;
        g.anchor=GridBagConstraints.LINE_START;
        g.weightx=0;
        g.insets=new Insets(8, 5,8,5);
        this.add(logout_button,g);
        
        g.gridx=1;
        g.gridy=0;
        g.gridwidth=1;
        g.gridheight=1;
        g.fill=GridBagConstraints.NONE;
        g.anchor=GridBagConstraints.LINE_START;
        g.weightx=0;
        g.insets=new Insets(8, 5,8,5);
        this.add(rules_button,g);
        
        g.gridx=2;
        g.gridy=0;
        g.gridwidth=1;
        g.gridheight=1;
        g.fill=GridBagConstraints.NONE;
        g.anchor=GridBagConstraints.CENTER;
        g.weightx=1;
        g.insets=new Insets(8, 5,8,5);
        this.add(time_pane,g);
        
        g.gridx=3;
        g.gridy=0;
        g.gridwidth=1;
        g.gridheight=1;
        g.fill=GridBagConstraints.NONE;
        g.anchor=GridBagConstraints.LINE_END;
        g.weightx=0;
        g.insets=new Insets(8, 5,8,5);
        this.add(search_panel,g);
        
        g.gridx=4;
        g.gridy=0;
        g.gridwidth=GridBagConstraints.REMAINDER;
        g.gridheight=1;
        g.fill=GridBagConstraints.NONE;
        g.anchor=GridBagConstraints.LINE_START;
        g.weightx=0;
        g.insets=new Insets(8, 5,8,5);
        this.add(scores_button,g);
        
    }
    
    private void logoutAction(){
        Main.mainFrame.leaveRoom();
    }

    private void rulesAction(){
        Main.mainFrame.roomPane.toggleRules();
    }
        
    private void searchWordAction(){
        String word = search_field.getText().trim().toLowerCase();
        if(word!=null && word.length() !=0){
            try {
                Desktop.getDesktop().browse(new URI("http://"+Main.connection.LANG+".wiktionary.org/wiki/"+word.toLowerCase()));
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(Main.mainFrame,Language.getString(27));
            }
        }
        Main.mainFrame.roomPane.wordEntryPane.giveFocus();
    }
    
    private void scoresAction(){
        try {
            Desktop.getDesktop().browse(new URI(Main.OFFICIAL_WEBSITE+"/scores.php"));
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(Main.mainFrame,Language.getString(27));
        }
    }
} public class WordStatusPanel extends JPanel{

    private JLabel word_status=new JLabel();

    private Icon[] word_status_icons = {
        new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/word_good.png")),
        new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/word_already_found.png")),
        new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/word_short.png")),
        new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/word_not_in_grid.png")),
        new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/word_not_in_dic.png")),
        new ImageIcon(getClass().getResource("/inouire/baggle/client/icons/word_filtered.png")),
    };

    public WordStatusPanel(){
        Font F=new Font("Serial", Font.BOLD, 24);
        word_status.setFont(F);
        word_status.setText("");
        this.add(word_status);
        this.setPreferredSize(new Dimension(1000,38));
    }

    public void reset(){
        word_status.setText("");
        word_status.setIcon(null);
    }

    public void setWord(String word,Words status){
        String s=word;
        
        switch(status){
            case GOOD:
                word_status.setIcon(word_status_icons[0]);
                word_status.setToolTipText(Language.getString(66));
                word_status.setForeground(ColorFactory.GOOD_WORD);
                break;
            case ALREADY_FOUND:
                word_status.setIcon(word_status_icons[1]);
                word_status.setToolTipText(Language.getString(66));
                word_status.setForeground(ColorFactory.BAD_WORD);
                break;
            case SHORT:
                word_status.setIcon(word_status_icons[2]);
                word_status.setToolTipText(Language.getString(67));
                word_status.setForeground(ColorFactory.BAD_WORD);
                break;
            case NOT_IN_GRID:
                word_status.setIcon(word_status_icons[3]);
                word_status.setToolTipText(Language.getString(68));
                word_status.setForeground(ColorFactory.BAD_WORD);
                break;
            case NOT_IN_DIC:
                word_status.setIcon(word_status_icons[4]);
                word_status.setToolTipText(Language.getString(69));
                word_status.setForeground(ColorFactory.BAD_WORD);
                break;
            case FILTERED:
                word_status.setIcon(word_status_icons[5]);
                word_status.setToolTipText(Language.getString(70));
                word_status.setForeground(ColorFactory.BAD_WORD);
                break;
        }
        word_status.setText(s);
    }


}
import inouire.baggle.client.gui.modules.StatusActionPanel;
import inouire.baggle.client.gui.modules.TimePanel;
import inouire.baggle.client.gui.modules.WordEntryPanel;
import inouire.baggle.client.gui.modules.WordsFoundPanel;
import inouire.baggle.client.gui.modules.ChatPanel;
import inouire.baggle.client.gui.modules.PlayersPanel;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import inouire.baggle.client.Language;
import inouire.baggle.client.gui.modules.BoardPanel;
import inouire.baggle.client.gui.modules.ResultsPanel;
import inouire.baggle.client.gui.modules.RulesPane;
import inouire.baggle.client.gui.modules.TopBarPanel;
import inouire.baggle.client.gui.modules.WordStatusPanel;
    public void showPrevious(){
        String current = currentCard;
        String previous = previousCard;
        currentCard=previous;
        previousCard=current;
        actionPaneLayout.show(actionPane, previous);
    }
    
    public void showGame(){
        previousCard=currentCard;
        currentCard="game";
        showCurrent();
    }

    public void showResults(){
        previousCard=currentCard;
        currentCard="results";
        showCurrent();
    }
    
    public void showNoGame(){
        previousCard=currentCard;
        currentCard="nogame";
        showCurrent();
    }
    
    public void toggleRules(){
        if(currentCard.equals("rules")){
            showPrevious();
        }else{
            previousCard=currentCard;
            currentCard="rules";
            showCurrent();
        }
        
    }
    
    
    public void showNothing(){
        previousCard=currentCard;
        currentCard="nothing";
        showCurrent();
    }
    
    public void disableAll(){
        //TODO
    }

    public void enableAll(){
        //TODO
    }


    /**
     * Put the focus on the word field
     */
    public void putFocusOnWordField(){
        wordEntryPane.giveFocus();
    }

    /**
     * Refresh only the right side of the screen
     */
    public void refreshRight(){
        chatPane.repaint();
    }

    /**
     * Refresh only the center side of the screen
     */
    public void refreshCenter(){
        center.repaint();
    }

    /**
     * Refresh only the left side of the screen
     */
    public void refreshLeft(){
        playersPane.repaint();
    }

    public int getBotLevel(){
        return this.playersPane.getBotLevel();
    }

    public void setGameMode(String mode,boolean big_board){
        Color boardColor = ColorFactory.getBoardColor(big_board, mode);
        this.topBarPane.setBackground(boardColor);
        this.boardPane.setBoardColor(boardColor);
        
        repaint();
    }
}


class GamePanel extends JPanel{


    public GamePanel(StatusActionPanel sap , BoardPanel bp, WordStatusPanel wsp){
        setLayout(new BorderLayout());
        JPanel top = new JPanel(new GridLayout(0,1));
        top.add(sap);
        add(top,BorderLayout.NORTH);
        add(bp,BorderLayout.CENTER);
        add(wsp,BorderLayout.SOUTH);
    }
}

class NoGamePanel extends JPanel{
    
    StatusActionPanel sap = new StatusActionPanel(true);
    
    public NoGamePanel(){
        
        Font F=new Font("Serial", Font.BOLD, 20);
         
        JLabel no_game = new JLabel();
        no_game.setFont(F);
        no_game.setHorizontalAlignment(SwingConstants.CENTER);
        no_game.setVerticalAlignment(SwingConstants.BOTTOM);
        no_game.setText(Language.getString(78));