/* JChessBoard -- a chess game
 * Copyright (C) 2000-2004 Claus Divossen <claus.divossen@gmx.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/* $Id: VisualBoard.java,v 1.30 2004/12/26 23:12:14 cdivossen Exp $ */

package jchessboard;

import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;

import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.SwingConstants;

/**
 * This class creates the visual representation of the chess board, 
 * and gives the user an interface move the figures.
 */
class VisualBoard extends JLayeredPane {
    private static final int FIELDSIZE = 40;
    // Other board sizes could be implemented by
    // changing this value and replacing the
    // figure icons.
    private static final int MAX = (FIELDSIZE * 7);
    private static final int rankLabelWidth = 15;
    private static final int rankLabelHeight = FIELDSIZE;
    private static final int fileLabelWidth = FIELDSIZE;
    private static final int fileLabelHeight = 15;
    private FigureList[] allLists = new FigureList[13];
    private boolean reverseBoard = false; //White at bottom.
    private boolean isLocked = false; // Locks the board
    private JLabel[][] background = new JLabel[8][8];
    private JLayeredPane boardPane = new JLayeredPane();
    private JLabel[] rankLabel = new JLabel[16];
    private JLabel[] fileLabel = new JLabel[16];
    protected VirtualBoard virtualBoard = null;
    private boolean isEditorBoard = false;
    private HashMap icons = new HashMap();
    private java.awt.event.ActionListener listener = new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            restoreBackground();
        }
    };
    private javax.swing.Timer restoreBackgroundTimer = new javax.swing.Timer(500, listener);

    private JChessBoard jcb; // The parent JChessBoard

    public static String getVersion() {
        return "$Id: VisualBoard.java,v 1.30 2004/12/26 23:12:14 cdivossen Exp $";
    }

    public byte selectPromotion() {
        Object[] option = new Object[4];
        if (virtualBoard.isWhiteTurn()) {
            option[0] = (ImageIcon) icons.get(new Integer(VirtualBoard.WHITE_QUEEN));
            option[1] = (ImageIcon) icons.get(new Integer(VirtualBoard.WHITE_ROOK));
            option[2] = (ImageIcon) icons.get(new Integer(VirtualBoard.WHITE_BISHOP));
            option[3] = (ImageIcon) icons.get(new Integer(VirtualBoard.WHITE_KNIGHT));
        } else {
            option[0] = (ImageIcon) icons.get(new Integer(VirtualBoard.BLACK_QUEEN));
            option[1] = (ImageIcon) icons.get(new Integer(VirtualBoard.BLACK_ROOK));
            option[2] = (ImageIcon) icons.get(new Integer(VirtualBoard.BLACK_BISHOP));
            option[3] = (ImageIcon) icons.get(new Integer(VirtualBoard.BLACK_KNIGHT));
        }
        int choice =
            JOptionPane.showOptionDialog(
                null,
                "Promote pawn to:",
                "",
                JOptionPane.YES_NO_CANCEL_OPTION,
                JOptionPane.QUESTION_MESSAGE,
                null,
                option,
                option[0]);
        if (choice == 0)
            return VirtualBoard.QUEEN;
        else if (choice == 1)
            return VirtualBoard.ROOK;
        else if (choice == 2)
            return VirtualBoard.BISHOP;
        else if (choice == 3)
            return VirtualBoard.KNIGHT;
        else
            return VirtualBoard.NONE;
    }

    public void setLocked(boolean lock) {
        isLocked = lock;
    }

    class VisualFigure extends JLabel implements MouseListener, MouseMotionListener {
        int rank, file; // The field where this figure should be.
        int mousePressedX, mousePressedY; //Where this figure started
        // to be dragged.
        boolean isWhiteFigure;
        int type;

        public VisualFigure(int _type) {
            super((ImageIcon) icons.get(new Integer(_type)));
            type = _type;
            isWhiteFigure = type < 7;
            setSize(getIcon().getIconWidth(), getIcon().getIconHeight());
            addMouseMotionListener(this);
            addMouseListener(this);
        }
        public int getRank() {
            if (reverseBoard)
                return ((getLocation().y + (FIELDSIZE / 2)) / FIELDSIZE);
            else
                return 7 - ((getLocation().y + (FIELDSIZE / 2)) / FIELDSIZE);
        }
        public int getFile() {
            if (reverseBoard)
                return 7 - ((getLocation().x + (FIELDSIZE / 2)) / FIELDSIZE);
            else
                return ((getLocation().x + (FIELDSIZE / 2)) / FIELDSIZE);
        }
        public void setField(int newRank, int newFile) {
            if (reverseBoard)
                setLocation((7 - newFile) * FIELDSIZE, newRank * FIELDSIZE);
            else
                setLocation(newFile * FIELDSIZE, (7 - newRank) * FIELDSIZE);
        }

        // The following methods are required for the MouseListener
        // and MouseMotionListener interfaces.
        public void mousePressed(MouseEvent e) {
            if (isLocked)
                return;
            rank = getRank();
            file = getFile();
            mousePressedX = e.getX();
            mousePressedY = e.getY();
            synchronized (virtualBoard) {
                if (virtualBoard.field[(rank << 3) + file] == VirtualBoard.EMPTY_FIELD) {
                    VisualBoard.this.update();
                    return;
                }
                if (jcb.settings.showPossibleMoves)
                    for (int r = 0; r < 8; r++)
                        for (int f = 0; f < 8; f++)
                            if (virtualBoard.isPossibleMove(new Move(rank, file, r, f)))
                                if (reverseBoard)
                                    background[r][7 - f].setBackground(jcb.settings.boardHighlightColor);
                                else
                                    background[7 - r][f].setBackground(jcb.settings.boardHighlightColor);
            }
        }
        public void mouseDragged(MouseEvent e) {
            if (isLocked)
                return;
            int newX, newY;
            newX = getLocation().x + e.getX() - mousePressedX;
            if (newX > MAX)
                newX = MAX;
            if (newX < 0)
                newX = 0;
            newY = getLocation().y + e.getY() - mousePressedY;
            if (newY > MAX)
                newY = MAX;
            if (newY < 0)
                newY = 0;
            setLocation(newX, newY);
            boardPane.setLayer(this, 10, 0);
        }
        public void mouseReleased(MouseEvent e) {
            if (isLocked)
                return;
            synchronized (virtualBoard) {
                int newRank = getRank();
                int newFile = getFile();
                boardPane.setLayer(this, 2, 0);
                if (rank != newRank || file != newFile) {
                    final Move move = new Move(rank, file, newRank, newFile);
                    if (virtualBoard.isPossibleMove(move)) {
                        if ((virtualBoard.field[move.fromField()] == VirtualBoard.WHITE_PAWN && move.toRank() == 7)
                            || (virtualBoard.field[move.fromField()] == VirtualBoard.BLACK_PAWN && move.toRank() == 0)) {
                            move.setPawnPromotion(selectPromotion());
                        }
                        //isLocked=true;
                        synchronized (jcb) {
                            jcb.makeUsersMove(move);
                        }
                    } else
                        VisualBoard.this.update();
                } else
                    VisualBoard.this.update();
            }
        }
        public void mouseMoved(MouseEvent e) {
        }
        public void mouseClicked(MouseEvent e) {
        }
        public void mouseExited(MouseEvent e) {
        }
        public void mouseEntered(MouseEvent e) {
        }
    }

    class VisualEditorFigure extends VisualFigure {

        public VisualEditorFigure(int type) {
            super(type);
        }

        // The following methods are required for the MouseListener
        // and MouseMotionListener interfaces.
        public void mousePressed(MouseEvent e) {
            if (isLocked)
                return;
            rank = getRank();
            file = getFile();
            mousePressedX = e.getX();
            mousePressedY = e.getY();
            synchronized (virtualBoard) {
                if (virtualBoard.field[(rank << 3) + file] == VirtualBoard.EMPTY_FIELD) {
                    VisualBoard.this.redraw();
                    return;
                }
            }
        }
        public void mouseReleased(MouseEvent e) {
            if (isLocked)
                return;
            synchronized (virtualBoard) {
                int newRank = getRank();
                int newFile = getFile();
                boardPane.setLayer(this, 2, 0);
                if (rank != newRank || file != newFile) {
                    virtualBoard.field[(rank << 3) + file] = VirtualBoard.EMPTY_FIELD;
                    virtualBoard.field[(newRank << 3) + newFile] = type;
                    if (type == VirtualBoard.WHITE_KING)
                        virtualBoard.whiteKingPos = (newRank << 3) + newFile;
                    if (type == VirtualBoard.BLACK_KING)
                        virtualBoard.blackKingPos = (newRank << 3) + newFile;
                }
                VisualBoard.this.redraw();
            }
        }
    }

    class VisualPoolFigure extends VisualFigure {
        public int basePosX, basePosY;

        public VisualPoolFigure(int type, int posX, int posY) {
            super(type);
            basePosX = posX;
            basePosY = posY;
            setLocation(basePosX, basePosY);
        }

        public int getRank() {
            if (reverseBoard)
                return ((getLocation().y - fileLabelHeight + (FIELDSIZE / 2)) / FIELDSIZE);
            else
                return 7 - ((getLocation().y - fileLabelHeight + (FIELDSIZE / 2)) / FIELDSIZE);
        }
        public int getFile() {
            if (reverseBoard)
                return 7 - ((getLocation().x - rankLabelWidth + (FIELDSIZE / 2)) / FIELDSIZE);
            else
                return ((getLocation().x - rankLabelWidth + (FIELDSIZE / 2)) / FIELDSIZE);
        }

        // The following methods are required for the MouseListener
        // and MouseMotionListener interfaces.
        public void mousePressed(MouseEvent e) {
            if (isLocked)
                return;
            rank = getRank();
            file = getFile();
            mousePressedX = e.getX();
            mousePressedY = e.getY();
        }

        public void mouseDragged(MouseEvent e) {
            if (isLocked)
                return;
            int newX, newY;
            newX = getLocation().x + e.getX() - mousePressedX;
            newY = getLocation().y + e.getY() - mousePressedY;
            setLocation(newX, newY);
        }

        public void mouseReleased(MouseEvent e) {
            if (isLocked)
                return;
            synchronized (virtualBoard) {
                int newRank = getRank();
                int newFile = getFile();
                if (newFile >= 0 && newFile < 8 && newRank >= 0 && newRank < 8)
                    virtualBoard.field[(newRank << 3) + newFile] = type;
                if (type == VirtualBoard.WHITE_KING)
                    virtualBoard.whiteKingPos = (newRank << 3) + newFile;
                if (type == VirtualBoard.BLACK_KING)
                    virtualBoard.blackKingPos = (newRank << 3) + newFile;
                VisualBoard.this.redraw();
            }
            setLocation(basePosX, basePosY);
        }
    }

    /**
     * This class maintains a dynamic list of figures (VisualFigure) for each figure type.
     */
    class FigureList {
        // Each List begins empty. When a figure is requested with getFigure
        // and there are no more figures in the list, a new VisualFigure will be
        // created and appended to the list.
        // Ok, this could be done with a static list of a defined length for
        // each type, too, but I wanted to try it this way. I like dynamic
        // structures, allthough this is static from some point of view: because
        // the lists are rewound before the board is updated, already created
        // figures will be reused, and the laws of chess don't allow unlimited
        // figures. But don't forget: There could be up to nine queens of one
        // color! Or ten rooks, knights, bishops...
        private ArrayList list = new ArrayList(8);
        private int type;
        private ImageIcon icon;
        private int index = 0;

        public VisualFigure getFigure() {
            VisualFigure figure;
            if (index >= list.size()) {
                if (isEditorBoard)
                    list.add(new VisualEditorFigure(type));
                else
                    list.add(new VisualFigure(type));
                figure = (VisualFigure) list.get(index);
            } else
                figure = (VisualFigure) list.get(index);
            if (!figure.isVisible())
                figure.setVisible(true);
            index++;
            return (figure);
        }
        public void rewind() {
            index = 0;
        }
        public void hideRest() {
            if (list.size() > 0)
                while (index < list.size()) {
                    ((VisualFigure) list.get(index)).setVisible(false);
                    index++;
                }
        }
        public FigureList(int _type) {
            type = _type;
        }
    }

    public void update() {
        synchronized (this) {
            virtualBoard = jcb.getCurrentVirtualBoard();
            redraw();
        }
    }

    public void redraw() {
        VisualFigure figure;
        int x, y;
        restoreBackground();
        for (int t = 1; t < allLists.length; t++)
            allLists[t].rewind();
        synchronized (virtualBoard) {
            for (int rank = 0; rank < 8; rank++) {
                for (int file = 0; file < 8; file++) {
                    int type = virtualBoard.field[(rank << 3) + file];
                    if (type != VirtualBoard.EMPTY_FIELD) {
                        figure = allLists[type].getFigure();
                        boardPane.add(figure, new Integer(2), 0);
                        figure.setField(rank, file);
                    }
                }
            }
            for (int t = 1; t < allLists.length; t++)
                allLists[t].hideRest();
        }
//        if (!isEditorBoard) {
  //          setLocked(virtualBoard.gameIsFinished());
    //    }
        //            repaint();
    }

    public boolean reverseBoard() {
        return reverseBoard;
    }

    public void setReverseBoard(boolean reverse) {
        reverseBoard = reverse;
        updateLabels();
        redraw();
    }

    public void updateLabels() {
        if (!reverseBoard) {
            for (int n = 0; n < 8; n++) {
                rankLabel[n].setText("" + (8 - n));
                rankLabel[n + 8].setText("" + (8 - n));
                fileLabel[n].setText("" + (char) (((int) 'a') + n));
                fileLabel[n + 8].setText("" + (char) (((int) 'a') + n));
            }
        } else {
            for (int n = 0; n < 8; n++) {
                rankLabel[7 - n].setText("" + (8 - n));
                rankLabel[15 - n].setText("" + (8 - n));
                fileLabel[7 - n].setText("" + (char) (((int) 'a') + n));
                fileLabel[15 - n].setText("" + (char) (((int) 'a') + n));
            }
        }
    }

    public void restoreBackground() {
        for (int rank = 0; rank < 8; rank++)
            for (int file = 0; file < 8; file++)
                if ((rank + file & 1) == 1)
                    background[rank][file].setBackground(jcb.settings.boardColor1);
                else
                    background[rank][file].setBackground(jcb.settings.boardColor2);
    }

    public void showMove(Move move, int duration) {
        if (reverseBoard) {
            background[move.fromRank()][7 - move.fromFile()].setBackground(jcb.settings.boardHighlightColor);
            background[move.toRank()][7 - move.toFile()].setBackground(jcb.settings.boardHighlightColor);
        } else {
            background[7 - move.fromRank()][move.fromFile()].setBackground(jcb.settings.boardHighlightColor);
            background[7 - move.toRank()][move.toFile()].setBackground(jcb.settings.boardHighlightColor);
        }
        restoreBackgroundTimer.setRepeats(false);
        restoreBackgroundTimer.setDelay(duration);
        restoreBackgroundTimer.restart();
    }

    private void loadIcon(int type, String filename) {
        String fullFilename = "/images/" + filename;
        URL url = VisualBoard.class.getResource(fullFilename);
        ImageIcon icon = url != null ? new ImageIcon((URL) url) : new ImageIcon("null");
        if (icon == null) { // Doesn't work, damn!
            System.out.println("Could not load image from jar file: " + filename + "\n");
            System.exit(-1);
        }
        icons.put(new Integer(type), icon);
    }

    private void initialize() {
        loadIcon(VirtualBoard.WHITE_KING, "WK.gif");
        loadIcon(VirtualBoard.WHITE_QUEEN, "WQ.gif");
        loadIcon(VirtualBoard.WHITE_ROOK, "WR.gif");
        loadIcon(VirtualBoard.WHITE_BISHOP, "WB.gif");
        loadIcon(VirtualBoard.WHITE_KNIGHT, "WN.gif");
        loadIcon(VirtualBoard.WHITE_PAWN, "WP.gif");
        loadIcon(VirtualBoard.BLACK_KING, "BK.gif");
        loadIcon(VirtualBoard.BLACK_QUEEN, "BQ.gif");
        loadIcon(VirtualBoard.BLACK_ROOK, "BR.gif");
        loadIcon(VirtualBoard.BLACK_BISHOP, "BB.gif");
        loadIcon(VirtualBoard.BLACK_KNIGHT, "BN.gif");
        loadIcon(VirtualBoard.BLACK_PAWN, "BP.gif");

        virtualBoard = jcb.getCurrentVirtualBoard();

        for (int f = 1; f < 13; f++) {
            allLists[f] = new FigureList(f);
        }
        setLayout(null);
        setBackground(jcb.settings.boardBackgroundColor);
        setOpaque(true);
        add(boardPane);
        boardPane.setBounds(rankLabelWidth, fileLabelHeight, 8 * FIELDSIZE, 8 * FIELDSIZE);
        // Create field labels
        for (int n = 0; n < 8; n++) {
            rankLabel[n] = new JLabel("" + (8 - n), SwingConstants.CENTER);
            add(rankLabel[n]);
            rankLabel[n].setBounds(0, fileLabelHeight + n * rankLabelHeight, rankLabelWidth, rankLabelHeight);
            rankLabel[n].setForeground(jcb.settings.boardLabelColor);

            rankLabel[n + 8] = new JLabel("" + (8 - n), SwingConstants.CENTER);
            add(rankLabel[n + 8]);
            rankLabel[n
                + 8].setBounds(
                    rankLabelWidth + 8 * FIELDSIZE,
                    fileLabelHeight + n * rankLabelHeight,
                    rankLabelWidth,
                    rankLabelHeight);
            rankLabel[n + 8].setForeground(jcb.settings.boardLabelColor);

            fileLabel[n] = new JLabel("" + (char) (((int) 'a') + n), SwingConstants.CENTER);
            add(fileLabel[n]);
            fileLabel[n].setBounds(
                rankLabelWidth + n * fileLabelWidth,
                8 * FIELDSIZE + fileLabelHeight,
                fileLabelWidth,
                fileLabelHeight);
            fileLabel[n].setForeground(jcb.settings.boardLabelColor);

            fileLabel[n + 8] = new JLabel("" + (char) (((int) 'a') + n), SwingConstants.CENTER);
            add(fileLabel[n + 8]);
            fileLabel[n + 8].setBounds(rankLabelWidth + n * fileLabelWidth, 0, fileLabelWidth, fileLabelHeight);
            fileLabel[n + 8].setForeground(jcb.settings.boardLabelColor);
        }
        // Create the background:
        for (int x = 0; x < 8; x++)
            for (int y = 0; y < 8; y++) {
                JLabel backgroundLabel = new JLabel();
                backgroundLabel.setOpaque(true);
                backgroundLabel.setBounds(x * FIELDSIZE, y * FIELDSIZE, FIELDSIZE, FIELDSIZE);
                boardPane.add(backgroundLabel, new Integer(1), 0);
                background[y][x] = backgroundLabel;
            }
        // Create the reverse board button
        ImageIcon reverseIcon = new ImageIcon(VisualBoard.class.getResource("/images/reverse.png"));
        //JLabel reverseButton = new JLabel("R",SwingConstants.CENTER);
        JButton reverseButton = new JButton(reverseIcon);
        add(reverseButton);
        reverseButton.setForeground(jcb.settings.boardLabelColor);
        reverseButton.setBackground(jcb.settings.boardBackgroundColor);
        reverseButton.setBorder(null);
        reverseButton.setOpaque(true);
        reverseButton.setBounds(0, 0, rankLabelWidth, fileLabelHeight);
        reverseButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                setReverseBoard(!reverseBoard());
                jcb.updateMenu();
                // TODO: Shouldn't be done by an editor board.
            }
        });
        if (isEditorBoard) {
            JLabel backgroundLabel = new JLabel();
            backgroundLabel.setBackground(new java.awt.Color(150, 150, 150));
            backgroundLabel.setOpaque(true);
            backgroundLabel.setBounds(8 * FIELDSIZE + 2 * rankLabelWidth, 0, 2 * FIELDSIZE, 6 * FIELDSIZE);
            add(backgroundLabel, new Integer(1));

            VisualFigure figure = new VisualPoolFigure(VirtualBoard.WHITE_KING, 8 * FIELDSIZE + 2 * rankLabelWidth, 0);
            add(figure, new Integer(10));
            figure = new VisualPoolFigure(VirtualBoard.WHITE_QUEEN, 8 * FIELDSIZE + 2 * rankLabelWidth, FIELDSIZE);
            add(figure, new Integer(10));
            figure = new VisualPoolFigure(VirtualBoard.WHITE_ROOK, 8 * FIELDSIZE + 2 * rankLabelWidth, FIELDSIZE * 2);
            add(figure, new Integer(10));
            figure = new VisualPoolFigure(VirtualBoard.WHITE_BISHOP, 8 * FIELDSIZE + 2 * rankLabelWidth, FIELDSIZE * 3);
            add(figure, new Integer(10));
            figure = new VisualPoolFigure(VirtualBoard.WHITE_KNIGHT, 8 * FIELDSIZE + 2 * rankLabelWidth, FIELDSIZE * 4);
            add(figure, new Integer(10));
            figure = new VisualPoolFigure(VirtualBoard.WHITE_PAWN, 8 * FIELDSIZE + 2 * rankLabelWidth, FIELDSIZE * 5);
            add(figure, new Integer(10));

            figure = new VisualPoolFigure(VirtualBoard.BLACK_KING, 9 * FIELDSIZE + 2 * rankLabelWidth, 0);
            add(figure, new Integer(10));
            figure = new VisualPoolFigure(VirtualBoard.BLACK_QUEEN, 9 * FIELDSIZE + 2 * rankLabelWidth, FIELDSIZE);
            add(figure, new Integer(10));
            figure = new VisualPoolFigure(VirtualBoard.BLACK_ROOK, 9 * FIELDSIZE + 2 * rankLabelWidth, FIELDSIZE * 2);
            add(figure, new Integer(10));
            figure = new VisualPoolFigure(VirtualBoard.BLACK_BISHOP, 9 * FIELDSIZE + 2 * rankLabelWidth, FIELDSIZE * 3);
            add(figure, new Integer(10));
            figure = new VisualPoolFigure(VirtualBoard.BLACK_KNIGHT, 9 * FIELDSIZE + 2 * rankLabelWidth, FIELDSIZE * 4);
            add(figure, new Integer(10));
            figure = new VisualPoolFigure(VirtualBoard.BLACK_PAWN, 9 * FIELDSIZE + 2 * rankLabelWidth, FIELDSIZE * 5);
            add(figure, new Integer(10));

            JPanel buttonPanel = new JPanel();
            buttonPanel.setLayout(new GridLayout(3, 1));
            JLabel turnLabel = new JLabel("Turn:");
            buttonPanel.add(turnLabel);
            JRadioButton whiteTurnButton = new JRadioButton("White");
            whiteTurnButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    virtualBoard.isWhiteTurn = true;
                }
            });
            whiteTurnButton.setSelected(virtualBoard.isWhiteTurn);
            JRadioButton blackTurnButton = new JRadioButton("Black");
            blackTurnButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    virtualBoard.isWhiteTurn = false;
                }
            });
            blackTurnButton.setSelected(!virtualBoard.isWhiteTurn);
            ButtonGroup buttonGroup = new ButtonGroup();
            buttonGroup.add(whiteTurnButton);
            buttonGroup.add(blackTurnButton);
            buttonPanel.add(whiteTurnButton);
            buttonPanel.add(blackTurnButton);
            add(buttonPanel);
            buttonPanel.setBounds(
                8 * FIELDSIZE + 2 * rankLabelWidth,
                FIELDSIZE * 6,
                2 * FIELDSIZE,
                2 * FIELDSIZE + 2 * fileLabelHeight);
        }

        update();
        Dimension panelSize = null;
        if (isEditorBoard) {
            panelSize = new Dimension(10 * FIELDSIZE + 2 * rankLabelWidth, 8 * FIELDSIZE + 2 * fileLabelHeight);
        } else {
            panelSize = new Dimension(8 * FIELDSIZE + 2 * rankLabelWidth, 8 * FIELDSIZE + 2 * fileLabelHeight);
        }
        setPreferredSize(panelSize);
        setMinimumSize(panelSize);
        if (isEditorBoard) {
            setMaximumSize(panelSize);
        }
        //        setSize(8*FIELDSIZE+2*rankLabelWidth,8*FIELDSIZE+2*fileLabelHeight);
    }

    public VisualBoard(JChessBoard b) {
        jcb = b;
        initialize();
    }

    public VisualBoard(JChessBoard b, boolean _isEditorBoard) {
        jcb = b;
        isEditorBoard = _isEditorBoard;
        initialize();
    }

}
