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

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import org.logical_paradox.common.util.Cache;

/**
 * 利用可能リストをファイル上に投影するクラス
 * リストの管理はorg.logical_paradox.common.util.Cacheで行なう
 * 順番の管理がしたい場合，カスタム化されたCacheを使用するように
 * 派生クラスで実装する
 * 
 * @author satoshi akabane@logical-paradox.org
 * @version 1.0
 */
public abstract class AvailableList {
	protected final String filename;
	protected final Cache cache;

	/**
	 * コンストラクタ
	 * @param filename ファイル名
	 */
	public AvailableList(String filename) {
		this(filename, 0);
	}
	/**
	 * コンストラクタ
	 * @param filename ファイル名
	 * @param size フラグメントコレクションのサイズ
	 */
	public AvailableList(String filename, int size) {
		this.filename = filename;
		cache = createCache(size);

		// 断片化ファイルをメモリ上にロードする
		try {
			reload();
		} catch(IOException ioe) {
			// 断片化ファイル自体が存在しなかったので無視
		}
	}
	/**
	 * この利用可能リストで使用するキャッシュオブジェクトを生成する
	 * @param size
	 * @return
	 */
	protected Cache createCache(int size) {
		return new Cache(size);
	}
	/**
	 * 利用可能リストをファイルから読み込んで，完全に更新する
	 * @throws IOException ファイルアクセスに失敗
	 */
	public void reload() throws IOException {
		byte[] buf = new byte[(int)getFileSize()];
		InputStream in = getInputStream();
		in.read(buf);
		in.close();

		ByteBuffer buffer = ByteBuffer.allocate(buf.length).order(ByteOrder.BIG_ENDIAN);
		buffer.rewind();
		buffer.put(buf);
		buffer.rewind();
		restore(buffer);
	}
	/**
	 * バイト列から利用可能リストを復元する処理
	 * @param buffer バイト列
	 * @throws IOException 復元処理中に例外が発生した
	 */
	protected abstract void restore(ByteBuffer buffer) throws IOException;

	/**
	 * メモリ上にキャッシュされている断片化情報をファイルに出力する
	 * @throws IOException ファイルアクセスに失敗
	 */
	public abstract void flush() throws IOException;

	/**
	 * 断片化レコードキャッシュを返す
	 * 
	 * @return キャッシュ
	 */
	public Cache getCache() {
		return cache;
	}
	//-----------------------------------------------------------------------
	// ファイル以外のデータソースを使用する場合，ここ以降をオーバーライドする
	//-----------------------------------------------------------------------
	/**
	 * ファイルアクセスに必要な入力ストリームを返す
	 * 必ずファイルの先頭をポイントしている
	 * @return 入力ストリーム
	 * @throws IOException オープンに失敗した
	 */	
	protected InputStream getInputStream() throws IOException {
		return new BufferedInputStream(new FileInputStream(filename));
	}
	/**
	 * ファイルアクセスに必要な出力ストリームを返す
	 * 必ずファイルの先頭をポイントしている．また，このメソッドを呼ぶと既存のファイルは破棄される．
	 * @return 出力ストリーム
	 * @throws IOException オープンに失敗した
	 */
	protected OutputStream getOutputStream() throws IOException {
		return new BufferedOutputStream(new FileOutputStream(filename));
	}
	/**
	 * 断片化ファイルのファイルサイズを返す
	 * @return ファイルサイズ
	 * @throws IOException 断片化ファイルにアクセスできなかった
	 */
	protected long getFileSize() throws IOException {
		return new File(filename).length();
	}
}
