import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Deadly5 extends JFrame implements ActionListener {
    private JTextField numField, counterField, statusField;
    private JButton start, stop;
    private Counter c;
    private CountThread c1, c2;
    
    public Deadly5() {
        setTitle("Race Condition");
        setSize(500, 100);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        Container pane = getContentPane();
        pane.setLayout(new FlowLayout());
        
        numField = new JTextField(10);
        pane.add(numField);
        
        start = new JButton("Start Counters");
        start.addActionListener(this);
        pane.add(start);
        
        stop = new JButton("Stop");
        stop.addActionListener(this);
        pane.add(stop);
        
        statusField = new JTextField(10);
        pane.add(statusField);
        
        counterField = new JTextField(20);
        pane.add(counterField);
        
        c = new Counter();
        c1 = c2 = null;
    }
    
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == start && c1 == null && c2 == null) {
            int n = Integer.parseInt(numField.getText());
            c1 = new CountThread(c, 1, n);
            c2 = new CountThread(c, -1, n);
            c1.start();
            c2.start();
            statusField.setText("running...");
        } else if (e.getSource() == stop) {
            if (c1 != null) {c1.interrupt();}
            if (c2 != null) {c2.interrupt();}
            statusField.setText("interrupted");
        }
    }
    
    public void done(CountThread d) {
        if (d == c1) {c1 = null;} else {c2 = null;}
        if (c1 == null && c2 == null) {
            statusField.setText("Finished");
        }
    }
    
    class Counter {
        private long x = 0;
        
        public long getX() {return x;}
        public void increaseX(long incr) {x = x + incr;}
        
        public String toString() {return "Count: " + x;}
    }
    
    class CountThread extends Thread {
        private long incr, total;
        private Counter counter;
        
        public CountThread(Counter c, long i, long n) {
            counter = c;
            incr = i;
            total = n;
        }
        
        public void run() {
            long i = 0;
            try {
                while (!isInterrupted() && i < total) {
                    synchronized(counter) {
                        while (counter.getX() < 0 && incr < 0) {counter.wait();}
                        counter.increaseX(incr);
                        counterField.setText(counter.toString());
                        counter.notifyAll();
                    }
                    ++i;
                }
                System.out.println("Finished " + i + " loops");
            } catch (InterruptedException ie) {
                System.out.println("Interrupted at loop " + i);
            } finally {
                done(this);
            }
        }
    }
    
    public static void main(String[] args) {
        Deadly5 f = new Deadly5();
        f.setVisible(true);
    }
}
