001package bradleyross.library.applets;
002//import java.util.Date;
003import java.util.Vector;
004import java.util.Date;                                                                                                                                                                                                                                                                                                                                                                         
005import java.io.File;
006import java.io.FileInputStream;
007import java.io.FileNotFoundException;
008import java.io.IOException;
009import java.io.StringReader;
010import java.io.LineNumberReader;
011import java.awt.Container;
012import java.awt.Canvas;
013import java.awt.Color;
014import java.awt.Dimension;
015import java.awt.Graphics;
016import java.awt.GridLayout;
017import java.awt.event.MouseEvent;
018import java.awt.event.ActionEvent;
019import java.awt.event.ActionListener;
020import java.awt.event.MouseListener;
021import java.awt.event.AdjustmentListener;
022import java.awt.event.AdjustmentEvent;
023import java.awt.image.BufferedImage;
024import javax.swing.JApplet;
025import javax.swing.JScrollPane;
026import javax.swing.JScrollBar;
027import javax.swing.BoundedRangeModel;
028import javax.swing.JFrame;
029import javax.swing.JPanel;
030import javax.swing.JTextArea;
031import javax.swing.JButton;
032import javax.swing.BoxLayout;
033import java.net.MalformedURLException;
034import java.net.URL;
035import javax.imageio.ImageIO;
036import bradleyross.library.helpers.FileHelpers;
037import bradleyross.library.helpers.RandomHelpers;
038/**
039 * Concentration game.
040 * 
041 * @see JPanel
042 * @see JFrame
043 * @see Container
044 * @author Bradley Ross
045 */
046public class Concentration extends JApplet 
047{
048        /**
049         * Panel containing the actual game.  
050         * <p>It is
051         *    divided into tiles.</p>
052         */
053        GamePanel gamePanel = null;
054        /**
055         * Main panel for the game.
056         * 
057         * <p>The value is set by the {@link #init() } method to
058         *    the content panel of the main widow for the applet.  
059         *    The {link #gamePanel} panel is part of the content
060         *    pane.</p>
061         */
062        Container contentPane = null;
063        /**
064         * Optional frame for displaying diagnostic information.
065         * 
066         * <p>This frame only appears if the Debug parameter for the
067         *    applet is set to a value greater than zero.</p>
068         */
069        JFrame debugFrame = null;
070        /**
071         * True if class is called as a JApplet.
072         * 
073         * <p>If the class is called as a standalone application, the
074         *    value is set to false.</p>
075         * @see #setAppletMode(boolean)
076         */
077        boolean appletMode = true;
078        /**
079         * Setter for applietMode.
080         * 
081         * @param value Value to be used for appletMode
082         */
083        public void setAppletMode( boolean value)
084        {
085                appletMode = value;
086        }
087        /**
088         * Provided for compliance with Serializable interface.
089         */
090        private static final long serialVersionUID = 1L;
091        /**
092         * Root of directory or URL containing images.
093         */
094        protected URL imageRoot = null;
095        /** 
096         * Panel containing text area with debugging information.
097         */
098        protected secondPanel debugPanel = null;
099        /** 
100         * This is the latest id number to be used with one of the tiles.
101         * 
102         */
103        private static int latestCounter = 1000;
104        /**
105         * Controls amount of diagnostic output.
106         * <p>If the value is greater than zero, the 
107         *    {@link #debugFrame} is created as a second
108         *    window on the display to show the 
109         *    diagnostic messages.</p>
110         * @see #setDebugLevel(int)
111         * @see #getDebugLevel()
112         */
113        protected int debugLevel = 0;
114        /**
115         * Setter for debugLevel.
116         * @param value Value to be used for debugLevel
117         * @see #debugLevel
118         */
119        public void setDebugLevel(int value)
120        { debugLevel = value; }
121        /**
122         * Getter for debugLevel.
123         * @return Value of debugLevel
124         * @see #debugLevel
125         */
126        public int getDebugLevel()
127        { return debugLevel; }
128        /**
129         * Not sure if this is still used.
130         */
131        protected Container mainPanel = null;
132        /**
133         * Object containing the game panel.
134         * <p>This panel contains all of the individual tiles.</p>
135         */
136        protected Concentration game = null;
137        /**
138         * Vector object containing the images to be placed on the tiles.
139         */
140        Vector<ImageInstance> imageList = new Vector<ImageInstance>(); 
141        /**
142         * Array of the tiles on the game panel.
143         */
144        Tile tileList[] = null;
145        /**
146         * Number of tiles horizontally.
147         */
148        protected int tilesWidth = 6;
149        /**
150         * Number of tiles vertically.
151         */
152        protected int tilesHeight = 6;
153        /**
154         * Length of height and width of cell in pixels.
155         */
156        protected int cellWidth = 100;
157        /**
158         * Distance between cells in pixels.
159         */
160        protected int cellMargin = 10;
161        /**
162         * Number of tiles remaining that have yet to be matched
163         */
164        protected int numberRemaining = 0;
165        /**
166         * URL name to be used to obtain the list of image URL's.
167         */
168        protected String imageListUrl = null;
169        /**
170         * String containing the list of images.
171         */
172        protected String imageListString = null;
173        /**
174         * Displays messages if debugLevel is greater
175         * than 0.
176         * 
177         * @param message Message to be included in error window
178         * @see #debugLevel
179         * @see #debugFrame
180         */
181        protected void logMessage(String message)
182        {
183                if (debugLevel > 0)
184                { 
185                        debugPanel.writeMessage(message + "\n"); 
186                        /*
187                        debugFrame.repaint(10l);
188                        textBlock.repaint(10l);
189                        */
190                }
191        }
192        /**
193         * Causes thread for a number of milliseconds
194         * @param length Time to wait in milliseconds
195         */
196        protected void sleeper(int length)
197        {
198                if (length <= 0) { return; }
199                long startTime = System.currentTimeMillis();
200                long endTime = startTime + (long) length;
201                long currentTime = System.currentTimeMillis();
202                for (int i = 0; i < 15; i++)
203                {
204                        currentTime = System.currentTimeMillis();
205                        if (currentTime >= endTime) { break; }
206                        try 
207                        {
208                                Thread.sleep((int)(endTime - currentTime));
209                        } 
210                        catch (InterruptedException e) 
211                        { ; }
212                }
213                logMessage("sleeper: " + Integer.toString(length) + " " +
214                                Long.toString(currentTime - startTime));
215                System.out.println("Sleep program didn't reach end");
216        }
217        public String[][] getParameterInfo()
218        {
219                String[][] info = {
220                                { "CellWidth", "integer", "Width of cell in pixels" },
221                                { "CellMargin", "integer", "Width of cell margin in pixels" },
222                                { "Debug", "integer", "Amount of diagnostic output" }
223                };
224                return info;    
225        }
226        /**
227         * These are the individual squares for the game.
228         * 
229         * <p>The gamePanel object serves as the listener
230         *    for all of the Tile objects.</p>
231         * @author Bradley Ross
232         * 
233         * @see #game
234         *
235         */
236        protected class Tile extends Canvas 
237        {
238                /** Indicates that "card back" is shown. */
239                protected static final int INITIAL = 0;
240                /** Indicates that image to be matched is shown, */
241                protected static final int IMAGE = 1;
242                /** Indicates that card has been removed after being matched. */
243                protected static final int REVEALED = 2;
244                /** Indicates that status of card is unknown. */
245                protected static final int UNKNOWN = -1;
246                /** Indicate current status of the tile. */
247                protected int status = UNKNOWN;
248                // protected int requestedStatus = REVEALED;
249                /**
250                 * ID value for tile.
251                 */
252                protected int counter;
253                /** 
254                 * Pointer to a member of the imageList vector.
255                 * @see #imageList
256                 */
257                protected int imageNumber;
258                /**
259                 * Value to satisfy {@link java.io.Serializable} interface.
260                 */
261                private static final long serialVersionUID = 1L;
262                public Tile(int id)
263                {
264                        super();
265                        counter = id;
266                        if (debugLevel > 4)
267                        { logMessage("Creating Tile object - parameter for constructor is " +
268                                        Integer.toString(counter)); }
269                        setPreferredSize(new Dimension(this.getWidth(), this.getHeight()));
270                        setMinimumSize(new Dimension(this.getWidth(), this.getHeight()));
271                }
272                public Tile()
273                {
274                        super();
275                        latestCounter++;
276                        counter = latestCounter;
277                        if (debugLevel > 4)
278                        { logMessage("Creating Tile object - no arguments for constructor"); }
279                        setPreferredSize(new Dimension(cellWidth + cellMargin, cellWidth + cellMargin));
280                        this.setVisible(true);
281                        if (this.getGraphics() != null)
282                        { paint(this.getGraphics()); }
283                }
284                /**
285                 * Getter for counter
286                 * @see #counter
287                 * @return Value of counter
288                 */
289                public int getCounter()
290                { return counter; }
291                /**
292                 * Getter for imageNumber
293                 * @see #imageNumber
294                 * @return Value of imageNumber
295                 */
296                public int getImageNumber()
297                { return imageNumber; }
298                /**
299                 * Setter for imageNumber.
300                 * @param value Value to be used for imageNumber
301                 * @see #imageNumber
302                 */
303                public void setImageNumber(int value)
304                { imageNumber = value; }
305                /** 
306                 * Setter for status.
307                 * 
308                 * @param newStatus Value to be used for {@link #status}
309                 */
310                public void setStatus(int newStatus)
311                {
312                        if (newStatus == UNKNOWN)
313                        { status = UNKNOWN; }
314                        else if (status != newStatus)
315                        {
316                        status = newStatus;
317                        logMessage("Tile.setStatus requesting repaint of tile " + Integer.toString(counter));
318                        repaint();
319                        }
320                }
321                /**
322                 * Getter for status.
323                 * @return {@link #status}
324                 */
325                public int getStatus()
326                { return status; }
327                /**
328                 * This class allows requests to repaint the tile to be tracked.
329                 */
330                public void repaint()
331                {
332                        if (debugLevel > 4)
333                        {
334                        logMessage("Repaint requested for tile " + Integer.toString(counter) +
335                                        " : " + new Date().toString());
336                        }
337                        super.repaint();
338                }
339                /**
340                 * Draws on tile depending on status.
341                 * 
342                 */
343                public void paint(Graphics g)
344                {
345                        /* if (requestedStatus == status) { return; } */
346                        logMessage("Painting tile " + Integer.toString(counter) + " : " +
347                                        new Date().toString());
348                        super.paint(g);
349                        if (status == INITIAL)
350                        {
351                                int working = cellMargin / 2;
352                                g.setColor(Color.red);
353                                g.fillRect(working, working, cellWidth, cellWidth);
354                                g.setColor(Color.blue);
355                                g.fillRect(2 * working, 2 * working, cellWidth -  cellMargin, cellWidth -  cellMargin);
356                                g.setColor(Color.magenta);
357                                g.fillRect(3 * working, 3 * working, cellWidth - 2 * cellMargin, cellWidth - 2 * cellMargin);
358                                g.setColor(Color.cyan);
359                                g.fillRect(4 * working, 4 * working, cellWidth - 3 * cellMargin, cellWidth - 3 * cellMargin);
360                        }
361                        else if (status == IMAGE)
362                        {
363                                g.drawImage(imageList.elementAt(imageNumber).getImage(), cellMargin / 2, cellMargin / 2, cellWidth, cellWidth, this);
364                        }
365                        else if (status == REVEALED)
366                        {
367                                g.setColor(Color.gray);
368                                g.fillRect(0, 0, cellWidth + cellMargin, cellWidth + cellMargin);
369                        }
370                }
371        }
372        /**
373         * Instance of a BufferedImage for use with the game.
374         * @author Bradley Ross
375         * @see javax.imageio.ImageIO#read(InputStream)
376         *
377         */
378        protected class ImageInstance
379        {
380                /**
381                 * Image to be displayed as part of game.
382                 */
383                protected BufferedImage instance = null;
384                /**
385                 * Getter for image
386                 * @return Image
387                 */
388                public BufferedImage getImage()
389                { return instance; }
390                /**
391                 * Setter for image.
392                 * @param value Image to be used.
393                 */
394                public void setImage(BufferedImage value)
395                { instance = value; }
396                /**
397                 * URL indicating the location of the image for the
398                 * tile.
399                 * @see #getImageLocation()
400                 * @see #setImageLocation(URL)
401                 */
402                protected URL imageLocation;
403                public URL getImageLocation()
404                { return imageLocation; }
405                public void setImageLocation(URL value)
406                { imageLocation = value; }
407                /**
408                 * URL indicating the location of the web page describing
409                 * the image on the tile.
410                 * @see #getDescLocation()
411                 * @see #setDescLocation(URL)
412                 */
413                protected URL descLocation;
414                public URL getDescLocation()
415                { return descLocation; }
416                public void setDescLocation(URL value)
417                { descLocation = value; }
418                /** 
419                 * Index in {@link #tileList} of first location of image.
420                 */
421                protected int firstLocation = -1;
422                /**
423                 * Getter for firstLocation.
424                 * @return Index in tileList of first location of image.
425                 */
426                public int getFirstLocation()
427                { return firstLocation; }
428                /**
429                 * Setter for firstLocation.
430                 * 
431                 * @param value Index in tileList to be used for first location of image.
432                 */
433                public void setFirstLocation(int value)
434                { firstLocation = value; }
435                /**
436                 * Index in {@link #tileList} of second location of image.
437                 */
438                protected int secondLocation = -1;
439                /** 
440                 * Getter for secondLocation
441                 * @return Index in tileList of second location of image
442                 */
443                public int getSecondLocation()
444                { return secondLocation; }
445                /**
446                 * Setter for secondLocation
447                 * @param value Index in tileList to be used for second location of image
448                 */
449                public void setSecondLocation(int value)
450                { secondLocation = value; }
451                /*
452                 * Constructor for imageInstance defining file for image.
453                 * @param source File containing image
454                 */
455                public ImageInstance (File source)
456                {
457                        try 
458                        {
459                                instance = javax.imageio.ImageIO.read(new FileInputStream(source));
460                        } 
461                        catch (FileNotFoundException e) 
462                        {
463                                logMessage("Unable to find file while " +
464                                " instantiating ImageInstance");
465                                logMessage(e.getClass().getName() + " : " +
466                                                e.getMessage());
467                                e.printStackTrace();
468                        } 
469                        catch (IOException e) 
470                        {
471                                logMessage(e.getClass().getName() + " : " + 
472                                                e.getMessage());
473                                e.printStackTrace();
474                        }
475                }
476                public ImageInstance (BufferedImage image)
477                {
478                        instance = image; 
479
480                }
481                /**
482                 * Deprecated constructor.
483                 * @param width Width of image in pixels
484                 * @param height Height of image in pixels
485                 * @param source Source of image
486                 * @deprecated
487                 */
488                public ImageInstance (int width, int height, File source)
489                {
490                        try 
491                        {
492                                instance = javax.imageio.ImageIO.read(new FileInputStream(source));
493                        } 
494                        catch (FileNotFoundException e) 
495                        {
496                                System.out.println(e.getClass().getName() + " : " +
497                                                e.getMessage());
498                                e.printStackTrace();
499                        } 
500                        catch (IOException e) 
501                        {
502                                System.out.println(e.getClass().getName() + " : " + 
503                                                e.getMessage());
504                                e.printStackTrace();
505                        }
506                }
507        } 
508        /** 
509         * Playing area for the Concentration game.
510         * @author Bradley Ross
511         *
512         */
513        protected class GamePanel extends JPanel implements MouseListener
514        {
515                /**
516                 * For compliance with Serializable interface,
517                 */
518                private static final long serialVersionUID = 1L;
519                /**
520                 * The constructor for GamePanel instantiates the individual tiles
521                 * on the game panel.
522                 * <p>This is where the randomization of the order of the images
523                 *    would be carried out.</p>
524                 *    @see RandomHelpers
525                 */
526                public GamePanel()
527                {
528                        super();
529                        logMessage("Constructing GamePanel object"); 
530                        layout = new GridLayout(0, tilesWidth, 0, 0);
531                        layout.setHgap(0);
532                        layout.setVgap(0);
533                        numberRemaining = tilesWidth * tilesHeight;
534                        setBackground(Color.gray);
535                        setLayout(layout);
536                        tileList = new Tile[tilesWidth * tilesHeight];
537                        int imageOrder[] = RandomHelpers.createRandomOrder(imageList.size());
538                        int tileOrder[] = RandomHelpers.createRandomOrder(tilesWidth * tilesHeight);
539                        logMessage("There are " + Integer.toString(imageList.size()) +
540                        " images");
541                        logMessage("There are " + Integer.toString(tileList.length) +
542                        " tiles");
543                        for (int i = 0; i < tilesHeight * tilesWidth; i++)
544                        {
545                                int select = tileOrder[i];
546                                tileList[i] = new Tile(i);
547                                int imageSelect = imageOrder[select / 2];
548                                tileList[i].setImageNumber(imageOrder[select / 2]);
549                                add(tileList[i]);
550                                if (select % 2 == 0)
551                                { imageList.elementAt(imageSelect).setFirstLocation(i); }
552                                else
553                                { imageList.elementAt(imageSelect).setSecondLocation(i); }
554                                tileList[i].setStatus(Tile.INITIAL);
555                        }
556                
557                        logMessage("Constructor for gamePanel now complete"); 
558                }
559                /**
560                 * Actions upon winning game.  I may have to place the processes in a separate
561                 * thread, because any sleep operations in this class seems to shut down the 
562                 * entire applet.
563                 */
564                
565                void reward()
566                {
567                        int tiles = tilesWidth * tilesHeight;
568                        logMessage("Reward started " + new Date().toString());  
569                        for (int i = 0; i < tiles; i++)
570                        { tileList[i].setStatus(Tile.IMAGE); }
571                }
572                
573                /**
574                 * Executed when tile is clicked.
575                 */
576                public void mouseClicked(MouseEvent e)
577                {
578                        if (numberRemaining < 2)
579                        {
580                                randomize();
581                                // paintChildren(getGraphics());
582                                return; 
583                        }
584                        Tile source = (Tile) e.getSource();
585                        if (numberShowing == 0 && source.getStatus() == Tile.INITIAL)
586                        {
587                                firstShowing = source.getCounter();
588                                source.setStatus(Tile.IMAGE);
589                                numberShowing = 1;
590                        }
591                        else if (numberShowing == 0 && source.getStatus() == Tile.IMAGE)
592                        {
593                                if (debugLevel > 0)
594                                {
595                                        logMessage("Aplication error");
596                                }
597                                System.exit(1);
598                        }
599                        else if (numberShowing == 0 && source.getStatus() == Tile.REVEALED)
600                        { ; }
601                        else if (numberShowing == 1 && source.getStatus() == Tile.INITIAL)
602                        {
603                                secondShowing = source.getCounter();
604                                source.setStatus(Tile.IMAGE);
605                                numberShowing = 2;
606                        }
607                        else if (numberShowing == 1 && (source.getStatus() == Tile.IMAGE ||
608                                        source.getStatus() == Tile.REVEALED))
609                        {
610                                tileList[firstShowing].setStatus(Tile.INITIAL);
611                                numberShowing = 0;
612                                firstShowing = -1;
613                        }
614                        else if (numberShowing == 2 && (source.getStatus() == Tile.IMAGE ||
615                                        source.getStatus() == Tile.REVEALED))
616                        {
617                                if (tileList[firstShowing].getImageNumber() == tileList[secondShowing].getImageNumber())
618                                {
619                                        tileList[firstShowing].setStatus(Tile.REVEALED);
620                                        tileList[secondShowing].setStatus(Tile.REVEALED);               
621                                        numberRemaining = numberRemaining - 2;
622                                }
623                                else
624                                {
625                                        tileList[firstShowing].setStatus(Tile.INITIAL);
626                                        tileList[secondShowing].setStatus(Tile.INITIAL);
627                                }       
628                                firstShowing = -1;
629                                secondShowing = -1;
630                                numberShowing = 0;
631                        }
632                        else if (numberShowing == 2 && source.getStatus() == Tile.INITIAL)
633                        {
634                                if (tileList[firstShowing].getImageNumber() == tileList[secondShowing].getImageNumber())
635                                {
636                                        tileList[firstShowing].setStatus(Tile.REVEALED);
637                                        tileList[secondShowing].setStatus(Tile.REVEALED);
638                                        source.setStatus(Tile.IMAGE);
639                                        numberRemaining = numberRemaining - 2;
640                                }
641                                else
642                                {
643                                        tileList[firstShowing].setStatus(Tile.INITIAL);
644                                        tileList[secondShowing].setStatus(Tile.INITIAL);
645                                        source.setStatus(Tile.IMAGE);
646                                }       
647                                tileList[firstShowing].repaint(100l);
648                                tileList[secondShowing].repaint(100l);
649                                source.repaint(100l);
650                                firstShowing = source.getCounter();
651                                secondShowing = -1;
652                                numberShowing = 1;
653                        }
654                        else
655                        {
656                                System.out.println("Unknown case");
657                        }
658                        // this.repaint(100l);
659                        logMessage(Integer.toString(source.getCounter()) + " clicked - " +
660                                        Integer.toString(numberShowing) + " showing - " +
661                                        "Squares: (" +
662                                        Integer.toString(firstShowing) + ", " +
663                                        Integer.toString(secondShowing) + "), Remaining: " +
664                                        Integer.toString(numberRemaining));
665                        if (numberRemaining < 2)
666                        {                       
667                                logMessage("Puzzle has been solved " + new Date().toString());  
668                                reward();
669                        }       
670                }
671                /** 
672                 * Required for implementing MouseListener interface.
673                 * 
674                 */
675                public void mouseEntered(MouseEvent e)
676                { ; }
677                /**
678                 * Required for implementing MouseListener interface.
679                 */
680                public void mouseExited(MouseEvent e)
681                { ; }
682                /**
683                 * Required for implementing MouseListener interface.
684                 */
685                public void mousePressed(MouseEvent e)
686                { ; }
687                /**
688                 * Required for implementing MouseListener interface.
689                 */
690                public void mouseReleased(MouseEvent e)
691                { ; }
692                /**
693                 * Allows tracking and manipulation of paintComponents calls.
694                 */
695                public void paintComponents(Graphics g)
696                {
697                        logMessage("paintComponents triggered for game panel - " +
698                                        new Date().toString());
699                        super.paintComponents(g);
700                }
701                /**
702                 * Allows tracking and manipulation of requests to repaint panel.
703                 */
704                public void repaint()
705                {
706                        logMessage("Repaint requested for game panel : " +
707                                        new Date().toString());
708                        super.repaint();
709                }
710                /**
711                 * Randomize order of tiles and reset to initial conditions.
712                 */
713                public void randomize()
714                {
715                        logMessage("Starting randomize");
716                        int imageOrder[] = RandomHelpers.createRandomOrder(imageList.size());
717                        int tileOrder[] = RandomHelpers.createRandomOrder(tilesWidth * tilesHeight);
718                        logMessage("There are " + Integer.toString(imageList.size()) +
719                        " images");
720                        logMessage("There are " + Integer.toString(tileList.length) +
721                        " tiles");
722                        for (int i = 0; i < tilesHeight * tilesWidth; i++)
723                        {
724                                int select = tileOrder[i];
725                                int imageSelect = imageOrder[select / 2];
726                                tileList[i].setImageNumber(imageOrder[select / 2]);
727                                if (select % 2 == 0)
728                                { imageList.elementAt(imageSelect).setFirstLocation(i); }
729                                else
730                                { imageList.elementAt(imageSelect).setSecondLocation(i); }
731                                tileList[i].setStatus(Tile.UNKNOWN);
732                                tileList[i].setStatus(Tile.INITIAL);
733                        }
734                        firstShowing = -1;
735                        secondShowing = -1;
736                        numberShowing = 0;
737                        numberRemaining = tilesWidth * tilesHeight;
738                }       
739        } /* End of gamePanel */
740        /** 
741         * Panel for displaying diagnostic listings when debugLevel greater than 0.
742         * @author Bradley Ross
743         *
744         */
745        protected class secondPanel extends JPanel implements ActionListener, AdjustmentListener
746        {
747                /**
748                 * Dummy field to satisfy Serializable interface.
749                 */
750                private static final long serialVersionUID = 1L;
751                /**
752                 * Button used to reset game by randomizing positions of tiles
753                 * and showing card backs for all squares.
754                 */
755                protected JButton resetButton = new JButton("Reset Game");
756                /** 
757                 * Button used to clear text area.
758                 */
759                protected JButton clearButton = new JButton("Clear Text");
760                /**
761                 * Scrolling area containing the text area.
762                 */
763                protected JScrollPane scrollPane = null;
764                /**
765                 * Vertical scroll bar for the scrolling pane.
766                 */
767                protected JScrollBar scrollBar = null;
768                /**
769                 * Used for debugging messages.
770                 */
771                JTextArea textBlock = null;
772                /** 
773                 * Object containing bounds and values for vertical scroll bar.
774                 */
775                protected BoundedRangeModel rangeModel = null;
776                /**
777                 * Add a message to the text area and move the scroll bar to the
778                 * bottom of the scrolling area.
779                 * <p>Since the upper bound of the vertical scrollbar setting is constantly
780                 *    changing as material is added to the box, it is necessary to get the
781                 *    current maximum value of the scroll bar setting.</p>
782                 * @param text Text to be added
783                 */
784                public void writeMessage(String text)
785                {
786                        textBlock.append(text);
787                        scrollBar.setValue(scrollBar.getModel().getMaximum() - scrollBar.getModel().getExtent());
788                }
789                public secondPanel()
790                {
791                        JPanel buttons = new JPanel();
792                        buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS));
793                        this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
794                        textBlock = new JTextArea(10, 50);
795                        resetButton.setName("reset");
796                        clearButton.setName("clear");
797                        buttons.add(resetButton);
798                        buttons.add(clearButton);
799                        add(buttons);
800                        scrollPane = new JScrollPane(textBlock);
801                        scrollBar = scrollPane.getVerticalScrollBar();
802                        rangeModel = scrollBar.getModel();
803                        add(scrollPane);
804                        textBlock.setVisible(true);
805                        resetButton.addActionListener(this);
806                        clearButton.addActionListener(this);
807                        scrollBar.addAdjustmentListener(this);
808                        textBlock.setText((String) null);
809                        // scrollBar.setValue(rangeModel.getMinimum());
810                        writeMessage("Minimum: " + Integer.toString(rangeModel.getMinimum()) + "  " +
811                                        " Maximum: " + Integer.toString(rangeModel.getMaximum()) + "\n");
812                        writeMessage("Extent: " + Integer.toString(rangeModel.getExtent()) +
813                                        " Value: " + Integer.toString(rangeModel.getValue()) + "\n");
814                }
815                /**
816                 * Take action when button is clicked.
817                 * @param e Action event generated when button is clicked
818                 */
819                public void actionPerformed(ActionEvent e)
820                {
821                        if (e.getSource() == (Object) resetButton)
822                        {
823                                logMessage("Reset button clicked");
824                                gamePanel.randomize();
825                        }
826                        else if (e.getSource() == (Object) clearButton)
827                        {
828                                textBlock.setText((String) null);
829                                logMessage("Clear button clicked");
830                                writeMessage("Minimum: " + Integer.toString(rangeModel.getMinimum()) + "  " +
831                                                " Maximum: " + Integer.toString(rangeModel.getMaximum()) + "\n");
832                                writeMessage("Extent: " + Integer.toString(rangeModel.getExtent()) +
833                                                " Value: " + Integer.toString(rangeModel.getValue()) + "\n");
834                                try 
835                                {
836                                        Thread.sleep(1);
837                                } 
838                                catch (InterruptedException e1) 
839                                {
840                                        e1.printStackTrace();
841                                }
842                                writeMessage("Minimum: " + Integer.toString(rangeModel.getMinimum()) + "  " +
843                                                " Maximum: " + Integer.toString(rangeModel.getMaximum()) + "\n");
844                                writeMessage("Extent: " + Integer.toString(rangeModel.getExtent()) +
845                                                " Value: " + Integer.toString(rangeModel.getValue()) + "\n");
846                        }
847                }
848                /**
849                 * Action to be taken when the scrollbar is used to move within the scrolling
850                 * area.
851                 * @param e Event representing action to be monitored
852                 */
853                public void adjustmentValueChanged(AdjustmentEvent e)
854                {
855                        if (debugLevel < 10) { return; }
856                        if (e.getValueIsAdjusting()) { return; }
857                        textBlock.append(" " + Integer.toString(e.getValue()) + " ");
858                }
859        }
860        GridLayout layout = null;
861        /**
862         * Number of tiles currently displaying picture. 
863         */
864        protected int numberShowing = 0;
865        /**
866         * Index in tileList of first tile displaying picture.
867         */
868        protected int firstShowing = -1;
869        /** Index in tileList of second tile displaying picture. */
870        protected int secondShowing = -1;
871        BufferedImage image1 = null;
872        BufferedImage image2 = null;
873        /**
874         * Constructor .
875         * @param width number of tiles per row
876         * @param height number of rows
877         */
878        public Concentration(int width, int height)
879        {
880                tilesWidth = width;
881                tilesHeight = height;
882                game = this;
883        }
884        /**
885         * Default constructor.
886         */
887        public Concentration()
888        {
889
890                logMessage("Running constructor without parameters - " + new Date().toString()); 
891                game = this;
892                tilesWidth = 6;
893                tilesHeight = 6;
894
895        }
896        /**
897         * Construct a dummy image.
898         * @param value number to go in cell
899         * @return Image
900         */
901        protected BufferedImage buildTestImage (int value)
902        {
903                BufferedImage image = new BufferedImage(cellWidth + cellMargin, cellWidth + cellMargin, BufferedImage.TYPE_3BYTE_BGR);
904                Graphics g = image.getGraphics();
905                g.setColor(Color.white);
906                g.fillRect(0, 0, 110, 110);
907                g.setColor(Color.blue);
908                g.fillRect (5, 5, 100, 100);
909                g.setColor(Color.lightGray);
910                g.fillRect ( 20, 20, 60, 60);
911                g.setColor(Color.blue);
912                g.fillRect(30, 30, 40, 40);
913                g.drawString(Integer.toString(value), 60, 60);
914                return image;
915        }       
916        /** 
917         * Executed when being called as applet.
918         */
919        public void init()
920        {
921                if (appletMode && debugLevel > 0)
922                { System.out.println("Running in applet mode"); }
923                else if (!appletMode && debugLevel > 0)
924                { System.out.println("Not running in applet mode"); }
925                if (appletMode)
926                {
927                        String value = null;
928                        value = getParameter("ImageList");
929                        if (value != null)
930                        {
931                                imageListUrl = value;
932                        }
933                        else
934                        {
935                                imageListUrl = "images.txt";
936                        }
937                        value = null;
938                        value = getParameter("CellWidth");
939                        if (value != null)
940                        {
941                                cellWidth = Integer.parseInt(value);
942                        }
943                        value = null;
944                        value = getParameter("CellMargin");
945                        if (value != null)
946                        {
947                                cellMargin = Integer.parseInt(value);
948                        }
949                        value = null;
950                        value = getParameter("Debug");
951                        int working = debugLevel;
952                        if (value != null)
953                        {
954                                try
955                                {
956                                        working = Integer.parseInt(value);
957                                }
958                                catch (Exception e)
959                                { working = debugLevel; }
960                                debugLevel = working;
961                        }
962                }
963                if (debugLevel > 0)
964                {
965                        debugFrame = new JFrame();
966                        debugPanel = new secondPanel();
967                        debugFrame.add(debugPanel);
968                        debugPanel.setVisible(true);
969                        logMessage("Debugging History\n");
970                        debugFrame.setSize(new Dimension(700, 700));
971                        debugFrame.setVisible(true);
972                        logMessage("DebugLevel is " + Integer.toString(debugLevel));
973                }
974                contentPane = getContentPane();
975                game = this;
976                image1 = new BufferedImage(110, 110, BufferedImage.TYPE_3BYTE_BGR);
977                Graphics g = image1.getGraphics();
978                g.setColor(Color.red);
979                g.fillRect (cellMargin / 2, cellMargin / 2, cellWidth, cellWidth);
980                /*
981                g.setColor(Color.pink);
982                g.fillRect ( 20, 20, 70, 70);
983                 */
984                g.setColor(Color.gray);
985                if (appletMode)
986                { 
987                        imageRoot = getDocumentBase(); 
988                
989                                logMessage("Document base is " + imageRoot.toString()); 
990                        
991                }
992                else 
993                { imageRoot = null; }
994
995                try 
996                {
997                        URL temp = new URL(imageRoot, imageListUrl);
998                        String list = FileHelpers.readTextFile(temp);
999                        StringReader input = new StringReader(list);
1000                        LineNumberReader reader = new LineNumberReader(input);
1001                        String line = null;
1002                        while (true)
1003                        {
1004                                line = reader.readLine();
1005                                if (line == null) {break; }
1006                                tempRead1(line);
1007                        }
1008                } 
1009                catch (MalformedURLException e) 
1010                {
1011                        e.printStackTrace();
1012                }
1013                catch (IOException e)
1014                {
1015                        e.printStackTrace();
1016                }
1017
1018                // tempRead2();
1019                gamePanel = new GamePanel();
1020                for (int i = 0; i < tilesWidth * tilesHeight; i++)
1021                { tileList[i].addMouseListener((MouseListener) gamePanel); }
1022                contentPane.add(gamePanel);
1023                logMessage("Init procedure complete");
1024
1025        }
1026        /**
1027         * Restart the game.
1028         
1029        public void restart()
1030        {
1031                logMessage("*****  *****  Restart triggered");
1032                tileList = new Tile[tilesWidth*tilesHeight];
1033                imageList = new Vector<ImageInstance>(); 
1034                try 
1035                {
1036                        URL temp = new URL(imageRoot, imageListUrl);
1037                        String list = FileHelpers.readTextFile(temp);
1038                        StringReader input = new StringReader(list);
1039                        LineNumberReader reader = new LineNumberReader(input);
1040                        String line = null;
1041                        while (true)
1042                        {
1043                                line = reader.readLine();
1044                                if (line == null) {break; }
1045                                tempRead1(line);
1046                        }
1047                } 
1048                catch (MalformedURLException e) 
1049                {
1050                        logMessage("Malformed URL while reading image");
1051                        e.printStackTrace();
1052                }
1053                catch (IOException e)
1054                {
1055                        logMessage("IOException while reading image");
1056                        e.printStackTrace();
1057                }
1058                contentPane.removeAll();
1059                gamePanel = new GamePanel();
1060                for (int i = 0; i < tilesWidth * tilesHeight; i++)
1061                { 
1062                        tileList[i].addMouseListener((MouseListener) gamePanel); 
1063                }
1064                contentPane.add(gamePanel);
1065                logMessage("Restart finished");
1066                
1067        }
1068*/
1069        /**
1070         * Remove the debugging window if debugLevel was greater than 0.
1071         */
1072        public void stop()
1073        {
1074                if (debugLevel > 0)
1075                { 
1076                        logMessage("Entering stop method\n");
1077                        debugFrame.setVisible(false);
1078                        debugFrame.dispose(); 
1079                }
1080        }
1081        /**
1082         * Processes an image. }.
1083         * @param item File name to be processed
1084         */
1085        protected void tempRead1(String item)
1086        {
1087                if (!appletMode)
1088                {
1089                        String fullName = "/Applications/Tomcat/webapps/test/" + item;
1090                        imageList.add(new ImageInstance(new File(fullName)));
1091                }
1092                else if (appletMode)
1093                {
1094                        // imageList.add(new ImageInstance(image1));
1095
1096                        try 
1097                        {
1098                                imageList.add(new ImageInstance(ImageIO.read(new URL(imageRoot, item ))));
1099                        } 
1100                        catch (MalformedURLException e) 
1101                        {
1102                                logMessage("Unable to parse " + imageRoot.toString() + " : " +
1103                                                item + " - Malformed URL exception");
1104
1105                                e.printStackTrace();
1106                        } 
1107                        catch (IOException e) 
1108                        {
1109                                logMessage("Unable to parse " + imageRoot.toString() + " : " +
1110                                                item + " - IO exception");
1111
1112                                e.printStackTrace();
1113                        }
1114                }
1115                logMessage(item + " processed"); 
1116        }
1117}