/*
 * [TestAnimation.java]
 *
 * Summary: Demonstration of simple animation.
 *
 * Copyright: (c) 2011-2017 Roedy Green, Canadian Mind Products, http://mindprod.com
 *
 * Licence: This software may be copied and used freely for any purpose but military.
 *          http://mindprod.com/contact/nonmil.html
 *
 * Requires: JDK 1.8+
 *
 * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/
 *
 * Version History:
 *  1.0 2011-10-30 initial version
 */
package com.mindprod.example;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * Demonstration of simple animation.
 * <p/>
 * A square bounces diagonally up and down.
 *
 * @author Roedy Green, Canadian Mind Products
 * @version 1.0 2011-10-30 initial version
 * @since 2011-10-30
 */
public final class TestAnimation
    {
    /**
     * how big a square canvas to draw on.
     */
    private static final int CANVAS_SIZE = 300;

    /**
     * interval between painting frames in millis. Note int not long.
     */
    private static final int INTERVAL = 20;

    /**
     * where we draw the bouncing square
     */
    private static Bouncer canvas;

    /**
     * Test harness
     *
     * @param args not used
     */
    public static void main( String[] args )
        {
        // fire up application on the Swing Thread
        SwingUtilities.invokeLater( new Runnable()
            {
            /**
             * do all swing work on the swing thread.
             */
            public void run()
                {
                canvas = new Bouncer();
                canvas.setBackground( new Color( 0xf3fff6 ) /* pale green */ );
                canvas.setForeground( new Color( 0x6495ed ) /* cornflower blue */ );
                JFrame.setDefaultLookAndFeelDecorated( true );
                final JFrame frame = new JFrame( "Bouncing Square" );
                frame.setResizable( false );
                frame.setUndecorated( false );
                frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
                // allow some extra room for the frame title bar.
                frame.setSize( CANVAS_SIZE + 24, CANVAS_SIZE + 64 );
                frame.getContentPane().add( canvas );
                frame.validate();
                frame.setVisible( true );
                // this is a javax.swing.Timer, not to be confused with java.util.Timer;
                final Timer animationTimer = new Timer( INTERVAL, new ActionListener()
                    {
                    /**
                     * invoked whenever Timer triggers
                     * @param e event not used.
                     */
                    public void actionPerformed( ActionEvent e )
                        {
                        canvas.repaint();
                        }
                    } );
                animationTimer.setRepeats( true );
                animationTimer.start();
                } // end run
            } // end Runnable
        );
        } // end main
    }

/**
 * Animated panel used to draw a bouncing square
 */
class Bouncer extends JPanel
    {
    /**
     * how big a border to leave around area we draw bouncing square on, keep out the way of the Frame bar
     */
    private static final int BORDER = 50;

    /**
     * how big the bouncing square is on edge in pixels
     */
    private static final int SQUARE_SIZE = 20;

    /**
     * true if square is moving up, toward smaller values of y
     */
    private boolean ascending = false;

    /**
     * top edge of the square where the square should be now.
     */
    private int newY = BORDER;

    Bouncer()
        {
        // we don't want Swing painting any flicker-causing backgrounds.
        // we want to be responsible for painting the background.
        setOpaque( true );
        }

    /**
     * draws one frame of the animation.
     *
     * @param g where to paint.
     */
    public void paintComponent( Graphics g )
        {
        super.paintComponent( g );
        // how high we should let top edge of square move to
        final int highestPoint = BORDER;
        /// how low we should let top edge of square move to
        final int lowestPoint = getHeight() - BORDER - SQUARE_SIZE;
        // reverse direction when runs off the end.
        final int oldY = newY;
        if ( ascending )
            {
            newY--;  // ascend one pixel
            if ( newY <= highestPoint )
                {
                ascending = false;  // reverse direction
                }
            }
        else
            {
            newY++; // descend one pixel
            if ( newY >= lowestPoint )
                {
                ascending = true;  // reverse direction
                }
            }
        // erase old square. Ideally we would clip to region that does not overlap new square.
        // Swing's double buffering should hide the flicker
        g.setColor( getBackground() );
        g.fillRect( oldY, oldY, SQUARE_SIZE, SQUARE_SIZE );
        // paint new square, one pixel offset.
        g.setColor( getForeground() );
        g.fillRect( newY, newY, SQUARE_SIZE, SQUARE_SIZE );
        }
    }