package ec.gp.semantic;

import java.util.*;

public final class BooleanDesiredSemantics extends DesiredSemanticsBase<Boolean> {
	public BooleanDesiredSemantics(int length) {
		super(init(length, true));
	}
	
	public BooleanDesiredSemantics(ISemantics semantics) {
		super(init(semantics.size(), false));
		
		for (int i = 0; i < semantics.size(); ++i) {
			//this.addValues(i, (boolean) semantics.getValue(i));
			this.values[i] = BooleanDesiredSemanticsNavigableSet.getReadOnlyInstance((boolean) semantics.getValue(i));
		}
	}
	
	@Override
	public void compact() {
		for (int i = 0; i < this.values.length; ++i) {
			switch (this.values[i].size()) {
				case 0:
					this.values[i] = BooleanDesiredSemanticsNavigableSet.getReadOnlyInstance();
					break;
				case 1:
					this.values[i] = BooleanDesiredSemanticsNavigableSet.getReadOnlyInstance(this.values[i].first());
					break;
			}
		}
	}
	
	private static NavigableSet<Boolean>[] init(int length, boolean createSets) {
		NavigableSet<Boolean>[] values = new BooleanDesiredSemanticsNavigableSet[length];
		if (createSets) {
			for (int i = 0; i < length; ++i) {
				values[i] = new BooleanDesiredSemanticsNavigableSet();
			}
		}
		
		return values;
	}
}

final class BooleanDesiredSemanticsNavigableSet implements NavigableSet<Boolean> {
	
	// cache
	private static final BooleanDesiredSemanticsNavigableSet EMPTY = new BooleanDesiredSemanticsNavigableSet(0x00);
	private static final BooleanDesiredSemanticsNavigableSet NULL = new BooleanDesiredSemanticsNavigableSet(0x01);
	private static final BooleanDesiredSemanticsNavigableSet TRUE = new BooleanDesiredSemanticsNavigableSet(0x04);
	private static final BooleanDesiredSemanticsNavigableSet FALSE = new BooleanDesiredSemanticsNavigableSet(0x02);
	
	// bits: 0 = null, 1 = false, 2 = true, 6 = read only set
	private byte mask;
	
	static BooleanDesiredSemanticsNavigableSet getReadOnlyInstance() {
		return EMPTY;
	}
	
	static BooleanDesiredSemanticsNavigableSet getReadOnlyInstance(Boolean value) {
		if (value == null)
			return NULL;
		if (value.booleanValue() == true)
			return TRUE;
		return FALSE;
	}
	
	public BooleanDesiredSemanticsNavigableSet() {
		
	}
	
	private BooleanDesiredSemanticsNavigableSet(int mask) {
		this.mask = (byte) (mask | 0x40); // 0x40 means read only
		assert this.mask >= 0x40; // make sure that resulting number is nonnegative
	}
	
	
	@Override
	public Comparator<? super Boolean> comparator() {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public Boolean first() {
		switch (this.mask & 0x07) {
			case 0:
			case 1:
			case 3:
			case 5:
			case 7:
				return null;
			case 2:
			case 6:
				return false;
			default:
				assert this.mask >= 4;
				return true;
		}
	}
	
	@Override
	public Boolean last() {
		switch (this.mask & 0x07) {
			case 0:
			case 1:
				return null;
			case 2:
			case 3:
				return false;
			default:
				assert this.mask >= 4;
				return true;
		}
	}
	
	@Override
	public int size() {
		// 7 instructions, even faster than Integer.bitCount()
		return (this.mask & 1) + ((this.mask >>> 1) & 1) + ((this.mask >>> 2) & 1);
	}
	
	@Override
	public boolean isEmpty() {
		return (this.mask & 0x07) == 0;
	}
	
	@Override
	public boolean contains(Object o) {
		return (o == null && (this.mask & 1) == 1) ||
				((this.mask & 2) == 2 && (boolean) o == false) ||
				((this.mask & 4) == 4 && (boolean) o);
	}
	
	@Override
	public Object[] toArray() {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public <T> T[] toArray(T[] a) {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public boolean add(Boolean e) {
		assert (this.mask & 0x40) == 0 : "This is read only instance";
		
		if (e == null) {
			this.mask |= 1;
		} else if (e) {
			this.mask |= 4;
		} else {
			this.mask |= 2;
		}
		
		return false;
	}
	
	@Override
	public boolean remove(Object o) {
		assert (this.mask & 0x40) == 0 : "This is read only instance";
		assert o == null || (Boolean) o == false || (Boolean) o == true;
		
		if (o == null) {
			this.mask &= 0xfe;
		} else if ((Boolean) o) {
			this.mask &= 0xfb;
		} else {
			this.mask &= 0xfd;
		}
		
		return false;
	}
	
	@Override
	public boolean containsAll(Collection<?> c) {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public boolean addAll(Collection<? extends Boolean> c) {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public boolean retainAll(Collection<?> c) {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public boolean removeAll(Collection<?> c) {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public void clear() {
		assert (this.mask & 0x40) == 0 : "This is read only instance";
		this.mask = 0;
	}
	
	@Override
	public Boolean lower(Boolean e) {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public Boolean floor(Boolean e) {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public Boolean ceiling(Boolean e) {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public Boolean higher(Boolean e) {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public Boolean pollFirst() {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public Boolean pollLast() {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public Iterator<Boolean> iterator() {
		return new Iterator<Boolean>() {
			
			// Previously checked bit
			private int iteratorMask = (mask & (-mask)) & 0x07;
			
			@Override
			public boolean hasNext() {
				return this.iteratorMask != 0;
			}
			
			@Override
			public Boolean next() {
				Boolean ret;
				
				switch (this.iteratorMask) {
					case 1:
						ret = null;
						break;
					case 2:
						ret = false;
						break;
					default:
						assert this.iteratorMask == 4;
						ret = true;
						break;
				}
				
				assert ((mask & (this.iteratorMask * 0x07) & ~this.iteratorMask)) == (mask & (this.iteratorMask * 0x06));
				//this.iteratorMask = (mask & (this.iteratorMask * 0xFF) & ~this.iteratorMask); // cut off all checked so far bits from the mask
				this.iteratorMask = mask & (this.iteratorMask * 0x06); // cut off all checked so far bits from the mask
				assert this.iteratorMask < 0x40; // make sure, we don't see readonly bit
				this.iteratorMask = this.iteratorMask & -this.iteratorMask; // isolate rightmost 1 bit; HD, ch2-1
				
				return ret;
			}
			
			@Override
			public void remove() {
				throw new UnsupportedOperationException("Not implemented");
			}
			
		};
	}
	
	@Override
	public NavigableSet<Boolean> descendingSet() {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public Iterator<Boolean> descendingIterator() {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public NavigableSet<Boolean> subSet(Boolean fromElement, boolean fromInclusive, Boolean toElement,
	                                    boolean toInclusive) {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public NavigableSet<Boolean> headSet(Boolean toElement, boolean inclusive) {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public NavigableSet<Boolean> tailSet(Boolean fromElement, boolean inclusive) {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public SortedSet<Boolean> subSet(Boolean fromElement, Boolean toElement) {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public SortedSet<Boolean> headSet(Boolean toElement) {
		throw new UnsupportedOperationException("Not implemented");
	}
	
	@Override
	public SortedSet<Boolean> tailSet(Boolean fromElement) {
		throw new UnsupportedOperationException("Not implemented");
	}
	
}
