package org.itscool.commons.threadpool;

import java.util.Vector;

/**
 * This class represents the Request Buffer. <BR>
 * It's a FIFO queue which is unbounded i.e. infinite size of
 * course limited by physical memory size.<BR>
 * このクラスは、リクエスト・バッファーを表します。<BR>
 * それは、果てしないすなわち無限のサイズであるキューが
 * 物理・メモリ・サイズによって制限したFIFOです。<BR>
 * @author Ashwin Desai.
 * @version 1.00A 機能修正
 *   ◆ バッファサイズの許容量を追加
 *   ◆ add()でキューのバッファサイズを超えた場合、ThreadBuffer
 *      Exceptionをスローし、バッファの追加をキャンセルする。
 */
public class FIFOQueue {
    /** リクエストバッファ */
    private Vector requestVector;
    /** バッファの状態 */
    private boolean closed = false;
    /** デフォルトバッファサイズ */
    public static final int DEFAULT_BUFFER_SIZE = 100;
    /** バッファサイズ */
    private int bufferSize = DEFAULT_BUFFER_SIZE;

    /**
    * キューの初期化
    */
    public FIFOQueue() {
        this(DEFAULT_BUFFER_SIZE);
    }

    /**
    * キューの初期化
    * @param bufferSize バッファサイズ
    */
    public FIFOQueue(int bufferSize) {
        this.bufferSize = bufferSize;
        requestVector = new Vector(bufferSize);
    }

    /**
    * バッファサイズの取得
    * @return bufferSize バッファサイズを返します
    */
    public synchronized int getBufferSize() {
        return bufferSize;
    }

    /**
    * バッファサイズの設定
    * @param bufferSize バッファサイズ
    */
    public synchronized void setBufferSize(int bufferSize) {
        this.bufferSize = bufferSize;
    }

    /**
    * requestVector が要素を持たないかどうかを判定する。
    * @return Vector が要素を持っていない、つまりそのサイズが 0 の場合
    * にだけ true、そうでない場合は false
    */
    public synchronized boolean requestEmpty() {
        return requestVector.isEmpty();
    }

    /**
    * Adds an Object r to the Queue. <BR>
    * If the queue is already closed, throws a ClosedException. <BR>
    * キューにオブジェクトrを加えます。<BR>
    * もし、キューがすでに閉じられているときは、ClosedExceptionを投げます。<BR>
    * <<追加>>
    * requestVectorのサイズがbuffer_sizeを超える場合は、バッファへの追加を
    * キャンセルし、例外ThreadBufferExceptionをスローします。
    */
    protected void add(Object r)
        throws ClosedException, ThreadBufferException {
        if (closed){
            throw new ClosedException("Queue closed .... ");
        }
        
        if (requestVector.size() > bufferSize) {
            throw new ThreadBufferException(
                "buffer size[" + requestVector.size() + "] buffer full");
        }

        synchronized (requestVector) {
            requestVector.addElement(r);
            requestVector.notifyAll();
        }
    }

    /**
     * Fetches and Removes the next available object in the queue. 
     * This method blocks if the queue is empty.
     * キューの次の利用できるオブジェクトをフェッチ(吸い出)して移し
     * ます。もしキューが空っぽなら、このメソッドは塞ぎます。
     */
    protected Object fetch(WorkerThread thread) {
        synchronized (requestVector) {
            while (requestVector.size() == 0) {
                try {
                    thread.setWaitStatus(); //adding
                    requestVector.wait();
                    thread.unsetWaitStatus(); //adding
                } catch (InterruptedException ie) {
                }
            }
            Object tmp = requestVector.elementAt(0);
            requestVector.removeElementAt(0);
            return tmp;
        }
    }

    /**
     * Marks the queue as Closed. 
     * Additional add() will throw ClosedException.
     * 排他的だとしてキューをマークします。
     * 追加です加えます( )ClosedExceptionを投げるでしょう。
     */
    void close() {
        closed = true;
    }
}
