import javax.swing.*;

import java.awt.*;
import java.awt.event.*;

public class BubbleSort2 extends JPanel implements Runnable, ActionListener {
	private int[] args = new int[12];
	private final Color[] cs = {Color.RED, Color.ORANGE, Color.GREEN, Color.BLUE};
	private volatile Thread thread = null;
	private int i, j;
	private volatile boolean threadSuspended = true;
	
	public BubbleSort2() {
		setPreferredSize(new Dimension(320, 250));
		JButton step = new JButton("Step");
		step.addActionListener(this);
		setLayout(new FlowLayout());
		add(step);
		startThread();
	}
	
	private void startThread() {
		if (thread == null) {
			thread = new Thread(this);
			thread.start();
		}
	}

	public synchronized void actionPerformed(ActionEvent e) {
		threadSuspended = false;
		notify();
	}

	@Override
	public void paintComponent(Graphics g) {
		int k;
		
		super.paintComponent(g);
		g.setColor(Color.YELLOW);
		g.fillOval(5, 50 + j * 10, 10, 10);
		g.setColor(Color.CYAN);
		g.fillOval(5, 50 + i * 10, 10, 10);
		for (k = 0; k < args.length; k++) {
			g.setColor(cs[k % cs.length]);
			g.fillRect(20, 50 + k * 10, args[k] * 5, 10);
		}
	}

	private void prepareRandomData() {
		int len = args.length;
		for (int k = 0; k < len; k++) { 
			args[k] = (int)(Math.random() * len * 4);  // 適当な範囲の乱数
		}
	}
	
	public void run() {
		while(true) {
			prepareRandomData();
			// バブルソートアルゴリズム
			for (i = 0; i < args.length - 1; i++) {
				for (j = args.length - 1; j > i; j--) {
					if (args[j - 1] > args[j]) { // スワップする。
						int tmp = args[j - 1];
						args[j - 1] = args[j];
						args[j] = tmp;
					}
					repaint();
					/* repaint の後で止まる */
					try {
						synchronized(this) {
							while (threadSuspended) {
								wait();
							}
							threadSuspended = true;
						}
					} catch (InterruptedException e) {}
				}
			}
		}
	}

	public static void main(String[] args) {
		SwingUtilities.invokeLater(() -> {
			JFrame frame = new JFrame("バブルソート");
			frame.add(new BubbleSort2());
			frame.pack();
			frame.setVisible(true);
			frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		});
	}
}
