/**
 * 
 */
package uk.ac.ucl.excites.sapelli.shared.io;

import java.io.IOException;
import java.util.BitSet;

import uk.ac.ucl.excites.sapelli.shared.util.BinaryHelpers;

/**
 * @author mstevens
 * 
 */
public class BitArray
{

	static public BitArray FromBytes(byte[] bytes)
	{
		try
		{
			BitArrayOutputStream baos = new BitArrayOutputStream();
			baos.write(bytes);
			baos.flush();
			baos.close();
			return baos.toBitArray();
		}
		catch(IOException e)
		{
			return null; // should never happen
		}
	}
	
	private final BitSet bits;
	private final int length;
	
	/**
	 * @param length
	 */
	public BitArray(int length)
	{
		this(new BitSet(length), length);
	}
	
	/**
	 * @param bits
	 * @param length
	 */
	public BitArray(BitSet bits, int length)
	{
		if(length < 0)
			throw new IllegalArgumentException("length cannot be negative!");
		this.bits = bits;
		this.length = length;
	}

	public boolean get(int index)
	{
		if(index >= 0 && index < length)
			return bits.get(index);
		throw new IndexOutOfBoundsException("index (" + index + ") out of bounds [0, " + (length - 1) + "]!");
	}
	
	public void set(int index, boolean value)
	{
		if(index >= 0 && index < length)
			bits.set(index, value);
		throw new IndexOutOfBoundsException("index (" + index + ") out of bounds [0, " + (length - 1) + "]!");
	}

	/**
	 * @return the number of bits in the array
	 */
	public int length()
	{
		return length;
	}

	public byte[] toByteArray()
	{
		byte[] bytes = new byte[BinaryHelpers.bytesNeeded(length)];
		for(int i = 0; i < length; i++)
			if(bits.get(i))
				bytes[i / Byte.SIZE] |= 1 << (7 - (i % 8)); //MSB is read first
		return bytes;
	}
	
	/**
	 * Writes the bits to a {@link BitOutputStream}
	 * 
	 * @param bos the BitOutputStream
	 * @throws IOException if an I/O error occurs
	 */
	public void writeTo(BitOutputStream bos) throws IOException
	{
		for(int i = 0; i < length; i++)
			bos.write(bits.get(i));
	}
	
	public int hashCode()
	{
		int hash = 1;
		for(int i = 0; i < length; i++)
			hash = 31 * hash + (get(i) ? 0 : 1);
		return hash;
	}
	
	public boolean equals(Object obj)
	{
		if(this == obj)
			return true;
		if(obj instanceof BitArray)
		{
			BitArray other = (BitArray) obj;
			if(this.length != other.length)
				return false;
			for(int i = 0; i < length; i++)
				if(this.get(i) != other.get(i))
					return false;
			return true;
		}
		return false;
	}
	
	/**
	 * @param offset
	 * @param length
	 * @return a subArray of this one starting with the bit at position offset and the given length or less
	 */
	public BitArray subArray(int offset, int length)
	{
		if(offset < 0 || offset > this.length)
			throw new IndexOutOfBoundsException("offset (" + offset + ") out of bounds [0, " + (this.length - 1) + "]!");
		int to = offset + length;
		if(to > this.length)
			to = this.length;
		BitArray sub = new BitArray(to - offset);
		for(int i = offset; i < to; i++)
			sub.set(i, this.get(i));
		return sub;
	}
	
}

@@ -110,16 +110,44 @@
 BitSet;%0D
+%0Aimport java.util.Iterator;%0D
 %0A%0D%0Aimpor
@@ -261,16 +261,45 @@
 BitArray
+ implements Iterable%3CBoolean%3E
 %0D%0A%7B%0D%0A%0D%0A%09
@@ -1431,24 +1431,463 @@
  %22%5D!%22);%0D%0A%09%7D%0D
+%0A%09%0D%0A%09@Override%0D%0A%09public Iterator%3CBoolean%3E iterator()%0D%0A%09%7B%0D%0A%09%09return new Iterator%3CBoolean%3E()%0D%0A%09%09%7B%0D%0A%09%09%09%0D%0A%09%09%09private int index = 0;%0D%0A%0D%0A%09%09%09@Override%0D%0A%09%09%09public boolean hasNext()%0D%0A%09%09%09%7B%0D%0A%09%09%09%09return index %3C length;%0D%0A%09%09%09%7D%0D%0A%0D%0A%09%09%09@Override%0D%0A%09%09%09public Boolean next()%0D%0A%09%09%09%7B%0D%0A%09%09%09%09return get(index++);%0D%0A%09%09%09%7D%0D%0A%0D%0A%09%09%09@Override%0D%0A%09%09%09public void remove()%0D%0A%09%09%09%7B%0D%0A%09%09%09%09throw new UnsupportedOperationException(%22Cannot remove items from BitArray%22);%0D%0A%09%09%09%7D%0D%0A%09%09%7D;%0D%0A%09%7D%0D
 %0A%0D%0A%09/**%0D%0A%09 *

Add iteration support in BitArray