package hibergui.generator.tool.io;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * With this class you can read data from <code>InputStream</code> more than
 * once a time.
 * 
 * If you want to reset the position of given <code>InputStream</code> you
 * just have to call <code>reset</code> method without calling
 * <code>mark</code> method before using it.
 * 
 * @author Csaba Gyenge
 */
public class BufferedStream extends InputStream {
	private static final int READ_SIZE = 100;

	private InputStream source;
	private ByteArrayInputStream bis = null;
	private byte[] buffer = null;

	/**
	 * Method to read data from <code>is</code> to an array.
	 * 
	 * @return Array of byte which contains data of given <code>is</code>
	 *         input stream
	 */
	protected static byte[] buffering(InputStream is) throws IOException {
		byte[] array = new byte[READ_SIZE];
		byte[] res = new byte[READ_SIZE];
		byte[] resTemp;
		int pos = 0, size;
		while ((size = is.read(array, 0, READ_SIZE)) != -1) {
			// Resize result array
			if (pos + size > res.length) {
				int actSize = res.length;
				resTemp = new byte[actSize * 2];
				System.arraycopy(res, 0, resTemp, 0, actSize);
				res = resTemp;
			}
			// Copy array
			System.arraycopy(array, 0, res, pos, size);
			pos += size;
		}
		resTemp = new byte[pos];
		System.arraycopy(res, 0, resTemp, 0, pos);
		return resTemp;
	}

	/**
	 * Read data from <code>InputStream</code> more than once a time.
	 * 
	 * @param is
	 *            <code>InputStream</code> to read data from.
	 */
	public BufferedStream(InputStream is) {
		this.source = is;
	}

	@Override
	public int read() throws IOException {
		if (bis == null) {
			buffer = buffering(this.source);
			source.close();
			bis = new ByteArrayInputStream(buffer);
		}
		return bis.read();
	}

	/**
	 * Call this method to reset the input stream. You don't need to use
	 * <code>mark</code> method, or something else before calling this method.
	 */
	@Override
	public synchronized void reset() throws IOException {
		bis = new ByteArrayInputStream(buffer);
	}

	/**
	 * It is always return <code>true</code> because <code>reset</code> is
	 * always supported.
	 * 
	 * @return Constant <code>true</code> value.
	 */
	@Override
	public boolean markSupported() {
		return true;
	}
}
