/**
 * Logback: the reliable, generic, fast and flexible logging framework.
 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
 *
 * This program and the accompanying materials are dual-licensed under
 * either the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation
 *
 *   or (per the licensee's choosing)
 *
 * under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation.
 */
package ch.qos.logback.core.net.server;

import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import ch.qos.logback.core.net.server.Client;
import ch.qos.logback.core.net.server.ServerListener;


/**
 * A mock {@link ServerListener} that has a blocking queue to pass a client
 * to a {@link #acceptClient()} caller.  If the {@link #close()} method is
 * called while a caller is blocked waiting to take from the queue, the
 * caller's thread is interrupted.
 *
 * @author Carl Harris
 */
public class MockServerListener<T extends Client> implements ServerListener<T> {

  private final BlockingQueue<T> queue = 
      new LinkedBlockingQueue<T>();
  
  private boolean closed;
  private Thread waiter;
  
  public synchronized Thread getWaiter() {
    return waiter;
  }
  
  public synchronized void setWaiter(Thread waiter) {
    this.waiter = waiter;
  }
  
  public synchronized boolean isClosed() {
    return closed;
  }

  public synchronized void setClosed(boolean closed) {
    this.closed = closed;
  }

  public T acceptClient() throws IOException, InterruptedException {
    if (isClosed()) {
      throw new IOException("closed");
    }
    setWaiter(Thread.currentThread());
    try {
      return queue.take();
    }
    finally {
      setWaiter(null);
    }
  }

  public void addClient(T client) {
    queue.offer(client);
  }
  
  public synchronized void close() {
    setClosed(true);
    Thread waiter = getWaiter();
    if (waiter != null) {
      waiter.interrupt();
    }   
  }

}
