/**
 * LOGICAL-PARADOX.ORG
 * Copyright (C)2004 satoshi akabane(akabane@logical-paradox.org)
 *
 */
package org.logical_paradox.common.util;

import java.util.Iterator;

/**
 * 汎用キャッシュクラス
 * <br>
 * キャッシュの限界サイズを超えて登録しようとした場合，古いものから削除される
 * @author satoshi akabane@logical-paradox.org
 * @version 1.0
 */
public class Cache {
	// キャッシュの限界サイズ
	protected int limit;
	protected CacheCollection collection;

	/**
	 * デフォルトコンストラクタ
	 * キャッシュアウトしない設定で初期化される
	 */
	public Cache() {
		this(0);
	}
	/**
	 * コンストラクタ
	 * 指定されたキャッシュサイズを超えた場合，古いものがキャッシュアウトする．<br>
	 * sizeに0を指定した場合，キャッシュアウトされない
	 * 
	 * @param size サイズ
	 */
	public Cache(int size) {
		limit = size;
		collection = new CacheCollection();
	}
	/**
	 * このキャッシュを管理しているコレクションのイテレータを返す
	 * @return イテレータ
	 */
	public Iterator iterator() {
		return new CacheIterator(this);
	}
	/**
	 * キャッシュコレクションを設定する
	 * 特定の振る舞いをするキャッシュコレクションクラスを使用したい場合に使用する．
	 * 
	 * @param c コレクション
	 */
	protected void setCacheCollection(CacheCollection c) {
		collection = c;
	}
	/**
	 * キャッシュから最も妥当なオブジェクトを取り出す
	 * 取り出されたオブジェクトはキャッシュから削除される．<br>
	 * 特殊なアルゴリズムを導入したい場合，このメソッドをオーバーライドして実装する．
	 * 
	 * @return 取り出されたオブジェクト
	 */
	public synchronized Object getOne() {
		return collection.removeFirst();
	}
	/**
	 * キャッシュアウトする
	 * 派生クラスでキャッシュアウトのアルゴリズムを変更したい場合，<br>
	 * このメソッドをオーバーライドして実装すること．
	 * 
	 * @return キャッシュアウトしたオブジェクト
	 */
	protected Object cacheOut() {
		return getOne();
	}
	/**
	 * キャッシュにオブジェクトを追加する
	 * キャッシュサイズを超えた場合，妥当なキャッシュドオブジェクトがキャッシュアウトされる
	 * 
	 * @param o 追加するオブジェクト
	 * @return キャッシュアウトしたオブジェクト(null: なし)
	 */
	public Object add(Object o) {
		Object rc = null;
		synchronized(collection) {
			if(collection.size() == limit) {
				rc = cacheOut();
			}
			collection.add(o);
		}
		return rc;
	}
	/**
	 * キャッシュから指定されたオブジェクトを削除する
	 * 
	 * @param o 削除対象のオブジェクト
	 * @return 削除されたオブジェクト
	 */
	public synchronized boolean remove(Object o) {
		return collection.remove(o);
	}
	/**
	 * このキャッシュの容量を返す
	 * 
	 * @return キャッシュのサイズ(レコード数)
	 */
	public synchronized int size() {
		return collection.size();
	}

	/**
	 * キャッシュを扱うイテレータ
	 * @author satoshi akabane@logical-paradox.org
	 * @version $Revision: 1.3 $
	 */
	private class CacheIterator implements Iterator {
		/** キャッシュ */
		private final Cache cache;

		/**
		 * コンストラクタ
		 * @param c キャッシュ
		 */
		private CacheIterator(Cache c) {
			cache = c;
		}
		/**
		 * 先頭の要素を1つ捨てる
		 */
		public void remove() {
			synchronized(cache) {
				cache.getOne();
			}
		}
		/**
		 * キャッシュに要素が残っているかどうかを返す
		 * @return true:ある / false:ない
		 */
		public boolean hasNext() {
			synchronized(cache) {
				return cache.size() > 0;
			}
		}
		/**
		 * 次の要素を返す
		 * 取り出された要素はキャッシュから削除される
		 * @return 取り出された値
		 */
		public Object next() {
			synchronized(cache) {
				return cache.getOne();
			}
		}
	}
}
