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

/**
    a Java Swing application using slight "animation" via a thread

    @author Sharon Tuttle
    @version 2021-10-25
*/

public class ThreadImage1
{
    /**
        creates a simple frame with a panel that can have an image animated
        across it

        @param args is expected to contain a string containing the
           name of a .gif or .jpg or .png image file
    */

    public static void main(String[] args)
    {
        if (args.length != 1)
	{
	    JOptionPane.showMessageDialog(null, "Need 1 argument, " +
					  "a .gif or .jpg or .png file name");
	    System.exit(1);
	}

	// quirk: I may need this so an inner class can see it...?

	final String imageFileName = args[0];
	
        EventQueue.invokeLater(
	    () ->
	       {
                   ThreadImage1Frame mainFrame =
		       new ThreadImage1Frame(imageFileName);
		   mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		   mainFrame.setVisible(true);
	       } );
    }
}

/**
    A frame with a panel that can have an image animated across it
*/

class ThreadImage1Frame extends JFrame
{
    // data fields

    private static final int DEFAULT_WIDTH = 450;
    private static final int DEFAULT_HEIGHT = 200;
    
    /**
        construct a ThreadImage1Frame instance

        @param imgFileName the name of a .gif or .png or .jpg image file
    */

    public ThreadImage1Frame(String imgFileName)
    {
	setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
	setTitle("Animation of YOUR image");

	ThreadImage1Panel mainPanel =
	    new ThreadImage1Panel(imgFileName, DEFAULT_WIDTH, DEFAULT_HEIGHT);
	add(mainPanel);
    }
}

/**
    A panel whose subpanel can have a moving image, provided by the user
*/

class ThreadImage1Panel extends JPanel
{
    // data fields!

    private final static Font DISPLAY_FONT =
	new Font("Dialog", Font.PLAIN, 20);

    private String imgName;
    private ImageIcon myImageIcon;
    private int imageX;
    private int imageY;

    private int displayWidth;
    private int displayHeight;

    private Thread paintThread;
    private Runnable myPaintIt;

    /**
        set up display parameters and a Runnable instance
        for eventually animating a provided image

        @param imgFile the name of a .gif or .jpg ot .png file
        @param width desired display widthm in pixels
        @param height desired display height, in pixels
    */

    public ThreadImage1Panel(String imgFile, int width, int height)
    {
	myPaintIt = null;
	paintThread = null;

	setLayout(new BorderLayout());

	imgName = imgFile;

	// shorter, to compensate for a begin-and-end-buttons-panel
	//    in the South...

	MyImagePanel aMyImagePanel = new MyImagePanel(width, height - 20);
	add(aMyImagePanel, BorderLayout.CENTER);

	JPanel buttonPanel = new JPanel();

	JButton begin = new JButton("Begin");
	begin.setFont(DISPLAY_FONT);
	begin.addActionListener(new BeginThread());
        buttonPanel.add(begin);

	JButton end = new JButton("End");
	end.setFont(DISPLAY_FONT);
	end.addActionListener(new EndThread());
	buttonPanel.add(end);

	add(buttonPanel, BorderLayout.SOUTH);
    }

    /**
        this subpanel will be painted upon!!
    */

    private class MyImagePanel extends JPanel
    {
	/**
            construct a new MyImagePanel

            @param width my new MyImagePanel's desired displayWidth
            @param height my new MyImagePanel's desired displayHeight
	*/

	public MyImagePanel(int width, int height)
	{
	    displayWidth = width;
	    displayHeight = height;

	    // start out the image with its top left corner at (0, 0)

	    imageX = 0;
	    imageY = 0;

	    // one way to create an ImageIcon: call its constructor
	    //    that expects them name of a .png, .jpg, or .gif
	    //    image file

	    myImageIcon = new ImageIcon(imgName);

	    myPaintIt =
		() ->
	        {
		    boolean finished = false;

		    while (!finished)
		    {
			try
			{
			    if (imageX < displayWidth)
			    {
				imageX += 5;
			    }
			    else
			    {
				imageX = 0;
			    }

			    repaint();

			    Thread.sleep(100);
			}
			catch (InterruptedException exc)
			{
			    finished = true;
			}
		    }
		};

	    // NOT creating paintThread yet -- will do when the Begin
	    //    button is clicked, so I can re-create it MORE than once!
	}

	/**
            paints/draws the provided image on this panel
	*/

	public void paintComponent(Graphics g)
	{
	    super.paintComponent(g);

	    // an ImageIcon can be painted on this panel using
	    //    its paintIcon method

	    myImageIcon.paintIcon(this, g, imageX, imageY);
	}
    }

    /**
        action listener to create a new thread (if appropriate) when
        Begin button is clicked
    */

    private class BeginThread implements ActionListener
    {
	/**
            begin a new thread (if appropriate) when Begin button is
            pushed

            @param event not used here
	*/

	public void actionPerformed(ActionEvent event)
	{
	    // if paintThread is not currently running, create
	    //    a new thread and start it up; othwerwise,
	    //    ignore this button push

	    if (paintThread == null)
	    {
		paintThread = new Thread(myPaintIt);
		paintThread.start();
	    }
	}
    }

    /**
        action listener to end the image-moving thread (if appropriate) when
        End button is clicked
    */

    private class EndThread implements ActionListener
    {
	/**
            end the image-moving thread (if appropriate) when End button is
            pushed

            @param event not used here
	*/

	public void actionPerformed(ActionEvent event)
	{
	    // only do something IF there is currently a
	    //    paintThread running -- othwerwise,
	    //    ignore this button push

	    if (paintThread != null)
	    {
                paintThread.interrupt();
		paintThread = null;
	    }
	}
    }
}