001/*
002 * @author Francesco.Kriegel@gmx.de
003 */
004package conexp.fx.core.collections.setlist;
005
006/*-
007 * #%L
008 * Concept Explorer FX
009 * %%
010 * Copyright (C) 2010 - 2019 Francesco Kriegel
011 * %%
012 * This program is free software: you can redistribute it and/or modify
013 * it under the terms of the GNU General Public License as
014 * published by the Free Software Foundation, either version 3 of the
015 * License, or (at your option) any later version.
016 * 
017 * This program is distributed in the hope that it will be useful,
018 * but WITHOUT ANY WARRANTY; without even the implied warranty of
019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
020 * GNU General Public License for more details.
021 * 
022 * You should have received a copy of the GNU General Public
023 * License along with this program.  If not, see
024 * <http://www.gnu.org/licenses/gpl-3.0.html>.
025 * #L%
026 */
027
028import java.util.Collection;
029import java.util.Comparator;
030import java.util.HashSet;
031import java.util.List;
032import java.util.Map;
033import java.util.Set;
034import java.util.Spliterator;
035import java.util.Spliterators;
036import java.util.concurrent.ConcurrentHashMap;
037import java.util.function.BiPredicate;
038
039import com.google.common.base.Predicate;
040import com.google.common.collect.Sets;
041
042import conexp.fx.core.collections.BitSetFX;
043import conexp.fx.core.math.GuavaIsomorphism;
044import conexp.fx.core.math.Isomorphism;
045
046public interface SetList<E> extends Set<E>, List<E>, Collection<E>, Iterable<E>, Cloneable {
047
048  public boolean set(Object o, E e);
049
050  public Collection<E> getAll(Collection<Integer> c, boolean includeNull);
051
052  public Collection<Integer> indicesOf(Collection<?> c, boolean includeMinusOne);
053
054  @Deprecated
055  public int lastIndexOf(Object o);
056
057  public SetList<E> filter(Predicate<? super E> p);
058
059  public SetList<E> subList(int from, int to);
060
061  public BitSetFX subBitSet(Collection<?> c);
062
063  public default HashSetArrayList<E> clone() {
064    return new HashSetArrayList<E>(this);
065  }
066
067  public default GuavaIsomorphism<E, Integer> indexGuava() {
068    return new GuavaIsomorphism<E, Integer>() {
069
070      @Override
071      public final Integer apply(final E e) {
072        return indexOf(e);
073      }
074
075      @Override
076      public final E invert(final Integer i) {
077        return get(i);
078      }
079    };
080  }
081
082  public default Isomorphism<E, Integer> index() {
083    return new Isomorphism<E, Integer>(this::indexOf, this::get);
084  }
085
086  public default Isomorphism<E, Integer> currentIndex() {
087    final Map<E, Integer> indexOfMap = new ConcurrentHashMap<>();
088    final Map<Integer, E> getMap = new ConcurrentHashMap<>();
089    int i = 0;
090    for (E e : this) {
091      indexOfMap.put(e, i);
092      getMap.put(i, e);
093      i++;
094    }
095    return new Isomorphism<E, Integer>(indexOfMap::get, getMap::get);
096  }
097
098  @Override
099  default Spliterator<E> spliterator() {
100    return Spliterators.spliterator(this, Spliterator.ORDERED);
101  }
102
103  default LecticOrder<E> getLecticOrder() {
104    return new LecticOrder<E>(this);
105  }
106
107  public class LecticOrder<E> {
108
109    private final SetList<E> base;
110
111    private LecticOrder(final SetList<E> base) {
112      super();
113      this.base = base;
114    }
115
116    public static final <T> Comparator<T> toComparator(final BiPredicate<T, T> isSmallerPredicate) {
117      return (x, y) -> x.equals(y) ? 0 : isSmallerPredicate.test(x, y) ? -1 : 1;
118    }
119
120    public final Comparator<E> getIndexComparator() {
121      return (x, y) -> {
122        final int i = base.indexOf(x);
123        final int j = base.indexOf(y);
124        if (i == j)
125          return 0;
126        if (i < j)
127          return -1;
128        return 1;
129      };
130    }
131
132    public final Comparator<Set<E>> getLecticComparator() {
133      return toComparator(this::isSmaller);
134    }
135
136    public final Comparator<Set<E>> getLecticComparator(final E element) {
137      return toComparator((x, y) -> isSmaller(x, y, element));
138    }
139
140    public final boolean isSmaller(final Set<E> set1, final Set<E> set2) {
141      return !set1.equals(set2) && Sets
142          .symmetricDifference(set1, set2)
143          .stream()
144          .sorted(getIndexComparator())
145          .findFirst()
146          .map(set2::contains)
147          .get();
148    }
149
150    public final boolean isSmaller(final Set<E> set1, final Set<E> set2, final E element) {
151//      if (set1.equals(set2))
152//        return false;
153//      if (!set2.contains(element))
154//        return false;
155//      return Stream
156//          .concat(
157//              set1.parallelStream().filter(
158//                  s -> !set2.contains(
159//                      s)),
160//              set2.parallelStream().filter(
161//                  s -> !set1.contains(
162//                      s)))
163//          .min(
164//              getSetListComparator(
165//                  base))
166//          .get()
167//          .equals(
168//              element);
169      return !set1.equals(set2) && set2.contains(element) && Sets
170          .symmetricDifference(set1, set2)
171          .stream()
172          .sorted(getIndexComparator())
173          .findFirst()
174          .get()
175          .equals(element);
176    }
177
178    public final Set<E> oplus(final Set<E> set, final E m) {
179      final Set<E> result = new HashSet<E>(set);
180      result.retainAll(base.subList(0, base.indexOf(m)));
181      result.add(m);
182      return result;
183    }
184
185  }
186}