package com.nifty.cloud.ncs;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * FileInputStreamをラップするクラスです。
 *
 */
public class NiftyCloudFileInputStream extends InputStream
{
	private static final Log log = LogFactory.getLog(NiftyCloudFileInputStream.class);

	private File file = null;
	private FileInputStream fis = null;
	private long readMark = 0;
	private long markPoint = 0;

    /**
     * 指定したFileオブジェクトを使用してNiftyCloudFileInputStreamを生成します。
     *
     * @param file
     *  ファイル
     *
     * @throws FileNotFoundException
     *  指定されたファイルが存在しない、または開けないことを示します。
     */
	public NiftyCloudFileInputStream(File file) throws FileNotFoundException
	{
		if (file == null) {
			throw (new IllegalArgumentException("Source File can't be null."));
		}

		this.fis = new FileInputStream(file);
		this.file = file;
	}

    /**
     * 入力ストリームを最後にマークされた位置に再設定します。
     *
     * @throws IOException
     */
	public void reset() throws IOException
	{
		fis.close();
		fis = new FileInputStream(file);

		long skipped = 0;
		long toSkip = markPoint;
		while (toSkip > 0) {
			skipped = fis.skip(toSkip);
			toSkip -= skipped;
		}

		if (log.isDebugEnabled()) {
			log.debug(String.format("Reset to mark point %d after returning %d bytes.", markPoint, readMark));
		}

		readMark = 0;
	}

	@Override
	public boolean markSupported()
	{
		return (true);
	}

	@Override
	public void mark(int readlimit)
	{
		markPoint += readMark;
		readMark = 0;

		if (log.isDebugEnabled()) {
			log.debug(String.format("Input stream marked at %d bytes", markPoint));
		}
	}

	@Override
	public int available() throws IOException
	{
		return (fis.available());
	}

	@Override
	public void close() throws IOException
	{
		fis.close();
	}

	@Override
	public int read() throws IOException
	{
		int readLength = fis.read();
		if (readLength != -1) {
			readMark++;
			return (readLength);
		}
		return (-1);
	}

	@Override
	public int read(byte[] b, int off, int len) throws IOException
	{
		int length = fis.read(b, off, len);

		readMark += length;

		return (length);
	}

	/**
	 * ラップされたFileInputStreamを返却します。
	 *
	 * @return ラップされたFileInputStream
	 */
	public InputStream getWrappedInputStream()
	{
		return (fis);
	}

	@Override
	public long skip(long n) throws IOException
	{
		return (fis.skip(n));
	}

}
