// class implementing a FIFO rotating buffer for integers

class Buffer {
  private int elems[];   // buffer containing elements
  private int in;        // index of the next element to be added
  private int out;       // index of the next element to be removed
  private int size;      // size of the buffer

  // constructor
  Buffer(int size) {
    in = 0;
    out = 0;
    this.size = size;
    elems = new int[size];
    for(int i = 0; i < size; i++) {
      elems[i] = 0;
    }
  }

  // prints the contents of the buffer
  private void printElems() {
    for(int i = 0; i < in; i++) {
      System.out.print("  ");
    }
    System.out.println("i");
    for(int i = 0; i < out; i++) {
      System.out.print("  ");
    }
    System.out.println("o");
    System.out.print(""+elems[0]);
    for(int i = 1; i < size; i++) {
      System.out.print(" "+elems[i]);
    }
    System.out.println();
  }

  // returns the size of the buffer
  public int size() {
    return(size);
  }

  // returns true if buffer is empty
  public boolean isEmpty() {
    return(in == out && elems[in] == 0);
  }

  // returns true if buffer is full
  public boolean isFull() {
    return(in == out && elems[in] != 0);
  }

  // adds an element to the buffer, waits if full
  public synchronized void addElement(int elem, String name) {
    System.out.println(name+": adding "+elem+" to the buffer");
    while(isFull()) {
      System.out.println(name+": buffer is full, waiting...");
      try {
	wait();
      } catch(InterruptedException x) {
	System.out.println(x);
      }
    }      
    if(isEmpty()) {
      notify();
    }
    elems[in] = elem;
    in = (in + 1) % size;
    System.out.println(name+": "+elem+" added to the buffer");
    printElems();
  }
  
  // removes an element, waits for next element if empty
  public synchronized int removeElement(String name) {
    int elem;
    
    System.out.println(name+": removing an element from the buffer");
    while(isEmpty()) {
      System.out.println(name+": Buffer empty, waiting...");
      try {
	wait();
      } catch(InterruptedException x) {
	System.out.println(x);
      }
    }
    if(isFull()) {
      notify();
    }
    elem = elems[out];
    elems[out] = 0;
    out = (out + 1) % size;
    System.out.println(name+": "+elem+" removed from the buffer");
    printElems();
    return(elem);
  }
}	
