package com.smaspe.iterables;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * Created by Simon on 15/07/15.
 */
public class _<T> implements Iterable<T> {

    private static final Iterator EMPTY = new Iterator() {
        @Override
        public boolean hasNext() {
            return false;
        }

        @Override
        public Object next() {
            return null;
        }
    };
    private Iterable<T> delegate;

    public _(Iterable<T> delegate) {
        this.delegate = delegate;
    }

    public static <T> _<T> iter(T... array) {
        return _(() -> new Iterator<T>() {
            public int i = 0;

            @Override
            public boolean hasNext() {
                return i < array.length;
            }

            @Override
            public T next() {
                return array[i++];
            }
        });
    }

    public static <T> _<T> chain(Iterable<T>... iterables) {
        return chain(iter(iterables));
    }

    public static <T> _<T> chain(Iterable<Iterable<T>> iterables) {
        return _(() -> new Iterator<T>() {
            Iterator<Iterable<T>> iterator = iterables.iterator();
            Iterator<T> current = EMPTY;

            @Override
            public boolean hasNext() {
                while (!current.hasNext() && iterator.hasNext()) {
                    current = iterator.next().iterator();
                }
                return current.hasNext();
            }

            @Override
            public T next() {
                return current.next();
            }
        });
    }

    public static <T, R> _<R> map(Iterable<T> input, Func<T, R> func) {
        return _(() -> new Iterator<R>() {
            Iterator<T> iter = input.iterator();

            @Override
            public boolean hasNext() {
                return iter.hasNext();
            }

            @Override
            public R next() {
                return func.call(iter.next());
            }
        });
    }

    public static <T> _<T> filter(Iterable<T> input, Func<T, Boolean> func) {
        return _(() -> new Iterator<T>() {
            boolean hasKnownNext = false;
            Iterator<T> iter = input.iterator();
            T nextValue = null;

            @Override
            public boolean hasNext() {
                if (hasKnownNext) {
                    return true;
                }
                while (iter.hasNext()) {
                    nextValue = iter.next();
                    if (func.call(nextValue)) {
                        hasKnownNext = true;
                        return true;
                    }
                }
                return false;
            }

            @Override
            public T next() {
                if (hasNext()) {
                    hasKnownNext = false;
                    return nextValue;
                }
                throw new NoSuchElementException();
            }
        });
    }

    public static <T> _<T> _(Iterable<T> delegate) {
        return new _(delegate);
    }

    public Iterable<T> chainWith(Iterable<T> next) {
        return chain(delegate, next);
    }

    public <R> _<R> map(Func<T, R> func) {
        return map(delegate, func);
    }

    public _<T> filter(Func<T, Boolean> func) {
        return filter(delegate, func);
    }

    @Override
    public Iterator<T> iterator() {
        return delegate.iterator();
    }

    public ArrayList<T> collect() {
        ArrayList<T> res = new ArrayList<>();
        for (T t : delegate) {
            res.add(t);
        }
        return res;
    }

    public interface Func<T, R> {
        R call(T input);
    }
}

@@ -158,16 +158,126 @@
 /07/15.%0A
+ *%0A * Utils class for before Java8 Streams. filters, map, chaining...%0A *%0A * Returned Iterables are never null%0A
  */%0Apubl
@@ -559,120 +559,8 @@
   %7D;
-%0A    private Iterable%3CT%3E delegate;%0A%0A    public _(Iterable%3CT%3E delegate) %7B%0A        this.delegate = delegate;%0A    %7D
 %0A%0A  
@@ -610,33 +610,36 @@
 %0A        return 
-_
+from
 (() -%3E new Itera
@@ -909,32 +909,135 @@
      %7D);%0A    %7D%0A%0A
+    public Iterable%3CT%3E chainWith(Iterable%3CT%3E next) %7B%0A        return _.%3CT%3Echain(delegate, next);%0A    %7D%0A%0A
     public stati
@@ -1202,33 +1202,36 @@
 %0A        return 
-_
+from
 (() -%3E new Itera
@@ -1727,32 +1727,118 @@
      %7D);%0A    %7D%0A%0A
+    public %3CR%3E _%3CR%3E map(Func%3CT, R%3E func) %7B%0A        return map(delegate, func);%0A    %7D%0A%0A
     public stati
@@ -1900,33 +1900,36 @@
 %0A        return 
-_
+from
 (() -%3E new Itera
@@ -2228,32 +2228,126 @@
      %7D);%0A    %7D%0A%0A
+    public _%3CT%3E filter(Func%3CT, Boolean%3E func) %7B%0A        return filter(delegate, func);%0A    %7D%0A%0A
     public stati
@@ -2423,17 +2423,20 @@
  return 
-_
+from
 (() -%3E n
@@ -3304,93 +3304,36 @@
    p
-ublic static %3CT%3E _%3CT%3E _(Iterable%3CT%3E delegate) %7B%0A        return new _(delegate);%0A    %7D
+rivate Iterable%3CT%3E delegate;
 %0A%0A  
@@ -3333,32 +3333,34 @@
 te;%0A%0A    public 
+_(
 Iterable%3CT%3E chai
@@ -3359,213 +3359,113 @@
 %3CT%3E 
-chainWith(Iterable%3CT%3E next) %7B%0A        return chain(delegate, next);%0A    %7D%0A%0A    public %3CR%3E _%3CR%3E map(Func%3CT, R%3E func) %7B%0A        return map(delegate, func);%0A    %7D%0A%0A    public _%3CT%3E filter(Func%3CT, Boolean%3E func
+delegate) %7B%0A        this.delegate = delegate;%0A    %7D%0A%0A    public static %3CT%3E _%3CT%3E from(Iterable%3CT%3E delegate
 ) %7B%0A
@@ -3471,38 +3471,39 @@
 %0A        return 
-filter
+new _%3C%3E
 (delegate, func)
@@ -3487,38 +3487,32 @@
 new _%3C%3E(delegate
-, func
 );%0A    %7D%0A%0A    @O

Add functions. Add fluent interface.