/******************************************************************************
* Copyright (c) 2016 Oracle
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Konstantin Komissarchik - initial implementation and ongoing maintenance
******************************************************************************/
package org.eclipse.sapphire.util;
import static org.eclipse.sapphire.modeling.util.MiscUtil.equal;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.SortedSet;
import java.util.TreeSet;
import org.eclipse.sapphire.Filter;
/**
* @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
*/
public final class SortedSetFactory<E>
{
private final Comparator<E> comparator;
private Filter<E> filter;
private E firstElement = null;
private SortedSet<E> set = null;
private boolean exported = false;
private SortedSetFactory( final Comparator<E> comparator )
{
this.comparator = comparator;
}
@SuppressWarnings( "unchecked" )
public static <E> SortedSet<E> empty()
{
return (SortedSet<E>) EMPTY_SORTED_SET;
}
public static <E> SortedSet<E> singleton( final E element )
{
if( element == null )
{
throw new IllegalArgumentException();
}
return new SingletonSortedSet<E>( null, element );
}
@SafeVarargs
public static <E> SortedSet<E> unmodifiable( final E... elements )
{
return SortedSetFactory.<E>start().add( elements ).result();
}
public static <E> SortedSet<E> unmodifiable( final Collection<E> elements )
{
return SortedSetFactory.<E>start().add( elements ).result();
}
public static <E> SortedSetFactory<E> start()
{
return start( null );
}
public static <E> SortedSetFactory<E> start( final Comparator<E> comparator )
{
return new SortedSetFactory<E>( comparator );
}
public SortedSetFactory<E> filter( final Filter<E> filter )
{
if( this.exported )
{
throw new IllegalStateException();
}
this.filter = filter;
if( this.filter != null )
{
if( this.set != null )
{
for( Iterator<E> itr = this.set.iterator(); itr.hasNext(); )
{
if( ! this.filter.allows( itr.next() ) )
{
itr.remove();
}
}
final int size = this.set.size();
if( size == 1 )
{
this.firstElement = this.set.first();
this.set = null;
}
else if( size == 0 )
{
this.set = null;
}
}
else if( this.firstElement != null )
{
if( ! this.filter.allows( this.firstElement ) )
{
this.firstElement = null;
}
}
}
return this;
}
public SortedSetFactory<E> add( final E element )
{
if( this.exported )
{
throw new IllegalStateException();
}
if( element != null && ( this.filter == null || this.filter.allows( element ) ) )
{
if( this.set != null )
{
this.set.add( element );
}
else if( this.firstElement != null )
{
this.set = new TreeSet<E>( this.comparator );
this.set.add( this.firstElement );
this.set.add( element );
this.firstElement = null;
}
else
{
this.firstElement = element;
}
}
return this;
}
@SafeVarargs
public final SortedSetFactory<E> add( final E... elements )
{
if( elements != null )
{
for( E element : elements )
{
add( element );
}
}
return this;
}
public SortedSetFactory<E> add( final Collection<E> elements )
{
if( elements != null )
{
for( E element : elements )
{
add( element );
}
}
return this;
}
public boolean remove( final E element )
{
boolean removed = false;
if( element != null )
{
if( this.set != null )
{
removed = this.set.remove( element );
if( this.set.size() == 1 )
{
this.firstElement = this.set.iterator().next();
this.set = null;
}
}
else if( this.firstElement != null && this.firstElement.equals( element ) )
{
removed = true;
this.firstElement = null;
}
}
return removed;
}
public E first()
{
E first;
if( this.set != null )
{
first = this.set.first();
}
else if( this.firstElement != null )
{
first = this.firstElement;
}
else
{
throw new NoSuchElementException();
}
return first;
}
public E last()
{
E last;
if( this.set != null )
{
last = this.set.last();
}
else if( this.firstElement != null )
{
last = this.firstElement;
}
else
{
throw new NoSuchElementException();
}
return last;
}
public boolean contains( final E element )
{
boolean contains = false;
if( this.set != null )
{
contains = this.set.contains( element );
}
else if( this.firstElement != null && this.firstElement.equals( element ) )
{
contains = true;
}
return contains;
}
public int size()
{
final int size;
if( this.set != null )
{
size = this.set.size();
}
else if( this.firstElement != null)
{
size = 1;
}
else
{
size = 0;
}
return size;
}
public SortedSet<E> result()
{
if( this.exported )
{
throw new IllegalStateException();
}
this.exported = true;
if( this.set != null )
{
return Collections.unmodifiableSortedSet( this.set );
}
else if( this.firstElement != null )
{
return new SingletonSortedSet<E>( this.comparator, this.firstElement );
}
else
{
return empty();
}
}
private static final Iterator<Object> EMPTY_ITERATOR = new Iterator<Object>()
{
public boolean hasNext()
{
return false;
}
public Object next()
{
throw new NoSuchElementException();
}
public void remove()
{
throw new UnsupportedOperationException();
}
};
private static final Object[] EMPTY_ARRAY = new Object[ 0 ];
private static final SortedSet<Object> EMPTY_SORTED_SET = new SortedSet<Object>()
{
public int size()
{
return 0;
}
public boolean isEmpty()
{
return true;
}
public boolean contains( final Object object )
{
return false;
}
public Iterator<Object> iterator()
{
return EMPTY_ITERATOR;
}
public Object[] toArray()
{
return EMPTY_ARRAY;
}
public <T> T[] toArray( final T[] array )
{
if( array.length > 0 )
{
array[ 0 ] = null;
}
return array;
}
public boolean add( final Object object )
{
throw new UnsupportedOperationException();
}
public boolean remove( Object object )
{
throw new UnsupportedOperationException();
}
public boolean containsAll( final Collection<?> collection )
{
return false;
}
public boolean addAll( final Collection<? extends Object> collection )
{
throw new UnsupportedOperationException();
}
public boolean retainAll( final Collection<?> collection )
{
throw new UnsupportedOperationException();
}
public boolean removeAll( final Collection<?> collection )
{
throw new UnsupportedOperationException();
}
public void clear()
{
throw new UnsupportedOperationException();
}
public Comparator<? super Object> comparator()
{
return null;
}
public SortedSet<Object> subSet( final Object fromElement,
final Object toElement )
{
return EMPTY_SORTED_SET;
}
public SortedSet<Object> headSet( final Object toElement )
{
return EMPTY_SORTED_SET;
}
public SortedSet<Object> tailSet( final Object fromElement )
{
return EMPTY_SORTED_SET;
}
public Object first()
{
return new NoSuchElementException();
}
public Object last()
{
return new NoSuchElementException();
}
};
private static final class SingletonSortedSet<E> implements SortedSet<E>
{
private final Comparator<E> comparator;
private final E entry;
public SingletonSortedSet( final Comparator<E> comparator,
final E entry )
{
this.comparator = comparator;
this.entry = entry;
}
public int size()
{
return 1;
}
public boolean isEmpty()
{
return false;
}
@SuppressWarnings( "unchecked" )
public boolean contains( final Object object )
{
return ( this.comparator == null ? equal( this.entry, object ) : this.comparator.compare( this.entry, (E) object ) == 0 );
}
public boolean containsAll( final Collection<?> collection )
{
for( Object object : collection )
{
if( ! contains( object ) )
{
return false;
}
}
return true;
}
public Iterator<E> iterator()
{
return new Iterator<E>()
{
private boolean hasNext = true;
public boolean hasNext()
{
return this.hasNext;
}
public E next()
{
if( this.hasNext )
{
this.hasNext = false;
return SingletonSortedSet.this.entry;
}
throw new NoSuchElementException();
}
public void remove()
{
throw new UnsupportedOperationException();
}
};
}
public Object[] toArray()
{
return new Object[] { this.entry };
}
@SuppressWarnings( "unchecked" )
public <T> T[] toArray( final T[] array )
{
T[] a = array;
if( a.length == 0 )
{
a = (T[]) java.lang.reflect.Array.newInstance( a.getClass().getComponentType(), 1 );
a[ 0 ] = (T) this.entry;
}
else
{
a[ 0 ] = (T) this.entry;
if( a.length > 1 )
{
a[ 1 ] = null;
}
}
return a;
}
public boolean add( final E object )
{
throw new UnsupportedOperationException();
}
public boolean remove( final Object object )
{
throw new UnsupportedOperationException();
}
public boolean addAll( final Collection<? extends E> collection )
{
throw new UnsupportedOperationException();
}
public boolean retainAll( final Collection<?> collection )
{
throw new UnsupportedOperationException();
}
public boolean removeAll( final Collection<?> collection )
{
throw new UnsupportedOperationException();
}
public void clear()
{
throw new UnsupportedOperationException();
}
public Comparator<? super E> comparator()
{
return null;
}
public SortedSet<E> subSet( final E fromElement,
final E toElement )
{
return empty();
}
public SortedSet<E> headSet( final E toElement )
{
return empty();
}
public SortedSet<E> tailSet( final E fromElement )
{
if( contains( fromElement ) )
{
return this;
}
return empty();
}
public E first()
{
return this.entry;
}
public E last()
{
return this.entry;
}
@Override
public String toString()
{
return "[" + this.entry.toString() + "]";
}
}
}