package ceylon.language;

import java.util.Arrays;

import com.redhat.ceylon.compiler.metadata.java.TypeInfo;

public class ArraySequence<Element> implements Sequence<Element> {

	private final Element[] array;
	private final long first;

	public ArraySequence(Element... array) {
		this.array = array;
		this.first = 0;
	}

    public ArraySequence(Element[] array, long first) {
        this.array = array;
        this.first = first;
    }

	@Override
    @TypeInfo("ceylon.language.Natural")
	public long getLastIndex() {
		return getEmpty() ? null : array.length - first - 1;
	}

	@Override
	public Element getFirst() {
		return getEmpty() ? null : array[(int) first];
	}

	@Override
	public Sequence<? extends Element> getRest() {
		return new ArraySequence<Element>(array, first + 1);
	}

	@Override
	public boolean getEmpty() {
		return array.length <= first;
	}

	@Override
    @TypeInfo("ceylon.language.Natural")
	public long getSize() {
		return getEmpty() ? 0 : array.length - first;
	}

	@Override
	public Element getLast() {
		return getEmpty() ? null : array[array.length - 1];
	}

	@Override
	public boolean defines(Natural index) {
		throw new RuntimeException("Not implemented yet");
	}

	@Override
	public Iterator<Element> getIterator() {
		return new ArraySequenceIterator<Element>(this);
	}

	public static class ArraySequenceIterator<Element> implements Iterator<Element> {

		private final Sequence<? extends Element> sequence;

		public ArraySequenceIterator(Sequence<? extends Element> sequence) {
			this.sequence = sequence;
		}

		@Override
		public Element getHead() {
			return sequence.getFirst();
		}

		@Override
		public Iterator<Element> getTail() {
			return new ArraySequenceIterator<Element>(sequence.getRest());
		}

	}

	@Override
	public Element item(Natural key) {
		return key.longValue() >= getSize() ? 
		        null : array[(int) (key.longValue() - first)];
	}

	@Override
	public Category getKeys() {
		throw new RuntimeException("Not implemented yet");
	}

	@Override
	public boolean definesEvery(Iterable<? extends Natural> keys) {
		throw new RuntimeException("Not implemented yet");
	}

	@Override
	public boolean definesAny(Iterable<? extends Natural> keys) {
		throw new RuntimeException("Not implemented yet");
	}

	@Override
	public Sequence<Element> items(Iterable<? extends Natural> keys) {
		throw new RuntimeException("Not implemented yet");
	}

	@Override
	public Sequence<Element> getClone() {
		throw new RuntimeException("Not implemented yet");
	}

    @Override
    public java.lang.String getElementsString() {
        return Sequence$impl.getElementsString(this);
    }

	@Override
	public Sequence<? extends Element> span(long from, long to) {
		if(from >= to)
			return new ArraySequence<Element>();
		if(to > getLastIndex())
			return new ArraySequence<Element>(array, from);
		Element[] newArray = Arrays.copyOfRange(array, (int)from, (int)to);
		return new ArraySequence<Element>(newArray);
	}

	/*@Override
	public Ordered<Element> segment(long from, long length) {
		return Ordered$Impl.segment(this, from, length);
	}*/
}
@@ -1314,32 +1314,57 @@
 r() %7B%0D%0A%09%09return 
+getEmpty() ? null : %0D%0A%09%09%09
 new ArraySequenc
@@ -1790,69 +1790,237 @@
 %0A%09%09%09
-return new ArraySequenceIterator%3CElement%3E(sequence.getRest())
+Sequence%3C? extends Element%3E rest = sequence.getRest();%0D%0A%09%09%09return rest.getEmpty() ? null :%0D%0A%09%09%09%09new ArraySequenceIterator%3CElement%3E(rest);%0D%0A%09%09%7D%0D%0A%09%09%0D%0A%09%09@Override%0D%0A%09%09public java.lang.String toString() %7B%0D%0A%09%09%09return %22SequenceIterator%22
 ;%0D%0A%09
@@ -3277,24 +3277,338 @@
 Array);%0D%0A%09%7D%0D
+%0A%09%0D%0A%09@Override%0D%0A%09public java.lang.String toString() %7B%0D%0A%09%09if (getEmpty()) return %22%7B%7D%22;%0D%0A%09%09StringBuilder result = new StringBuilder(%22%7B %22);%0D%0A%09%09for (Element elem: array) %7B%0D%0A%09%09%09result.append(elem)%0D%0A%09%09%09%09.append(%22, %22);%0D%0A%09%09%7D%0D%0A%09%09result.setLength(result.length()-2);%0D%0A%09%09result.append(%22 %7D%22);%0D%0A%09%09return result.toString();%0D%0A%09%7D%0D
 %0A%0D%0A%09/*@Overr

Fix ArraySequence