package ceylon.language;

import java.util.Arrays;

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

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

	private final java.lang.Object[] array;
	private final long first;

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

    ArraySequence(java.lang.Object[] 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 (Element) (getEmpty() ? null : array[(int) first]);
	}

	@Override
	public Iterable getRest() {
		if (first+1==array.length) {
			return $empty.getEmpty();
		}
		else {
			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 (Element) (getEmpty() ? null : array[array.length - 1]);
	}

	@Override
	public boolean defines(Natural index) {
		return index.value+first<array.length;
	}

	@Override
	public Iterator<Element> getIterator() {
		return getEmpty() ? null : 
			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() {
			Iterable rest = sequence.getRest();
			return rest.getEmpty() ? null :
				new ArraySequenceIterator<Element>((Sequence<? extends Element>) rest);
		}
		
		@Override
		public java.lang.String toString() {
			return "SequenceIterator";
		}

	}

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

	@Override
	public Category getKeys() {
		return Correspondence$impl.getKeys(this);
	}

	@Override
	public boolean definesEvery(Iterable<? extends Natural> keys) {
		return Correspondence$impl.definesEvery(this, keys);
	}

	@Override
	public boolean definesAny(Iterable<? extends Natural> keys) {
		return Correspondence$impl.definesAny(this, keys);
	}

	@Override
	public Iterable<? extends Element> items(Iterable<? extends Natural> keys) {
		return Correspondence$impl.items(this, keys);
	}

	@Override
	public Sequence<Element> getClone() {
		return 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);
		java.lang.Object[] newArray = Arrays.copyOfRange(array, (int)from, (int)to);
		return new ArraySequence<Element>(newArray, 0);
	}
	
	@Override
	public java.lang.String toString() {
		return Sequence$impl.toString(this);
	}

	/*@Override
	public Ordered<Element> segment(long from, long length) {
		return Ordered$Impl.segment(this, from, length);
	}*/
}
@@ -562,36 +562,16 @@
 %09%09return
- getEmpty() ? null :
  array.l
@@ -656,37 +656,16 @@
 Element)
- (getEmpty() ? null :
  array%5B(
@@ -675,17 +675,16 @@
 ) first%5D
-)
 ;%0D%0A%09%7D%0D%0A%0D
@@ -926,29 +926,13 @@
 urn 
-array.length %3C= first
+false
 ;%0D%0A%09
@@ -1028,25 +1028,8 @@
 turn
- getEmpty() ? 0 :
  arr
@@ -1117,29 +1117,8 @@
 ent)
- (getEmpty() ? null :
  arr
@@ -1137,17 +1137,16 @@
 gth - 1%5D
-)
 ;%0D%0A%09%7D%0D%0A%0D
@@ -1219,13 +1219,19 @@
 dex.
-v
+longV
 alue
+()
 +fir
@@ -1322,33 +1322,8 @@
 urn 
-getEmpty() ? null : %0D%0A%09%09%09
 new 
@@ -1347,22 +1347,9 @@
 ator
-%3CElement%3E(this
+(
 );%0D%0A
@@ -1366,15 +1366,8 @@
 lic 
-static 
 clas
@@ -1389,25 +1389,16 @@
 Iterator
-%3CElement%3E
  impleme
@@ -1428,174 +1428,8 @@
 %0D%0A%0D%0A
-%09%09private final Sequence%3C? extends Element%3E sequence;%0D%0A%0D%0A%09%09public ArraySequenceIterator(Sequence%3C? extends Element%3E sequence) %7B%0D%0A%09%09%09this.sequence = sequence;%0D%0A%09%09%7D%0D%0A%0D%0A
 %09%09@O
@@ -1477,25 +1477,16 @@
 %09return 
-sequence.
 getFirst
@@ -1573,17 +1573,8 @@
 t = 
-sequence.
 getR
@@ -1619,83 +1619,26 @@
 ll :
-%0D%0A%09%09%09%09new ArraySequenceIterator%3CElement%3E((Sequence%3C? extends Element%3E) rest
+ rest.getIterator(
 );%0D%0A
@@ -1798,54 +1798,86 @@
 %0D%0A%09%09
-return (Element) (key.longValue() %3E= getSize()
+long index = key.longValue()+first;%0D%0A%09%09return (Element) (index %3E= array.length
  ? %0D
@@ -1910,33 +1910,13 @@
 nt) 
-(key.longValue() - first)
+index
 %5D);%0D

simplify impl of ArraySequence (it is never empty)