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.lang.reflect.Array;
029import java.util.Collection;
030import java.util.Iterator;
031import java.util.ListIterator;
032
033import com.google.common.base.Function;
034import com.google.common.base.Predicate;
035import com.google.common.base.Predicates;
036import com.google.common.collect.Collections2;
037import com.google.common.collect.Iterators;
038
039import conexp.fx.core.collections.BitSetFX;
040import conexp.fx.core.collections.GuavaFunctions;
041
042public abstract class AbstractSetList<E> implements SetList<E> {
043
044  public AbstractSetList() {
045    super();
046  }
047
048  public AbstractSetList(final Collection<? extends E> c) {
049    super();
050    addAll(c);
051  }
052
053  public boolean add(final E e) {
054    try {
055      add(size(), e);
056      return true;
057    } catch (IllegalArgumentException x) {
058      return false;
059    }
060  }
061
062  public void add(final int i, final E e) {
063    listIterator(i).add(e);
064  }
065
066  public boolean addAll(final Collection<? extends E> c) {
067    return addAll(size(), c);
068  }
069
070  public boolean addAll(final int i, final Collection<? extends E> c) {
071    boolean changed = false;
072    final ListIterator<E> it = listIterator(i);
073    for (E e : c)
074      try {
075        it.add(e);
076        changed = true;
077      } catch (IllegalArgumentException x) {}
078    return changed;
079  }
080
081  public boolean set(final Object o, final E e) {
082    if ((o == null && e == null) || o.equals(e))
083      return false;
084    final ListIterator<E> it = listIterator();
085    while (it.hasNext())
086      if (it.next().equals(o)) {
087        it.set(e);
088        return true;
089      }
090    return false;
091  }
092
093  public E set(final int i, final E e) {
094    final ListIterator<E> it = listIterator(i);
095    if (it.hasNext()) {
096      final E oldElement = it.next();
097      it.set(e);
098      return oldElement;
099    }
100    throw new IndexOutOfBoundsException();
101  }
102
103  public E remove(int i) {
104    final ListIterator<E> it = listIterator(i);
105    if (it.hasNext()) {
106      final E e = it.next();
107      it.remove();
108      return e;
109    }
110    throw new IndexOutOfBoundsException();
111  }
112
113  public boolean remove(final Object o) {
114    final Iterator<E> it = iterator();
115    while (it.hasNext())
116      if (it.next().equals(o)) {
117        it.remove();
118        return true;
119      }
120    return false;
121  }
122
123  public boolean removeAll(final Collection<?> c) {
124    boolean changed = false;
125    final Iterator<E> it = iterator();
126    while (it.hasNext())
127      if (c.contains(it.next())) {
128        it.remove();
129        changed = true;
130      }
131    return changed;
132  }
133
134  public boolean retainAll(final Collection<?> c) {
135    boolean changed = false;
136    final Iterator<E> it = iterator();
137    while (it.hasNext())
138      if (!c.contains(it.next())) {
139        it.remove();
140        changed = true;
141      }
142    return changed;
143  }
144
145  public boolean contains(final Object o) {
146    return indexOf(o) != -1;
147  }
148
149  public boolean containsAll(final Collection<?> c) {
150    for (Object o : c)
151      if (!contains(o))
152        return false;
153    return true;
154  }
155
156  public E get(final int i) {
157    return listIterator(i).next();
158  }
159
160  public final Collection<E> getAll(final Collection<Integer> c, final boolean includeNull) {
161    if (includeNull)
162      return Collections2.transform(c, new Function<Integer, E>() {
163
164        public final E apply(final Integer i) {
165          return get(i);
166        }
167      });
168    else
169      return Collections2.filter(Collections2.transform(c, new Function<Integer, E>() {
170
171        public final E apply(final Integer i) {
172          return get(i);
173        }
174      }), Predicates.notNull());
175  }
176
177  public int indexOf(final Object o) {
178    int i = 0;
179    for (E e : this) {
180      if (e.equals(o))
181        return i;
182      i++;
183    }
184    return -1;
185  }
186
187  public final Collection<Integer> indicesOf(final Collection<?> c, final boolean includeMinusOne) {
188    if (includeMinusOne)
189      return Collections2.transform(c, GuavaFunctions.toGuavaFunction(this::indexOf));
190    else
191      return Collections2.filter(
192          Collections2.transform(c, GuavaFunctions.toGuavaFunction(this::indexOf)),
193          Predicates.not(Predicates.equalTo(-1)));
194  }
195
196  @Deprecated
197  public final int lastIndexOf(final Object o) {
198    return indexOf(o);
199  }
200
201  public final SetList<E> subList(final int from, final int to) {
202    return filter(new Predicate<E>() {
203
204      public final boolean apply(final E e) {
205        final int i = indexOf(e);
206        return from <= i && i < to;
207      }
208    });
209  }
210
211  public final BitSetFX subBitSet(final Collection<?> c) {
212    final BitSetFX b = new BitSetFX(size());
213    for (int i : indicesOf(c, true))
214      b.flip(i);
215    return b;
216  }
217
218  public final SetList<E> filter(final Predicate<? super E> p) {
219    return SetLists.filter(this, p);
220  }
221
222  public final Iterator<E> iterator() {
223    return listIterator();
224  }
225
226  public final ListIterator<E> listIterator() {
227    return listIterator(0);
228  }
229
230  public abstract ListIterator<E> listIterator(final int i);
231
232  public boolean isEmpty() {
233    return iterator().hasNext();
234  }
235
236  public int size() {
237    return Iterators.size(iterator());
238  }
239
240  public void clear() {
241    final Iterator<E> it = iterator();
242    while (it.hasNext()) {
243      it.next();
244      it.remove();
245    }
246  }
247
248  public final HashSetArrayList<E> clone() {
249    return new HashSetArrayList<E>(this);
250  }
251
252  public final boolean equals(final Object o) {
253    return o != null
254        && (this == o || (o instanceof SetList && size() == ((SetList<?>) o).size() && containsAll((SetList<?>) o)));
255  }
256
257  public int hashCode() {
258    int hashCode = 1;
259    for (E e : this)
260      hashCode = 23 * hashCode + (e == null ? 0 : e.hashCode());
261    return hashCode;
262  }
263
264  public Object[] toArray() {
265    final Object[] a = new Object[size()];
266    int i = 0;
267    for (E e : this)
268      a[i++] = e;
269    return a;
270  }
271
272  @SuppressWarnings("unchecked")
273  public <T> T[] toArray(T[] a) {
274    if (a == null)
275      throw new NullPointerException();
276    try {
277      if (a.length < size())
278        a = (T[]) Array.newInstance(a.getClass().getComponentType(), size());
279      int i = 0;
280      for (E e : this)
281        a[i++] = (T) e;
282      if (a.length > size())
283        a[size()] = null;
284      return a;
285    } catch (ClassCastException x) {
286      throw new ArrayStoreException();
287    }
288  }
289
290  public final String toString() {
291    final StringBuilder s = new StringBuilder();
292    s.append("{");
293    final Iterator<E> it = iterator();
294    if (it.hasNext())
295      s.append(it.next().toString());
296    while (it.hasNext())
297      s.append(", " + it.next().toString());
298    s.append("}");
299    return s.toString();
300  }
301}