/*
 * The MIT License (MIT)
 *
 * Copyright 2015 Valentyn Kolesnikov
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.github.underscore.examples;

import java.util.*;

/**
 * Examples for underscore-java.
 *
 * @author Valentyn Kolesnikov
 */
public class Xor {
    public static <E> List<E> uniq(final List<E> list) {
        return new ArrayList<E>(new HashSet<E>(list));
    }

    public static <E> Optional<E> find(final Iterable<E> iterable, final Predicate<E> pred) {
        for (E element : iterable) {
            if (pred.apply(element)) {
                return Optional.of(element);
            }
        }
        return Optional.absent();
    }

    public static <E> boolean some(final Iterable<E> iterable, final Predicate<E> pred) {
        return find(iterable, pred).isPresent();
    }

    public static <E> boolean contains(final Iterable<E> iterable, final E elem) {
        return some(iterable, new Predicate<E>() {
            @Override
            public Boolean apply(E e) {
                return elem == null ? e == null : elem.equals(e);
            }
        });
    }

    public static <E> List<E> filter(final List<E> list, final Predicate<E> pred) {
        final List<E> filtered = new ArrayList<E>();
        for (E element : list) {
            if (pred.apply(element)) {
                filtered.add(element);
            }
        }
        return filtered;
    }

    public static <E> List<E> difference(final List<E> list1, final List<E> list2) {
        return filter(list1, new Predicate<E>() {
            @Override
            public Boolean apply(E elem) {
                return !contains(list2, elem);
            }
        });
    }

    @SuppressWarnings("unchecked")
    public static <E> E[] toArray(final List<E> iterable) {
        return (E[]) iterable.toArray();
    }

    @SuppressWarnings("unchecked")
    public static <T> List<T> concat(final List<T> first, final List<T> ... other) {
        int length = 0;
        for (List<T> otherItem : other) {
            length += otherItem.size();
        }
        final T[] result = (T[]) Arrays.copyOf(toArray(first), first.size() + length);
        int index = 0;
        for (List<T> otherItem : other) {
            System.arraycopy(toArray(otherItem), 0, result, first.size() + index, otherItem.size());
            index += otherItem.size();
        }
        return (List<T>) Arrays.asList(result);
    }

    public static <T> List<T> xor(final List<T> ... lists) {
        int index = -1;
        int length = lists.length;
        List<T> result = null;
        while (++index < length) {
            final List<T> array = lists[index];
            result = result == null ? array : concat(difference(result, array), difference(array, result));
        }
        return uniq(result);
    }
}

@@ -2953,29 +2953,8 @@
 t%3CT%3E
- first, final List%3CT%3E
  ...
@@ -2975,133 +2975,21 @@
     
+f
 in
-t length = 0;%0A        for (List%3CT%3E otherItem : other) %7B%0A            length += otherItem.size();%0A        %7D%0A        final T%5B%5D
+al List%3CT%3E
  res
@@ -2998,255 +2998,96 @@
 t = 
-(T%5B%5D)
+new
  Array
-s.copyOf(toArray(first), first.size() + length);%0A        int index = 0;%0A        for (List%3CT%3E otherItem : other) %7B%0A            System.arraycopy(toArray(otherItem), 0, result, first.size() + index, otherItem.size());%0A            index += 
+List%3CT%3E();%0A        for (List%3CT%3E otherItem : other) %7B%0A            result.addAll(
 othe
@@ -3095,14 +3095,8 @@
 Item
-.size(
 );%0A 
@@ -3123,39 +3123,14 @@
 urn 
-(List%3CT%3E) Arrays.asList(
 result
-)
 ;%0A  

Improve concat method in examples.