001/*
002 * Main.java
003 */
004package minesweeper;
005
006import java.awt.*;
007import java.awt.event.*;
008//import java.awt.image.*;
009//import javax.imageio.*;
010import javax.swing.*;
011//import javax.swing.border.*;
012//import java.text.*;
013//import java.io.*;
014import java.util.*;
015
016import org.apache.logging.log4j.*;
017
018/**
019 * DESCRIBE {@link Main} HERE.
020 *
021 * @author 2017-2018 APCS
022 * @author ADD @author TAG FOR EVERYONE WHO CONTRIBUTED TO THIS FILE
023 * @author <a href="https://github.com/wps-dpetty">David C. Petty</a>
024 */
025public class Main extends JFrame {
026
027    //////////////////////////////// FIELDS ////////////////////////////////
028
029    /**
030     * log4j {@link Logger}.
031     */
032    private static Logger logger = LogManager.getLogger(Minesweeper.SHORT);
033    /**
034     * Number of rows in grid.
035     */
036    private static int rows;
037    /**
038     * Number of cols in grid.
039     */
040    private static int cols;
041    /**
042     * Number of mines in grid.
043     */
044    private static int mines;
045
046    /**
047     * {@link Stopwatch} <strong>FOR WHAT?</strong>
048     */
049    private static Stopwatch sw;
050
051    /**
052     * Single {@link JPanel} in main {@link JFrame} so as to accurately
053     * calculate drawing area.
054     */
055    private static JPanel panel;
056    /**
057     * {@link JLabel} to display timer.
058     */
059    private static JLabel timerLabel;
060    /**
061     * {@link Grid} of {@link Button}s.
062     */
063    private static Grid grid;
064
065    ///////////////////////////// CONSTRUCTORS /////////////////////////////
066
067    /**
068     * Construct a {@link Main} frame.
069     *
070     * @param name  frame title
071     * @param rows  number of rows in grid
072     * @param cols  number of columns in grid
073     * @param mines number of mines in grid
074     */
075    public Main(String name, int rows, int cols, int mines) {
076        super(name);
077        Main.rows = rows;
078        Main.cols = cols;
079        Main.mines = mines;
080        logger.info("{}: {} ({}x{}) {}",
081                getClass().getName(), name, rows, cols, mines);
082    }
083
084    //////////////////////////////// CLASSES ///////////////////////////////
085
086    /**
087     * PanelListener listens for resize events and adjusts grid accordingly.
088     */
089    private static class PanelListener extends ComponentAdapter {
090        public void componentResized(ComponentEvent e) {
091            // Log layoutDimensions from GridBagLayout to help calculate resize.
092            GridBagLayout layout = (GridBagLayout) panel.getLayout();
093            int[][] dims = layout.getLayoutDimensions();
094            int xSum = 0, ySum = 0;
095            for (int i = 0; i < dims[0].length; i++) xSum += dims[0][i];
096            for (int j = 0; j < dims[1].length; j++) ySum += dims[1][j];
097            int igw = grid.getCols() * grid.getSide();  // initial grid width
098            int igh = grid.getRows() * grid.getSide();  // initial grid height
099            double rgw = xSum;                          // reset grid width
100            double rgh = dims[1][2] + panel.getHeight() - ySum; // reset grid height
101            logger.info("{} {} ({},{}) [{}x{} {}x{}: {} {}]",
102                    e, Arrays.deepToString(dims), xSum, ySum, igw, igh, rgw, rgh,
103                    rgw / grid.getCols(), rgh / grid.getRows());
104            // Calculate minimum square button size & set grid size accordingly.
105            int side = (int) Math.min(rgw / grid.getCols(), rgh / grid.getRows());
106            grid.setSize(side * grid.getCols(), side * grid.getRows());
107        }
108    }
109
110    //////////////////////////////// METHODS ///////////////////////////////
111
112    /**
113     * Return {@link Grid} component.
114     *
115     * @return grid component
116     */
117    public static Grid getGrid() {
118        return grid;
119    }
120
121    /**
122     * Create and show main graphical user interface.
123     */
124    private static void createAndShowGUI() {
125        // Create and set up the window frame.
126        // REDFLAG: mines should be a function of level, rows, and cols
127        Main frame = new Main("Minesweeper", 16, 30, 99);
128        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
129
130        // Use single JPanel in frame to get full width & height.
131        panel = new JPanel();
132        panel.addComponentListener(new PanelListener());
133
134        // Initialize panel layout.
135        GridBagLayout layout = new GridBagLayout();
136        panel.setLayout(layout);
137        GridBagConstraints c = new GridBagConstraints();
138
139        // Display mineCount.
140        JLabel mineCount = new JLabel("0" + mines, SwingConstants.CENTER);
141        mineCount.setFont(new Font("Verdana", 1, 20));
142        c = new GridBagConstraints();
143        c.anchor = GridBagConstraints.FIRST_LINE_START;
144        c.anchor = GridBagConstraints.CENTER;
145        c.fill = GridBagConstraints.HORIZONTAL;
146        c.gridx = 0;
147        c.gridy = 0;
148        c.ipadx = 10;
149        c.weightx = 0.5;
150        panel.add(mineCount, c);
151
152        // Display smile.
153        Image image = Images.getImage("/images/smiley1.jpeg");
154        ImageIcon icon = new ImageIcon(image);
155        Dimension size = new Dimension(icon.getIconWidth(), icon.getIconHeight());
156        JButton smile = new JButton(icon);
157        smile.setPreferredSize(size);
158        c = new GridBagConstraints();
159        c.anchor = GridBagConstraints.PAGE_START;
160        c.anchor = GridBagConstraints.CENTER;
161        c.fill = GridBagConstraints.NONE;
162        c.gridx = 1;
163        c.gridy = 0;
164        c.ipadx = 10;
165        c.weightx = 0.5;
166        panel.add(smile, c);
167
168        sw = new Stopwatch();// initialize sw
169
170        // Display timerLabel.
171        timerLabel = new JLabel("00:00", SwingConstants.CENTER);
172        timerLabel.setFont(new Font("Verdana", 1, 20));
173        c = new GridBagConstraints();
174        c.anchor = GridBagConstraints.FIRST_LINE_END;
175        c.anchor = GridBagConstraints.CENTER;
176        c.fill = GridBagConstraints.HORIZONTAL;
177        c.gridx = 2;
178        c.gridy = 0;
179        c.ipadx = 10;
180        c.weightx = 0.5;
181        panel.add(timerLabel, c);
182
183        // Display separator.
184        JSeparator separator = new JSeparator();
185        c = new GridBagConstraints();
186        c.anchor = GridBagConstraints.CENTER;
187        c.fill = GridBagConstraints.BOTH;
188        c.gridx = 0;
189        c.gridy = 1;
190        c.ipadx = 0;
191        c.gridwidth = 3;
192        c.weightx = 0.5;
193        panel.add(separator, c);
194
195        // Display grid.
196        grid = new Grid(rows, cols);
197        c = new GridBagConstraints();
198        c.anchor = GridBagConstraints.SOUTH;
199        c.fill = GridBagConstraints.NONE;
200        c.gridx = 0;
201        c.gridy = 2;
202        c.ipadx = 0;
203        c.gridwidth = 3;
204        c.weightx = 0.5;
205        panel.add(grid, c);
206
207        // Display frame.
208        frame.add(panel);
209        frame.pack();
210        frame.setMinimumSize(frame.getSize());  // layout will not get smaller
211        frame.setVisible(true);
212    }
213
214    public static void startTimer(boolean resetTimer) {
215        //resetTimer();
216        if (resetTimer || (!sw.isStopWatchRunning())) {
217            sw.startStopWatch();// Traditionally Stopwatch is only started after the first click on the grid...
218            javax.swing.Timer mainTimer = new javax.swing.Timer(100, new ActionListener() {
219                public void actionPerformed(ActionEvent e) {
220                    timerLabel.setText(sw.getFormattedElapsedTime());
221                }
222            });
223            mainTimer.start();
224        }
225    }
226
227    public  static void youDied() {
228        Main frame = new Main("Minesweeper", 16, 30, 99);
229        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
230
231        // Use single JPanel in frame to get full width & height.
232        panel = new JPanel();
233        panel.addComponentListener(new PanelListener());
234
235        // Initialize panel layout.
236        GridBagLayout layout = new GridBagLayout();
237        panel.setLayout(layout);
238        GridBagConstraints c = new GridBagConstraints();
239        // Display dead emoticon.
240        Image image = Images.getImage("/images/youLost1.jpeg");
241        ImageIcon icon = new ImageIcon(image);
242        Dimension size = new Dimension(icon.getIconWidth(), icon.getIconHeight());
243        JButton smile = new JButton(icon);
244        smile.setPreferredSize(size);
245        c = new GridBagConstraints();
246        c.anchor = GridBagConstraints.PAGE_START;
247        c.anchor = GridBagConstraints.CENTER;
248        c.fill = GridBagConstraints.NONE;
249        c.gridx = 1;
250        c.gridy = 0;
251        c.ipadx = 10;
252        c.weightx = 0.5;
253        panel.add(smile, c);
254    }
255
256    /**
257     * Minesweeper main method.
258     *
259     * @param args command-line arguments
260     */
261    public static void main(String[] args) {
262        javax.swing.SwingUtilities.invokeLater(new Runnable() {
263            public void run() {
264                createAndShowGUI();
265            }
266        });
267    }
268}