/* * Copyright 2013 Guidewire Software, Inc. */ package gw.lang.enhancements; import static gw.lang.enhancements.OrderedList.Direction.ASCENDING; import static gw.lang.enhancements.OrderedList.Direction.DESCENDING; import gw.util.IOrderedList; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.AbstractList; @SuppressWarnings({"UnusedDeclaration"}) public class OrderedList<T> extends AbstractList<T> implements IOrderedList<T> { enum Direction{ ASCENDING, DESCENDING } private static class Tuple<T> { private Direction _direction; private IToComparable<T> _block; private Comparator _comparator; public Tuple( Direction direction, IToComparable<T> block, Comparator comparator ) { _direction = direction; _block = block; _comparator = comparator; } public Direction getDirection() { return _direction; } public IToComparable<T> getBlock() { return _block; } public Comparator getComparator() { return _comparator; } } private List<Tuple<T>> _orderByBlocks = new LinkedList<Tuple<T>>(); private Iterable<T> _originalValues = null; private List<T> _values = null; public OrderedList( Iterable<T> values ) { _originalValues = values; } public void addOrderBy( IToComparable<T> block) { addOrderBy(block, null); } public void addOrderBy( IToComparable<T> block, Comparator comparator ) { checkSort(); checkOrderBy(); _orderByBlocks.add( new Tuple<T>( ASCENDING, block, comparator ) ); } public void addOrderByDescending( IToComparable<T> block ) { addOrderByDescending( block, null ); } public void addOrderByDescending( IToComparable<T> block, Comparator comparator ) { checkSort(); checkOrderBy(); _orderByBlocks.add( new Tuple<T>( DESCENDING, block, comparator ) ); } public OrderedList<T> addThenBy( IToComparable<T> block ) { return addThenBy( block, null ); } public OrderedList<T> addThenBy( IToComparable<T> block, Comparator comparator ) { checkSort(); OrderedList<T> lst = new OrderedList<T>( _originalValues ); lst._orderByBlocks = new LinkedList<Tuple<T>>( _orderByBlocks ); lst._orderByBlocks.add( new Tuple<T>( ASCENDING, block, comparator ) ); return lst; } public OrderedList<T> addThenByDescending( IToComparable<T> block) { return addThenByDescending( block, null ); } public OrderedList<T> addThenByDescending( IToComparable<T> block, Comparator comparator ) { checkSort(); OrderedList<T> lst = new OrderedList<T>( _originalValues ); lst._orderByBlocks = new LinkedList<Tuple<T>>( _orderByBlocks ); lst._orderByBlocks.add( new Tuple<T>( DESCENDING, block, comparator ) ); return lst; } public T get( int index ) { maybeSort(); return _values.get( index ); } public int size() { maybeSort(); return _values.size(); } public Iterator<T> iterator() { maybeSort(); return _values.iterator(); } private void checkOrderBy() { if( _orderByBlocks.size() > 0 ) { throw new IllegalStateException( "You can only orderBy() once. After that, you must use thenBy()" ); } } private void checkSort() { if( _values != null ) { throw new IllegalStateException( "This list has already been sorted!" ); } } private void maybeSort() { if( _values == null ) { _values = new ArrayList<T>(); for (T originalValue : _originalValues) { _values.add(originalValue); } Collections.sort( _values, new Comparator<T>() { public int compare( T o1, T o2 ) { for( Tuple<T> orderByBlock : _orderByBlocks ) { Comparable c1 = orderByBlock.getBlock().toComparable(o1); Comparable c2 = orderByBlock.getBlock().toComparable(o2); Comparator comparator = orderByBlock.getComparator(); int ascendingCmp = comparator != null ? comparator.compare(c1, c2) : c1.compareTo( c2 ); @SuppressWarnings({"unchecked"}) int cmp = (orderByBlock.getDirection() == Direction.ASCENDING) ? ascendingCmp : (ascendingCmp < 0 ? 1 : - ascendingCmp); if( cmp != 0 ) { return cmp; } } return 0; } } ); } } public static interface IToComparable<T> { Comparable toComparable(T elt); } }