//
// $Source: /home/cur/djb1/java/threads/RCS/ReadChanWrite.java,v $
//
// $Id: ReadChanWrite.java,v 1.3 1996/10/02 15:20:14 djb1 Exp $
//
// Multiple Read / Write channels applet
//
// (C) Copyright 1996 Dave Beckett <D.J.Beckett@ukc.ac.uk>
// University of Kent at Canterbury
//

import java.awt.*;
import java.applet.*;

import java.lang.InterruptedException;

import Channel;

//{{{  class Writer
class Writer extends Panel implements Runnable
{
  //{{{  private member data
  private Thread thread;
  private Channel chan;
  private Component comp;
  private boolean button_clicked;
  private boolean active;
  private int id;
  
  private static final int delay = 2000;
  
  //}}}
  //{{{  Writer (Channel chan, int id, boolean active)
  public Writer (Channel chan, int id, boolean active)
  {
    this.chan=chan;
    this.id=id;
    this.active=active;
    button_clicked=false;
  
    setLayout(new GridLayout(1,1));
  
    String name="Writer "+id;
  
    if (!active) {
      comp = new Label(name, Label.CENTER);
    } else {
      comp = new Button(name);
    }
  
    add(comp);
  }
  
  //}}}
  //{{{  void setLabel (String text)
  public void setLabel (String text)
  {
    if (!active)
      ((Label)comp).setText(text);
    else
      ((Button)comp).setLabel(text);
  }
  
  //}}}
  //{{{  void run ()
  public void run ()
  {
    while (Thread.currentThread() == thread) {
      if (!active || button_clicked) {
        try {
          System.out.println ("Writer"+id+": Writing Integer");
          setLabel("c ! "+id);
          repaint(50);
          chan.write(new Integer(id));
          System.out.println ("Writer"+id+": Write done");
          Thread.sleep(delay);
          setLabel("Wrote "+id);
          repaint(50);
          Thread.sleep(delay);
        } catch (InterruptedException e) {
          break;
        }
        button_clicked=false;
      } else {
        // nothing
      }
      try {
        Thread.sleep(100);
      } catch (InterruptedException e) {
        break;
      }
    }
  }
  
  //}}}
  //{{{  void start ()
  public void start ()
  {
    if (thread == null)
      thread = new Thread(this, "Control");
    thread.start();
  }
  
  //}}}
  //{{{  void stop ()
  public void stop ()
  {
    thread = null;
  }
  
  //}}}
  //{{{  boolean action (Event event, Object arg)
  public boolean action (Event event, Object arg)
  {
    if (event.target == comp) {
      if (!active) {
        System.out.println ("Writer"+id+": Ignoring button press");
      } else {
        System.out.println ("Writer"+id+": Clicked");
        button_clicked = true;
      }
      return true;
    } else {
      return super.action(event, arg);
    }
  }
  
  //}}}
  //{{{  update (Graphics g)
  public void update (Graphics g) {
    paint(g);
  }
  
  //}}}
}


//}}}
//{{{  class Reader
class Reader extends Panel implements Runnable
{
  //{{{  private member data
  private Thread thread;
  private Channel chan;
  private Component comp;
  private boolean button_clicked;
  private boolean active;
  private int id;
  
  private static final int delay = 2000;
  
  //}}}
  //{{{  Reader (Channel chan, int id, boolean active)
  public Reader (Channel chan, int id, boolean active)
  {
    this.chan=chan;
    this.id=id;
    this.active=active;
    button_clicked=false;
  
    setLayout(new GridLayout(1,1));
  
    String name="Reader "+id;
  
    if (!active) {
      comp = new Label(name, Label.CENTER);
    } else {
      comp = new Button(name);
    }
  
    add(comp);
  }
  
  //}}}
  //{{{  void setLabel (String text)
  public void setLabel (String text)
  {
    if (!active)
      ((Label)comp).setText(text);
    else
      ((Button)comp).setLabel(text);
  }
  
  //}}}
  //{{{  void run ()
  public void run ()
  {
    while (Thread.currentThread() == thread) {
      if (!active || button_clicked) {
        try {
          System.out.println ("Reader"+id+": Reading Integer");
          setLabel("c ? ");
          repaint(50);
          Object o = chan.read();
          System.out.println ("Control"+id+": Read done");
          Thread.sleep(delay);
          setLabel("Read "+o);
          repaint(50);
          Thread.sleep(delay);
        } catch (InterruptedException e) {
          break;
        }
        button_clicked=false;
      }
      try {
        Thread.sleep(100);
      } catch (InterruptedException e) {
        break;
      }
    }
  }
  
  //}}}
  //{{{  void start ()
  public void start ()
  {
    if (thread == null)
      thread = new Thread(this, "Control");
    thread.start();
  }
  
  //}}}
  //{{{  void stop ()
  public void stop ()
  {
    thread = null;
  }
  
  //}}}
  //{{{  boolean action (Event event, Object arg)
  public boolean action (Event event, Object arg)
  {
    if (event.target == comp) {
      if (!active) {
        System.out.println ("Reader"+id+": Ignoring button press");
      } else {
        System.out.println ("Reader"+id+": Clicked");
        button_clicked = true;
      }
      return true;
    } else {
      return super.action(event, arg);
    }
  }
  
  //}}}
  //{{{  void update (Graphics g)
  public void update (Graphics g) {
    paint(g);
  }
  //}}}
}

//}}}
//{{{  class ArrowCanvas
class ArrowCanvas extends Canvas
{
  //{{{  private member data
  static final int inset = 30;
  static final int arrow_size = 50;
  
  //}}}
  //{{{  void paint (Graphics g)
  public void paint (Graphics g)
  {
    Dimension d=size();
    int hheight=d.height/2;
    int ax=d.width-arrow_size;
  
    g.drawLine(inset, hheight+1, d.width-inset, hheight+1);
    g.drawLine(inset, hheight, d.width-inset, hheight);
    g.drawLine(inset, hheight-1, d.width-inset, hheight-1);
  
    int xpoints[]={ax,                  d.width-inset, ax};
    int ypoints[]={hheight+ arrow_size, hheight, hheight-arrow_size};
  
    g.fillPolygon(xpoints, ypoints, xpoints.length);
  
    g.drawString("Channel c", 70, hheight-30);
  }
  //}}}
}

//}}}
//{{{  class ReadChanWrite
public class ReadChanWrite extends Applet
{
  //{{{  private member data
  private Label label;
  
  private int writer_count = 5;
  private int reader_count = 5;
  
  private boolean writers_active = true;
  
  private Writer[] writers;
  private Reader[] readers;
  
  private Panel writers_panel, readers_panel;
  private ArrowCanvas arrow;
  
  private Channel chan;
  
  //}}}
  //{{{  void init()
  // Called on class load
  public void init()
  {
    System.out.println ("ReadChanWrite:init()");
  
    String param;
    param = getParameter("READERS");
    if (param != null)
      try {
        int i = Integer.parseInt(param);
        if (i>0)
          reader_count = i;
      } catch (NumberFormatException e) {
        String errorMsg = "Parameter READERS parse error in "+param;
        showStatus(errorMsg);
        System.err.println(errorMsg);
      }
  
    param = getParameter("WRITERS");
    if (param != null)
      try {
        int i = Integer.parseInt(param);
        if (i>0)
          writer_count = i;
      } catch (NumberFormatException e) {
        String errorMsg = "Parameter WRITERS parse error in "+param;
        showStatus(errorMsg);
        System.err.println(errorMsg);
      }
  
    param = getParameter("ACTIVE");
    if (param != null) {
      if (param.equals("WRITERS")) {
        writers_active=true;
      } else if (param.equals("READERS")) {
        writers_active=false;
      } else {
        String errorMsg = "Parameter ACTIVE error - "+param+" not READERS or WRITERS";
        showStatus(errorMsg);
        System.err.println(errorMsg);
      }
    }
  
    chan = new Channel();
  
    writers = new Writer[writer_count];
    writers_panel = new Panel();
    writers_panel.setLayout(new GridLayout(writer_count,1));
  
    for (int i=0; i< writer_count; i++) {
      writers[i] = new Writer(chan, i, writers_active);
      writers_panel.add(writers[i]);
    }
  
    readers = new Reader[reader_count];
    readers_panel = new Panel();
    readers_panel.setLayout(new GridLayout(reader_count,1));
  
    for (int i=0; i< reader_count; i++) {
      readers[i] = new Reader(chan, i, !writers_active);
      readers_panel.add(readers[i]);
    }
  
  
    label = new Label("Channel OF Object between writers (left) and readers (right)");
  
    arrow = new ArrowCanvas();
  
    setLayout(new BorderLayout());
  
    add("North",label);
    add("West", writers_panel);
    add("East", readers_panel);
    add("Center", arrow);
  
    // Cause all components to be created
    validate();
  }
  
  //}}}
  //{{{  void stop()
  // Called on applet pausing
  public void stop()
  {
    System.out.println ("ReadChanWrite:stop()");
    for (int i=0; i< writer_count; i++)
      writers[i].stop();
    for (int i=0; i< reader_count; i++)
      readers[i].stop();
  }
  
  //}}}
  //{{{  void start()
  // Called on applet continuing
  public void start()
  {
    System.out.println ("ReadChanWrite:start()");
    for (int i=0; i< writer_count; i++)
      writers[i].start();
    for (int i=0; i< reader_count; i++)
      readers[i].start();
  
    repaint();
  }
  
  //}}}
  //{{{  void destroy()
  // Called on applet destruction
  public void destroy()
  {
    System.out.println ("ReadChanWrite:destroy()");
    for (int i=0; i< writer_count; i++) {
      writers[i].start();
      writers[i] = null;
    }
  
    for (int i=0; i< reader_count; i++) {
      readers[i].start();
      readers[i] = null;
    }
  }
  
  //}}}
  //{{{  Insets insets()
  // Put a little breathing space between the panel and its contents
  public Insets insets() {
    return new Insets(5,5,5,5);
  }
  
  //}}}
  //{{{  String getAppletInfo()
  public String getAppletInfo() {
    return "ReadChanWrite by Dave Beckett <D.J.Beckett@ukc.ac.uk>";
  }
  
  //}}}
  //{{{  String[][] getParameterInfo()
  public String[][] getParameterInfo()
  {
    String[][] info = {
      {"writers",    "int",       "number of writer processes"},
      {"readers",    "int",       "number of reader processes"},
      {"active",     "name",      "reader or writers active?"},
    };
    return info;
  }
  
  //}}}
}
//}}}
