content: package com.aicontest.visualizer;
  
  import java.util.AbstractQueue;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Iterator;
  import java.util.LinkedList;
  import java.util.NoSuchElementException;
  import java.util.PriorityQueue;
  import java.util.concurrent.BlockingQueue;
  import java.util.concurrent.TimeUnit;
  import java.util.concurrent.locks.Condition;
  import java.util.concurrent.locks.ReentrantLock;
  
  import com.aicontest.visualizer.js.tasks.DelayedExecutionUnit;
  import com.aicontest.visualizer.js.tasks.EventExecutionUnit;
  import com.aicontest.visualizer.js.tasks.IExecutionUnit;
  
  public class ExecutionUnitQueue extends AbstractQueue<IExecutionUnit> implements
  		BlockingQueue<IExecutionUnit> {
  
  	private transient final ReentrantLock lock = new ReentrantLock();
  	private transient final Condition available = lock.newCondition();
  	private final LinkedList<EventExecutionUnit> immediate = new LinkedList<EventExecutionUnit>();
  	private final PriorityQueue<DelayedExecutionUnit> delayed = new PriorityQueue<DelayedExecutionUnit>();
  
  	public void put(IExecutionUnit eu) {
  		offer(eu);
  	}
  
  	public boolean offer(IExecutionUnit eu, long timeout, TimeUnit unit) {
  		return offer(eu);
  	}
  
  	public boolean offer(IExecutionUnit eu) {
  		final ReentrantLock lock = this.lock;
  		lock.lock();
  		try {
  			if (eu instanceof DelayedExecutionUnit) {
  				DelayedExecutionUnit deu = (DelayedExecutionUnit) eu;
  				DelayedExecutionUnit first = delayed.peek();
  				delayed.offer(deu);
  				if (first == null || deu.compareTo(first) < 0)
  					available.signalAll();
  			} else {
  				immediate.offer((EventExecutionUnit) eu);
  				available.signalAll();
  			}
  			return true;
  		} finally {
  			lock.unlock();
  		}
  	}
  
  	public IExecutionUnit poll() {
  		final ReentrantLock lock = this.lock;
  		lock.lock();
  		try {
  			IExecutionUnit eu = immediate.peek();
  			if (eu == null) {
  				DelayedExecutionUnit deu = delayed.peek();
  				if (deu == null || deu.getDelay(TimeUnit.NANOSECONDS) > 0) {
  					return null;
  				} else {
  					IExecutionUnit x = delayed.poll();
  					assert x != null;
  					if (delayed.size() != 0)
  						available.signalAll();
  					return x;
  				}
  			} else {
  				IExecutionUnit x = immediate.poll();
  				assert x != null;
  				if (immediate.size() != 0)
  					available.signalAll();
  				return x;
  			}
  		} finally {
  			lock.unlock();
  		}
  	}
  
  	public IExecutionUnit take() throws InterruptedException {
  		final ReentrantLock lock = this.lock;
  		lock.lockInterruptibly();
  		try {
  			for (;;) {
  				IExecutionUnit eu = immediate.peek();
  				if (eu != null) {
  					IExecutionUnit x = immediate.poll();
  					assert x != null;
  					if (immediate.size() != 0)
  						available.signalAll();
  					return x;
  				}
  				DelayedExecutionUnit deu = delayed.peek();
  				if (deu != null) {
  					long delay = deu.getDelay(TimeUnit.NANOSECONDS);
  					if (delay > 0) {
  						available.awaitNanos(delay);
  					} else {
  						IExecutionUnit x = delayed.poll();
  						assert x != null;
  						if (delayed.size() != 0)
  							available.signalAll(); // wake up other takers
  						return x;
  					}
  				} else {
  					available.await();
  				}
  			}
  		} finally {
  			lock.unlock();
  		}
  	}
  
  	public IExecutionUnit poll(long timeout, TimeUnit unit)
  			throws InterruptedException {
  		long nanos = unit.toNanos(timeout);
  		final ReentrantLock lock = this.lock;
  		lock.lockInterruptibly();
  		try {
  			for (;;) {
  				IExecutionUnit eu = immediate.peek();
  				if (eu != null) {
  					IExecutionUnit x = immediate.poll();
  					assert x != null;
  					if (immediate.size() != 0)
  						available.signalAll();
  					return x;
  				}
  				DelayedExecutionUnit deu = delayed.peek();
  				if (deu == null) {
  					if (nanos <= 0)
  						return null;
  					else
  						nanos = available.awaitNanos(nanos);
  				} else {
  					long delay = deu.getDelay(TimeUnit.NANOSECONDS);
  					if (delay > 0) {
  						if (nanos <= 0)
  							return null;
  						if (delay > nanos)
  							delay = nanos;
  						long timeLeft = available.awaitNanos(delay);
  						nanos -= delay - timeLeft;
  					} else {
  						IExecutionUnit x = delayed.poll();
  						assert x != null;
  						if (delayed.size() != 0)
  							available.signalAll();
  						return x;
  					}
  				}
  			}
  		} finally {
  			lock.unlock();
  		}
  	}
  
  	public IExecutionUnit peek() {
  		final ReentrantLock lock = this.lock;
  		lock.lock();
  		try {
  			IExecutionUnit eu = immediate.peek();
  			if (eu != null) {
  				return eu;
  			}
  			return delayed.peek();
  		} finally {
  			lock.unlock();
  		}
  	}
  
  	public int size() {
  		final ReentrantLock lock = this.lock;
  		lock.lock();
  		try {
  			return immediate.size() + delayed.size();
  		} finally {
  			lock.unlock();
  		}
  	}
  
  	public int drainTo(Collection<? super IExecutionUnit> c) {
  		if (c == null)
  			throw new NullPointerException();
  		if (c == this)
  			throw new IllegalArgumentException();
  		final ReentrantLock lock = this.lock;
  		lock.lock();
  		try {
  			c.addAll(immediate);
  			int n = immediate.size();
  			immediate.clear();
  			int i = n;
  			for (;;) {
  				DelayedExecutionUnit first = delayed.peek();
  				if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)
  					break;
  				c.add(delayed.poll());
  				++n;
  			}
  			if (n > i)
  				available.signalAll();
  			return n;
  		} finally {
  			lock.unlock();
  		}
  	}
  
  	public int drainTo(Collection<? super IExecutionUnit> c, int maxElements) {
  		if (c == null)
  			throw new NullPointerException();
  		if (c == this)
  			throw new IllegalArgumentException();
  		if (maxElements <= 0)
  			return 0;
  		final ReentrantLock lock = this.lock;
  		lock.lock();
  		try {
  			int n;
  			if (immediate.size() > maxElements) {
  				n = 0;
  				while (n < maxElements) {
  					c.add(immediate.poll());
  					++n;
  				}
  			} else {
  				c.addAll(immediate);
  				n = immediate.size();
  				immediate.clear();
  				int i = n;
  				while (n < maxElements) {
  					DelayedExecutionUnit first = delayed.peek();
  					if (first == null
  							|| first.getDelay(TimeUnit.NANOSECONDS) > 0)
  						break;
  					c.add(delayed.poll());
  					++n;
  				}
  				if (n > i)
  					available.signalAll();
  			}
  			return n;
  		} finally {
  			lock.unlock();
  		}
  	}
  
  	public void clear() {
  		final ReentrantLock lock = this.lock;
  		lock.lock();
  		try {
  			immediate.clear();
  			delayed.clear();
  		} finally {
  			lock.unlock();
  		}
  	}
  
  	public int remainingCapacity() {
  		return Integer.MAX_VALUE;
  	}
  
  	public Object[] toArray() {
  		final ReentrantLock lock = this.lock;
  		lock.lock();
  		try {
  			ArrayList<IExecutionUnit> al = new ArrayList<IExecutionUnit>(
  					immediate.size() + delayed.size());
  			al.addAll(immediate);
  			al.addAll(delayed);
  			return al.toArray();
  		} finally {
  			lock.unlock();
  		}
  	}
  
  	public <T> T[] toArray(T[] a) {
  		final ReentrantLock lock = this.lock;
  		lock.lock();
  		try {
  			ArrayList<IExecutionUnit> al = new ArrayList<IExecutionUnit>(
  					immediate.size() + delayed.size());
  			al.addAll(immediate);
  			al.addAll(delayed);
  			return al.toArray(a);
  		} finally {
  			lock.unlock();
  		}
  	}
  
  	public boolean remove(Object o) {
  		final ReentrantLock lock = this.lock;
  		lock.lock();
  		try {
  			return immediate.remove(o) || delayed.remove(o);
  		} finally {
  			lock.unlock();
  		}
  	}
  
  	public Iterator<IExecutionUnit> iterator() {
  		return new Itr(toArray());
  	}
  
  	private class Itr implements Iterator<IExecutionUnit> {
  		final Object[] array;
  		int cursor;
  		int lastRet;
  
  		Itr(Object[] array) {
  			lastRet = -1;
  			this.array = array;
  		}
  
  		public boolean hasNext() {
  			return cursor < array.length;
  		}
  
  		public IExecutionUnit next() {
  			if (cursor >= array.length)
  				throw new NoSuchElementException();
  			lastRet = cursor;
  			return (IExecutionUnit) array[cursor++];
  		}
  
  		public void remove() {
  			if (lastRet < 0)
  				throw new IllegalStateException();
  			Object x = array[lastRet];
  			lastRet = -1;
  			lock.lock();
  			try {
  				for (Iterator<?> it = immediate.iterator(); it.hasNext();) {
  					if (it.next() == x) {
  						it.remove();
  						return;
  					}
  				}
  				for (Iterator<?> it = delayed.iterator(); it.hasNext();) {
  					if (it.next() == x) {
  						it.remove();
  						return;
  					}
  				}
  			} finally {
  				lock.unlock();
  			}
  		}
  	}
  
  	public void compressEvent(EventExecutionUnit task) {
  		final ReentrantLock lock = this.lock;
  		lock.lock();
  		try {
  			Iterator<EventExecutionUnit> it = immediate.iterator();
  			while (it.hasNext()) {
  				EventExecutionUnit eeu = it.next();
  				if (eeu.matches(task))
  					it.remove();
  			}
  			immediate.offer(task);
  			available.signalAll();
  		} finally {
  			lock.unlock();
  		}
  	}
  }