import java.awt.*;
import java.awt.event.*;

/**
    A simple component, draws Stars, which are animated in a separate thread which
    can be start()ed or stop()ped.
    @author Dave Burt
    @version 1.0 19 April 2002
 */
public class StarPanel
    extends Canvas
    implements Runnable
{
    private static final int DELAY_MILLIS = 10;
    private Star[] stars;
    private Thread runThread;
    
    public StarPanel(int maxStars)
    {
        System.out.println(Thread.currentThread().getName() + " - StarPanel.StarPanel()");
        setBackground(Color.black);
        
        stars = new Star[maxStars];
        for (int i = 0; i < maxStars; i++)
        {
            stars[i] = new Star();
        }
    }
    
    public void start()
    {
        System.out.println(Thread.currentThread().getName() + " - void StarPanel.start()");
        runThread = new Thread(this);
        runThread.start();
    }
    public void stop()
    {
        System.out.println(Thread.currentThread().getName() + " - void StarPanel.stop()");
        runThread.interrupt();
        runThread = null;
    }
    
    public void run()
    {
        System.out.println(Thread.currentThread().getName() + " - void StarPanel.run()");
        try
        {
            while (!runThread.interrupted())
            {
                for (int i = 0; i < stars.length; i++)
                {
                    stars[i].move();
                    if (!stars[i].isValid())
                        stars[i] = new Star();
                }
                repaint();
                Thread.yield();
                Thread.sleep(DELAY_MILLIS);
            }
        }
        catch (InterruptedException e) {}
    }
    
    public void paint(Graphics g)
    {
        //System.out.println(Thread.currentThread().getName() + " - void StarPanel.paint()");
        super.paint(g);
        g.setColor(Color.white);
        int x, y, size;
        for (int i = 0; i < stars.length; i++)
        {
            x = (int) (stars[i].getX() * getSize().width);
            y = (int) (stars[i].getY() * getSize().height);
            size = (int) stars[i].getSize();
            g.fillOval(x, y, size, size);
        }
    }
    
    public static void main(String[] args)
    {
        System.out.println(Thread.currentThread().getName() + " - static void StarPanel.main()");
        Frame f = new Frame();
        StarPanel sp = new StarPanel(50);
        f.setTitle("Starsim");
        f.setSize(400,400);
        f.add(sp);
        f.addWindowListener(new WindowAdapter()
            {
                public void windowClosed(WindowEvent e)
                {
                    System.out.println(Thread.currentThread().getName());
                    System.exit(0);
                }
            });
        f.show();
        sp.start();
    }
}

/**
    A point moving away from the center of its (0,0)-(1,1) box
    @author Dave Burt
    @version 1.0 19 April 2002
 */
class Star
{
    private static final double SPEED_INIT = 0.01;
    private static final double SPEED_INC = 1.1;
    private static final double SIZE_INIT = 1.0;
    private static final double SIZE_INC = 1.05;
    private static final double SIZE_MAX = 10;
    
    private double x, y;
    private double dx, dy;
    private double size = SIZE_INIT;
    
    public Star()
    {
        x = Math.random();
        y = Math.random();
        dx = (x - 0.5) * SPEED_INIT; // try (x-0.5)**3
        dy = (y - 0.5) * SPEED_INIT;
    }
    
    public void move()
    {
        //move(1.0);
        x += dx;
        y += dy;
        dx *= SPEED_INC;
        dy *= SPEED_INC;
        size *= SIZE_INC;
    }
    public void move(double increment)
    {
        x += dx * increment;
        y += dy * increment;
        dx *= Math.pow(SPEED_INC, increment);
        dy *= Math.pow(SPEED_INC, increment);
        size *= Math.pow(SIZE_INC, increment);
    }
    
    public double getX() { return x; }
    public double getY() { return y; }
    public double getSize() { return size; }
    
    /**
        @return false if this Star has moved out of bounds; true otherwise
     */
    public boolean isValid()
    {
        return x >= 0 && x <= 1
            && y >= 0 && y <= 1
            && (size < SIZE_MAX);
    }
    
}
