package com.github.phantomthief.pool.impl;

import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.function.IntSupplier;

import com.github.phantomthief.util.SimpleRateLimiter;

/**
 * @author w.vela
 * Created on 2020-08-19.
 */
public class DynamicCapacityLinkedBlockingQueue<E> implements BlockingQueue<E> {

    private final VariableLinkedBlockingQueue<E> queue;
    private final IntSupplier capacity;
    private final SimpleRateLimiter rateLimiter;

    /**
     * 可以动态调整 capacity 的 {@link java.util.concurrent.LinkedBlockingQueue}
     * @param capacity 这里为了支持可变化性，所以当返回值 <= 0 时，容量为最大值 {@link Integer#MAX_VALUE}
     *
     * 注意: 当需要声明在 field 内初始化时，建议使用 {@link #lazyDynamicCapacityLinkedBlockingQueue(IntSupplier)}
     */
    public DynamicCapacityLinkedBlockingQueue(IntSupplier capacity) {
        this.capacity = capacity;
        int thisCapacity = capacity.getAsInt();
        this.queue = new VariableLinkedBlockingQueue<>(thisCapacity <= 0 ? Integer.MAX_VALUE : thisCapacity);
        this.rateLimiter = SimpleRateLimiter.create(1);
    }

    /**
     * 参考构建函数 javadoc
     * 本工具方法构建出来的实例只有在第一次使用时才会初始化资源，可以更安全的在 field 内声明并初始化
     */
    public static <T> BlockingQueue<T> lazyDynamicCapacityLinkedBlockingQueue(IntSupplier capacity) {
        return new LazyBlockingQueue<>(() -> new DynamicCapacityLinkedBlockingQueue<>(capacity));
    }

    private void tryCheckCapacity() {
        if (rateLimiter.tryAcquire()) {
            int thisCapacity = capacity.getAsInt();
            if (thisCapacity <= 0) {
                thisCapacity = Integer.MAX_VALUE;
            }
            if (thisCapacity != queue.getCapacity()) {
                queue.setCapacity(thisCapacity);
            }
        }
    }

    @Override
    public boolean add(E e) {
        tryCheckCapacity();
        return queue.add(e);
    }

    @Override
    public boolean contains(Object o) {
        return queue.contains(o);
    }

    @Override
    public E remove() {
        return queue.remove();
    }

    @Override
    public E element() {
        return queue.element();
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        tryCheckCapacity();
        return queue.addAll(c);
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return queue.containsAll(c);
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        return queue.removeAll(c);
    }

    @Override
    public boolean isEmpty() {
        return queue.isEmpty();
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return queue.retainAll(c);
    }

    @Override
    public int size() {
        return queue.size();
    }

    @Override
    public int remainingCapacity() {
        return queue.remainingCapacity();
    }

    @Override
    public void put(E o) throws InterruptedException {
        tryCheckCapacity();
        queue.put(o);
    }

    @Override
    public boolean offer(E o, long timeout, TimeUnit unit) throws InterruptedException {
        tryCheckCapacity();
        return queue.offer(o, timeout, unit);
    }

    @Override
    public boolean offer(E o) {
        tryCheckCapacity();
        return queue.offer(o);
    }

    @Override
    public E take() throws InterruptedException {
        return queue.take();
    }

    @Override
    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
        return queue.poll(timeout, unit);
    }

    @Override
    public E poll() {
        return queue.poll();
    }

    @Override
    public E peek() {
        return queue.peek();
    }

    @Override
    public boolean remove(Object o) {
        return queue.remove(o);
    }

    @Override
    public Object[] toArray() {
        return queue.toArray();
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return queue.toArray(a);
    }

    @Override
    public String toString() {
        return queue.toString();
    }

    @Override
    public void clear() {
        queue.clear();
    }

    @Override
    public int drainTo(Collection<? super E> c) {
        return queue.drainTo(c);
    }

    @Override
    public int drainTo(Collection<? super E> c, int maxElements) {
        return queue.drainTo(c, maxElements);
    }

    @Override
    public Iterator<E> iterator() {
        return queue.iterator();
    }
}

@@ -274,16 +274,187 @@
 r;%0A%0A/**%0A
+ * %E5%A4%87%E6%B3%A8%EF%BC%8C%E6%9C%AC%E7%B1%BB%E4%B8%BB%E8%A6%81%E6%98%AF%E7%94%A8%E4%BA%8E%E7%BB%99%0A * %7B@link com.github.phantomthief.pool.KeyAffinityExecutor#newSerializingExecutor(IntSupplier, IntSupplier, String)%7D%0A * %E6%8F%90%E4%BE%9B%E6%94%AF%E6%8C%81%E7%9A%84%EF%BC%8C%E5%B9%B6%E4%B8%8D%E6%8E%A8%E8%8D%90%E5%A4%A7%E5%AE%B6%E7%9B%B4%E6%8E%A5%E4%BD%BF%E7%94%A8%EF%BC%8C%E6%9C%AA%E6%9D%A5%E4%B9%9F%E5%8F%AF%E8%83%BD%E4%BC%9A%E9%9A%8F%E6%97%B6%E8%B0%83%E6%95%B4%E5%AE%9E%E7%8E%B0%E5%92%8C%E8%A1%8C%E4%B8%BA%0A *%0A
  * @auth

add javadoc & comments.