/* * Beanfabrics Framework Copyright (C) by Michael Karneim, beanfabrics.org * Use is subject to license terms. See license.txt. */ // TODO javadoc - remove this comment only when the class and all non-public // methods and fields are documented package org.beanfabrics.model; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.List; import org.beanfabrics.Path; import org.beanfabrics.PathEvaluation; import org.beanfabrics.util.OrderPreservingMap; /** * The {@link DefaultSorter} is the default {@link Sorter} used by * {@link ListPM#sortBy(SortKey...)} and {@link MapPM#sortBy(SortKey...)}. * * @author Michael Karneim */ class DefaultSorter implements Sorter { public <K, V extends PresentationModel> void sortBy(OrderPreservingMap<K, V> map, SortKey... sortKeys) { if (map.isEmpty()) { return; } final int len = map.size(); List<Entry<K, V>> list = new ArrayList<Entry<K, V>>(len); for (int i = 0; i < len; ++i) { K key = map.getKey(i); V value = map.get(i); Entry<K, V> entry = new Entry<K, V>(key, value); list.add(entry); } List<SortKey> reverseKeys = new ArrayList<SortKey>(Arrays.asList(sortKeys)); Collections.reverse(reverseKeys); for (SortKey key : reverseKeys) { Path path = key.getSortPath(); boolean ascending = key.isAscending(); Collections.sort(list, new EntryComparator(new PathComparator(new ModelComparatorImpl(ascending ? 1 : -1), path))); } Collection<K> keys = new LinkedList<K>(); for (Entry<K, V> entry : list) { keys.add(entry.getKey()); } map.reorder(keys); } public <T extends PresentationModel> void sortBy(List<T> list, SortKey... sortKeys) { if (list.isEmpty()) { return; // nothing to do } List<SortKey> reverseKeys = new ArrayList<SortKey>(Arrays.asList(sortKeys)); Collections.reverse(reverseKeys); for (SortKey key : reverseKeys) { Path path = key.getSortPath(); boolean ascending = key.isAscending(); Collections.sort(list, new RowComparator(new PathComparator(new ModelComparatorImpl(ascending ? 1 : -1), path))); } } private static class ComparableComparator implements Comparator<Comparable> { public int compare(Comparable c1, Comparable c2) { final int result; if (c1 == null) { if (c2 == null) { result = 0; } else { result = -1; } } else { if (c2 == null) { result = 1; } else { int classnameComparison = c1.getClass().getName().compareTo(c2.getClass().getName()); if (classnameComparison != 0) { result = classnameComparison; } else { result = c1.compareTo(c2); } } } return result; } } private static class ModelComparatorImpl implements Comparator<PresentationModel> { private final int orderFactor; private final ComparableComparator comparableComparator = new ComparableComparator(); public ModelComparatorImpl(int orderFactor) { this.orderFactor = orderFactor; } public int compare(PresentationModel pm1, PresentationModel pm2) { final int result; if (pm1 == null) { if (pm2 == null) { return 0; } result = -1; } else { Comparable<?> c1 = pm1.getComparable(); if (c1 == null) { result = -1; } else if (pm2 == null) { result = +1; } else { Comparable<?> c2 = pm2.getComparable(); if (c2 == null) { result = +1; } else { result = comparableComparator.compare(c1, c2); } } } return result * orderFactor; } } private static class PathComparator implements Comparator<PresentationModel> { private final Path path; private final Comparator<PresentationModel> delegate; public PathComparator(Comparator<PresentationModel> delegate, Path path) { this.delegate = delegate; this.path = path; } public int compare(PresentationModel c1, PresentationModel c2) { PresentationModel pModel1 = PathEvaluation.evaluateOrNull(c1, path); PresentationModel pModel2 = PathEvaluation.evaluateOrNull(c2, path); return delegate.compare(pModel1, pModel2); } } private static class Entry<K, V> { private final K key; private final V value; public Entry(K key, V value) { super(); this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } } private static class EntryComparator implements Comparator<Entry> { final PathComparator delegate; public EntryComparator(PathComparator delegate) { this.delegate = delegate; } public int compare(Entry e1, Entry e2) { PresentationModel row1 = (PresentationModel)e1.getValue(); PresentationModel row2 = (PresentationModel)e2.getValue(); return delegate.compare(row1, row2); } } private static class RowComparator implements Comparator<PresentationModel> { private final PathComparator delegate; public RowComparator(PathComparator delegate) { this.delegate = delegate; } public int compare(PresentationModel row1, PresentationModel row2) { return delegate.compare(row1, row2); } } }