/*
 * This file is part of Nuts Framework.
 * Copyright(C) 2009-2012 Nuts Develop Team.
 *
 * Nuts Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License any later version.
 * 
 * Nuts Framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Nuts Framework. If not, see <http://www.gnu.org/licenses/>.
 */
package nuts.core.io;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;

/**
 * BitReader
 */
public class BitReader implements Closeable {

	private final static int MASK = 0x80;
	
	private InputStream istream;

	private int rack;
	
	private int mask;
	
	/**
	 * Constructor
	 * @param istream input stream
	 */
	public BitReader(InputStream istream) {
		this.istream = istream;
		reset();
	}
	
	/**
	 * get input stream
	 * @return input stream
	 */
	public InputStream getInputStream() {
		return istream;
	}
	
	/**
	 * reset
	 */
	public void reset() {
		rack = 0;
		mask = MASK;
	}
	
	/**
	 * close the input stream
	 * @throws IOException if an I/O error occurs
	 */
	public void close() throws IOException {
		if (istream != null) {
			istream.close();
		}
	}

	/**
	 * read a bit
	 * @return bit
	 * @throws IOException if an I/O error occurs
	 */
	public int readBit() throws IOException {
		if (mask == MASK) {
			if ((rack = istream.read()) == -1) 
				return -1;
		}
	
		int value = rack & mask;
		
		mask >>= 1;
		if (mask == 0) { 
			mask = MASK;
		}

		return (value != 0 ? 1 : 0);
	}

	
	/**
	 * read bits
	 * @param	size read bits size.
	 * @return bits array
	 * @throws IOException if an I/O error occurs
	 */
	public byte[] readBits(int size) throws IOException { 
		if (size < 0) {
			throw new IllegalArgumentException("Negative read bits size: " + size);
		}

		ByteArrayOutputStream baos = new ByteArrayOutputStream(size);
		
		int b = 0;
		for (int i = 0; i < size; i++) {
			if ((b = readBit()) == -1) {
				break;
			}
			baos.write(b);
		}
		
		return baos.toByteArray();
	}
}
