/**
 * Channel
 * 
 */

public class Channel {
  /**
   * object storage
   */
  private Object[] buffer;

  /**
   * buffer size
   */
  private int size;

  /**
   * index to the first filled cell
   */
  private int front;

  /**
   * index to the first empty cell
   */
  private int rear;

  /**
   * semaphore indicating an empty cell
   */
  private Sema empty;

  /**
   * semaphore indicating a filled cell
   */
  private Sema full;

  /**
   * mutex for send
   */
  private Object snd;

  /**
   * mutex for receive
   */
  private Object rcv;

  /**
   * Constructs a Channel
   */
  public Channel(int init) {
    buffer = new Object[init];
    size = init; front = 0; rear = 0;
    empty = new Sema(init);
    full = new Sema(0);
    snd = new Object();
    rcv = new Object();
  }

  /**
   * Sends an object to the channel
   */
  public void send(Object v) {
    empty.P();
    synchronized (snd) {
      buffer[rear] = v;
      rear++;
      if (rear >= size) rear -= size;
    }
    full.V();
  }

  /**
   * Receives an object from the channel
   */
  public Object receive() {
    Object v = null;
    full.P();
    synchronized (rcv) {
      v = buffer[front];
      front++;
      if (front >= size) front -= size;
    }
    empty.V();
    return v;
  }
}
