/**
  * Retrieves and removes the head of this queue, waiting if necessary until an element with an
  * expired delay is available on this queue, or the specified wait time expires.
  *
  * @return the head of this queue, or <tt>null</tt> if the specified waiting time elapses before
  *     an element with an expired delay becomes available
  * @throws InterruptedException {@inheritDoc}
  */
 public E poll(long timeout, TimeUnit unit) throws InterruptedException {
   long nanos = unit.toNanos(timeout);
   final ReentrantLock lock = this.lock;
   lock.lockInterruptibly();
   try {
     for (; ; ) {
       E first = q.peek();
       if (first == null) {
         if (nanos <= 0) return null;
         else nanos = available.awaitNanos(nanos);
       } else {
         long delay = first.getDelay(TimeUnit.NANOSECONDS);
         if (delay <= 0) return q.poll();
         if (nanos <= 0) return null;
         if (nanos < delay || leader != null) nanos = available.awaitNanos(nanos);
         else {
           Thread thisThread = Thread.currentThread();
           leader = thisThread;
           try {
             long timeLeft = available.awaitNanos(delay);
             nanos -= delay - timeLeft;
           } finally {
             if (leader == thisThread) leader = null;
           }
         }
       }
     }
   } finally {
     if (leader == null && q.peek() != null) available.signal();
     lock.unlock();
   }
 }
 /**
  * Retrieves and removes the head of this queue, waiting if necessary until an element with an
  * expired delay is available on this queue, or the specified wait time expires.
  *
  * @return the head of this queue, or <tt>null</tt> if the specified waiting time elapses before
  *     an element with an expired delay becomes available
  * @throws InterruptedException {@inheritDoc}
  */
 public E poll(long timeout, TimeUnit unit) throws InterruptedException {
   long nanos = unit.toNanos(timeout);
   final ReentrantLock lock = this.lock;
   lock.lockInterruptibly();
   try {
     for (; ; ) {
       E first = q.peek();
       if (first == null) {
         if (nanos <= 0) return null;
         else nanos = available.awaitNanos(nanos);
       } else {
         long delay = first.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 {
           E x = q.poll();
           assert x != null;
           if (q.size() != 0) available.signalAll();
           return x;
         }
       }
     }
   } finally {
     lock.unlock();
   }
 }
 /**
  * Retrieves and removes the head of this queue, waiting if necessary until an element with an
  * expired delay is available on this queue.
  *
  * @return the head of this queue
  * @throws InterruptedException {@inheritDoc}
  */
 public E take() throws InterruptedException {
   final ReentrantLock lock = this.lock;
   lock.lockInterruptibly();
   try {
     for (; ; ) {
       E first = q.peek();
       if (first == null) available.await();
       else {
         long delay = first.getDelay(TimeUnit.NANOSECONDS);
         if (delay <= 0) return q.poll();
         else if (leader != null) available.await();
         else {
           Thread thisThread = Thread.currentThread();
           leader = thisThread;
           try {
             available.awaitNanos(delay);
           } finally {
             if (leader == thisThread) leader = null;
           }
         }
       }
     }
   } finally {
     if (leader == null && q.peek() != null) available.signal();
     lock.unlock();
   }
 }
 /**
  * Retrieves and removes the head of this queue, or returns <tt>null</tt> if this queue has no
  * elements with an expired delay.
  *
  * @return the head of this queue, or <tt>null</tt> if this queue has no elements with an expired
  *     delay
  */
 public E poll() {
   final ReentrantLock lock = this.lock;
   lock.lock();
   try {
     E first = q.peek();
     if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0) return null;
     else return q.poll();
   } finally {
     lock.unlock();
   }
 }
 /**
  * Retrieves and removes the head of this queue, or returns <tt>null</tt> if this queue has no
  * elements with an expired delay.
  *
  * @return the head of this queue, or <tt>null</tt> if this queue has no elements with an expired
  *     delay
  */
 public E poll() {
   final ReentrantLock lock = this.lock;
   lock.lock();
   try {
     E first = q.peek();
     if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0) return null;
     else {
       E x = q.poll();
       assert x != null;
       if (q.size() != 0) available.signalAll();
       return x;
     }
   } finally {
     lock.unlock();
   }
 }
 /**
  * @throws UnsupportedOperationException {@inheritDoc}
  * @throws ClassCastException {@inheritDoc}
  * @throws NullPointerException {@inheritDoc}
  * @throws IllegalArgumentException {@inheritDoc}
  */
 public int drainTo(Collection<? super E> c) {
   if (c == null) throw new NullPointerException();
   if (c == this) throw new IllegalArgumentException();
   final ReentrantLock lock = this.lock;
   lock.lock();
   try {
     int n = 0;
     for (; ; ) {
       E first = q.peek();
       if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0) break;
       c.add(q.poll());
       ++n;
     }
     return n;
   } finally {
     lock.unlock();
   }
 }
 /**
  * @throws UnsupportedOperationException {@inheritDoc}
  * @throws ClassCastException {@inheritDoc}
  * @throws NullPointerException {@inheritDoc}
  * @throws IllegalArgumentException {@inheritDoc}
  */
 public int drainTo(Collection<? super E> 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 = 0;
     while (n < maxElements) {
       E first = q.peek();
       if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0) break;
       c.add(q.poll());
       ++n;
     }
     if (n > 0) available.signalAll();
     return n;
   } finally {
     lock.unlock();
   }
 }
 /**
  * Inserts the specified element into this delay queue.
  *
  * @param e the element to add
  * @return <tt>true</tt>
  * @throws NullPointerException if the specified element is null
  */
 public boolean offer(E e) {
   final ReentrantLock lock = this.lock;
   lock.lock();
   try {
     E first = q.peek();
     q.offer(e);
     if (first == null || e.compareTo(first) < 0) available.signalAll();
     return true;
   } finally {
     lock.unlock();
   }
 }
 /**
  * Retrieves and removes the head of this queue, waiting if necessary until an element with an
  * expired delay is available on this queue.
  *
  * @return the head of this queue
  * @throws InterruptedException {@inheritDoc}
  */
 public E take() throws InterruptedException {
   final ReentrantLock lock = this.lock;
   lock.lockInterruptibly();
   try {
     for (; ; ) {
       E first = q.peek();
       if (first == null) {
         available.await();
       } else {
         long delay = first.getDelay(TimeUnit.NANOSECONDS);
         if (delay > 0) {
           long tl = available.awaitNanos(delay);
         } else {
           E x = q.poll();
           assert x != null;
           if (q.size() != 0) available.signalAll(); // wake up other takers
           return x;
         }
       }
     }
   } finally {
     lock.unlock();
   }
 }