// j.n.magee 11/11/96
import java.awt.*;
import java.applet.*;

/********************************************************/

class Loop implements Runnable {

    public void run() {
        while(true)
            DisplayThread.rotate();
    }
}

/********************************************************/

public class ThreadDemo extends Applet {

    Button startA_;
    Button stopA_;
    Button startB_;
    Button stopB_;

    DisplayThread A_;
    DisplayThread B_;

    public void init() {
        super.init();
        // Set up Buttons
        this.setFont(new Font("Helvetica",Font.BOLD,18));
        Panel p1 = new Panel();
        p1.add(startA_=new Button("Start A"));
        p1.add(stopA_=new Button("Stop A"));
        p1.add(startB_=new Button("Start B"));
        p1.add(stopB_=new Button("Stop B"));
        // Set up Display
        Panel p2 = new Panel();
        GraphicCanvas g1 = new GraphicCanvas("Thread A",Color.blue);
        GraphicCanvas g2 = new GraphicCanvas("Thread B",Color.blue);
        p2.add(g1);
        p2.add(g2);
        // Arrange Applet display
        setLayout(new BorderLayout());
        add("Center",p2);
        add("South",p1);
        // Create Threads
        A_= new DisplayThread(g1,new Loop(),100);
        B_= new DisplayThread(g2,new Loop(),100);
        A_.start();
        B_.start();
    }

    public void start() {
        super.start();
    }

    public void stop() {
        A_.passivate();
        B_.passivate();
    }

    public void destroy() {
        A_.stop();
        B_.stop();
    }

    public boolean handleEvent(Event event) {
        if (event.id != event.ACTION_EVENT) {
            return super.handleEvent(event);
        } else if(event.target==startA_) {
            A_.activate();
            return true;
        } else if (event.target==stopA_) {
            A_.passivate();
            return true;
        } else if(event.target==startB_) {
            B_.activate();
            return true;
        } else if (event.target==stopB_) {
            B_.passivate();
            return true;
      } else
            return super.handleEvent(event);
    }

}

/********************************************************/

class DisplayThread extends Thread {

    GraphicCanvas display_;
    boolean suspended = true;
    int angle_=0;
    int rate_;
    final static int step = 6;
    Runnable target_;

    DisplayThread(GraphicCanvas g, Runnable target, int rate) {
        display_ = g;
        display_.setcolor(Color.red);
        target_=target;
        rate_=rate;
    }

     synchronized void mysuspend() {
        while (suspended)
            try {wait();} catch (InterruptedException e) {}
    }

    public void passivate() {
        if (!suspended) {
            suspended = true;
            display_.setcolor(Color.red);
           }
    }

    public void activate() {
        if (suspended) {
            suspended = false;
            display_.setcolor(Color.green);
            synchronized(this) {notify();}
        }
    }

    public static void rotate() {
        DisplayThread d = (DisplayThread)Thread.currentThread();
        d.mysuspend();
        d.angle_=(d.angle_+step)%360;
        d.display_.setvalue(d.angle_);
        try {Thread.sleep(d.rate_); } catch (InterruptedException e){}
    }

    public void run() {
          mysuspend();
          target_.run();
     }
 }


/********************************************************/


class GraphicCanvas extends Canvas {
    int value_ = 0;
    String title_;
    Color arcColor_;

    Font f1 = new Font("Times",Font.ITALIC+Font.BOLD,24);

    GraphicCanvas(String title,Color arc) {
        super();
        title_=title;
        arcColor_ = arc;
        resize(150,150);
  	}

    public void setcolor(Color c){
        setBackground(c);
        repaint();
    }

    public void setvalue(int newval){
        value_ = newval;
        repaint();
    }

    public void paint(Graphics g){
        update(g);
    }

    Image offscreen;
    Dimension offscreensize;
    Graphics offgraphics;

    public synchronized void update(Graphics g){
        Dimension d = size();
	    if ((offscreen == null) || (d.width != offscreensize.width)
	                            || (d.height != offscreensize.height)) {
	        offscreen = createImage(d.width, d.height);
	        offscreensize = d;
	        offgraphics = offscreen.getGraphics();
	        offgraphics.setFont(getFont());
	    }

	    offgraphics.setColor(getBackground());
	    offgraphics.fillRect(0, 0, d.width, d.height);

             // Display the title
         offgraphics.setColor(Color.black);
         offgraphics.setFont(f1);
         FontMetrics fm = offgraphics.getFontMetrics();
         int w = fm.stringWidth(title_);
         int h = fm.getHeight();
         int x = (size().width - w)/2;
         int y = h+10;
         offgraphics.drawString(title_, x, y);
         offgraphics.drawLine(x,y+3,x+w,y+3);
         // Display the arc
         offgraphics.setColor(arcColor_);
         offgraphics.fillArc(50,50,90,90,0,value_);
         g.drawImage(offscreen, 0, 0, null);
    }
}

