import  java.awt.*;
import  java.awt.event.*;
import  javax.swing.*;
import  javax.swing.border.*;

/**
 * A GUI application with start and stop buttons
 * that control a small animation of a moving block
 * 
 * @author Sharon Tuttle
 * @version 2015-10-21
 */

public class BlockThread1
{
    /**
     * creates a BlockThread1Frame
     * 
     * @param args not used here
     */
    
    public static void main(String args[])
    { 
        EventQueue.invokeLater(
            new Runnable()
            {
                public void run()
                {
                    BlockThread1Frame mainFrame = new BlockThread1Frame();
                    mainFrame.setDefaultCloseOperation( 
                        JFrame.EXIT_ON_CLOSE );    
                    mainFrame.setVisible(true); 
                }
            });
    }
}

/** 
 * A frame that passes on its size to the JPanel
 * subclass instance it adds to itself
 */

class BlockThread1Frame extends JFrame
{
    // data fields
    
    private final static int DEFAULT_WIDTH = 450;
    private final static int DEFAULT_HEIGHT = 200;
    
    /**
     * constructs a BlockThread1Frame instance
     */
    
    public BlockThread1Frame()
    {    
        this.setTitle("BlockThread1");
        this.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);

        // add BlockThread1 panel to frame
        
        BlockThread1Panel panel = 
            new BlockThread1Panel(DEFAULT_WIDTH, DEFAULT_HEIGHT);
        this.add(panel);
    }
}

/**
 * a JPanel subclass has a subpanel with an animation
 * that can be started and stopped
 */

class BlockThread1Panel extends JPanel
{
    // data fields
    
    private final static Font DISPLAY_FONT = 
        new Font("Dialog", Font.PLAIN, 20);
    
    // info about the block to be animated
    
    private int blockX;
    private int blockY;
    
    private static final int BLOCK_WIDTH = 40;
    private static final int BLOCK_HEIGHT = 20;
    private static final Color BLOCK_COLOR = Color.RED;
    
    // info about the panel's rough size
    
    private int displayWidth;
    private int displayHeight;
    
    private Thread paintThread;
    private PaintItRunnable myPaintIt;
    
    /**
     * set up display parameters and a Runnable instance
     * for eventually moving a block around
     *
     * @param width desired display width, in pixels
     * @param height desired display height, in pixels
     * 
     */
    
    public BlockThread1Panel(int width, int height)
    {
        this.setLayout(new BorderLayout());
        
        // I am putting buttons in the bottom of this
        //    panel -- so the display sub-panel is going
        //    to be shorter than the frame's height
        // (hmm; three times the buttons' DISPLAY_FONT size, maybe?)
        
        BlockPanel aBlockPanel = new BlockPanel(
            width,
            height - (3 * DISPLAY_FONT.getSize()));
        this.add(aBlockPanel, BorderLayout.CENTER);
        
        // putting buttons to start and stop the animation
        //    thread in the bottom/page_end of the panel
        
        JPanel buttonPanel = new JPanel();
        
        JButton beginButton = new JButton("Begin");
        beginButton.setFont(DISPLAY_FONT);
        beginButton.addActionListener(new BeginThread());
        buttonPanel.add(beginButton);
        
        JButton endButton = new JButton("End");
        endButton.setFont(DISPLAY_FONT);
        endButton.addActionListener(new EndThread());
        buttonPanel.add(endButton);
        
        this.add(buttonPanel, BorderLayout.PAGE_END);
    }
    
    /**
     * this subpanel is the one that will actually have
     * a block painted on it
     */
    
    private class BlockPanel extends JPanel
    {
        /**
         * construct a new BlockPanel
         * 
         * @param width new BlockPanel's desired displayWidth
         * @param height new BlockPanel's desired displayHeight
         */
        
        public BlockPanel(int width, int height)
        {
            displayWidth = width;
            displayHeight = height;
            
            // start out the block in about the middle of the screen
            
            blockX = (int) (displayWidth / 2.0);
            blockY = (int) (displayHeight / 2.0); 
            
            myPaintIt = new PaintItRunnable();
            
            // I am not creating paintThread yet -- want to wait
            //    until begin button is pushed (so I can 
            //    recreate it more than once
        }
        
        /**
         * paint/draw a block on this panel
         * 
         * @param g the Graphics object with the needed settings
         */
        
        public void paintComponent(Graphics g)
        {
            // calling parent JPanel's version of paintComponent
            //     to take care of painting the background, etc.
            
            super.paintComponent(g);
            
            // painting a red block at the current blockX, blockY
            //     values
            
            g.setColor(BLOCK_COLOR);
            g.fillRect(blockX, blockY, BLOCK_WIDTH, BLOCK_HEIGHT);
        }
    }
    
    /** 
     * this is to move the block across the BlockPanel
     */
    
    private class PaintItRunnable implements Runnable
    {
        /**
         * "move" the block across the BlockPanel
         */
        
        public void run()
        {
            boolean finished = false;
            
            // until interrupted, "move" the block right 5 pixels about
            //     every .1 second until run out of panel -- then start
            //     back at the left side
            
            while (!finished)
            {
                try
                {
                    // go right 5 pixels, unless have gone beyond
                    //     the right side of the panel - then start
                    //     back at the left side
                    
                    if (blockX < displayWidth)
                    {
                        blockX += 5;
                    }
                    else
                    {
                        blockX = 0;
                    }
                    
                    repaint();
                    
                    // notice: we are sleeping in this "new"
                    //    Thread, not the event dispatch thread
                    
                    Thread.sleep(100);
                }
                catch (InterruptedException exc)
                {
                    finished = true;
                }
            }
        }
    }
    
    /**
     * start up a new animation thread
     */
    
    private class BeginThread implements ActionListener
    {
        /**
         * if there is currently not an animation thread,
         *     create one and start it up
         * 
         * @param event click of the Begin button
         */
        
        public void actionPerformed(ActionEvent event)
        {
            // only create a new animation thread if there
            //     is not one right now
            
            if (paintThread == null)
            {
                paintThread = new Thread(myPaintIt);
                paintThread.start();
            }
        }
    }
    
    /**
     * end the animation thread
     */
    
    private class EndThread implements ActionListener
    {
        /**
         * if there currently is an animation thread,
         *     request that it end
         * 
         * @param event click of the End button
         */
        
        public void actionPerformed(ActionEvent event)
        {
            // if an animation thread is running, request
            //     that it end and make the animation thread
            //     data field point to nothing
            
            if (paintThread != null)
            {   
                paintThread.interrupt();
                paintThread = null;
            }
        }
    }
}