//{{{}}}

// package occam;

//{{{  public class Channel_1_1 {
public class Channel_1_1 {

  //{{{  COMMENT documentation
  //
  //Channel extends an occam CHAN OF INT for a single reader and single writer.
  //
  //It allows ALTing by that single reader.  This implementation follows closely
  //the transputer implementation -- ALTing is passive (i.e. no busy-waits).
  //
  //There is full synchronisation between a reading and writing thread.  Only
  //a single reader and a single writer is allowed with this version.  The single
  //reader may back off if it selects another Channel.  The writer is not allowed
  //to back off (as in occam, we cannot ALT on an output guard).
  //
  //There is no logical buffering of data in the Channel.
  //
  //Note: only the `read' and `write' methods are public.  The `enable' and
  //`disable' Channels are called only from an Alternative object (by the
  //ALTing process).  It is deliberate that `disable' is not synchronised.
  //
  //}}}

  //{{{  local state
  
  private int channel_hold;                // buffer (not detectable to users)
  
  protected boolean channel_empty = true;  // synchronisation flag
  
  private Alternative alt;                 // state of reader
  
  //}}}

  //{{{  public synchronized int read () throws InterruptedException {
  public synchronized int read () throws InterruptedException {
    if (channel_empty) {
      channel_empty = false;           // first to the rendezvous
      wait ();                         // wait for the writer thread
      notify ();                       // schedule the writer to finish
    } else {
      channel_empty = true;            // second to the rendezvous
      notify ();                       // schedule the waiting writer thread
    }
    return channel_hold;
  }
  //}}}
  //{{{  public synchronized void write (int n) throws InterruptedException {
  public synchronized void write (int n) throws InterruptedException {
    Alternative tmp_alt = alt;         // avoid race-hazard on the volatile alt
    channel_hold = n;
    if (tmp_alt != null) {             // a reader was ALTing on this Channel
      channel_empty = false;           // first to the rendezvous
      tmp_alt.schedule ();             // tell the reader we are here
      wait ();                         // wait for the reader thread
    } else if (channel_empty) {
      channel_empty = false;           // first to the rendezvous
      wait ();                         // wait for the reader thread
    } else {
      channel_empty = true;            // second to the rendezvous
      notify ();                       // schedule the waiting reader thread
      wait ();                         // let the reader regain this monitor
    }
  }
  //}}}

  //{{{  synchronized boolean enable (Alternative alt) {
  synchronized boolean enable (Alternative alt) {
    if (channel_empty) {
      this.alt = alt;
      return false;
    } else {
      return true;
    }
  }
  //}}}
  //{{{  boolean disable () {
  boolean disable () {
    alt = null;
    return !channel_empty;
  }
  //}}}

}
//}}}

