// PrimeApp.java
// author: Dr. J. Yoder, 2014
// Illustrates using a thread to compute a long result while updating the GUI

import javax.swing.*;
import java.awt.FlowLayout;
import java.util.ArrayList;
import java.util.List;

public class PrimeApp extends JFrame {

   private List<Long> primes = new ArrayList<>();
   private final JLabel statusLabel;
   private Thread worker;

   public static void main(String[] ignored) {
      new PrimeApp();
   }

   public PrimeApp() {
      setSize(800,600);
      setLayout(new FlowLayout());

      statusLabel = new JLabel();
      statusLabel.setText("Latest prime: (none)");
      add(statusLabel);

      JMenuBar bar = new JMenuBar();
      JMenu menu = new JMenu("Actions");
      JMenuItem item = new JMenuItem("Start finding primes");
      item.addActionListener(e -> startPrimes());
      menu.add(item);
      item = new JMenuItem("Stop finding primes");
      item.addActionListener(e -> stopPrimes());
      menu.add(item);
      bar.add(menu);
      setJMenuBar(bar);

      setVisible(true);
   }

   private boolean halted = false;

   public void startPrimes() {
      worker = new Thread(this::findPrimes);
      worker.start();
   }

   public void stopPrimes() {
      worker.interrupt();
   }

   public void findPrimes() {
      long prime;
      for(long candidate = 100000000; 
          candidate < Long.MAX_VALUE && !worker.isInterrupted(); 
          candidate++) {
         if ( isPrime(candidate) ) {
            primes.add(candidate);
            statusLabel.setText("Latest prime: " + candidate);
            System.out.println("Latest prime: " + candidate);
            repaint();
         }
      }
   }

   /**
    * Slow O((2^b)) or worse algorithm (where b is the number of bits in candidate)
    *
    * TODO: Implement Miller-Rabin Primality test to get O(n^12) or better performance.
    * http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test
    *
    * @param prime candidate to test
    * @return true if "prime" really is prime.
    */
   private boolean isPrime(long prime) {
      boolean isPrime = true;
      for (int divisor = 2; divisor < prime && isPrime; divisor++) {
         if ( prime % divisor == 0 ) {
            isPrime = false;
         }
      }
      return isPrime;
   }
}
