/* * This file is part of LibrePlan * * Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e * Desenvolvemento Tecnolóxico de Galicia * Copyright (C) 2010-2011 Igalia, S.L. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.libreplan.business.util; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.NoSuchElementException; import org.apache.commons.lang3.Validate; /** * This class wraps a list that is kept sorted if and only if modify method is * called as modifications are done. There cannot be elements a and b at * different positions such as a == b. * <p> * No null elements allowed * <p> * This class it NOT THREAD SAFE * @author Óscar González Fernández <ogonzalez@igalia.com> */ public class ListSorter<T> { private final List<T> list; private final Comparator<T> comparator; public static <T extends Comparable<T>> ListSorter<T> create( Collection<T> elements) { return create(elements, new Comparator<T>() { @Override public int compare(T o1, T o2) { return o1.compareTo(o2); } }); } public static <T> ListSorter<T> create(Collection<T> elements, Comparator<T> comparator) { Validate.notNull(elements); Validate.notNull(comparator); Validate.noNullElements(elements); return new ListSorter<T>(elements, comparator); } private ListSorter(Collection<? extends T> elements, Comparator<T> comparator) { this.comparator = comparator; this.list = new ArrayList<T>(elements); Collections.sort(this.list, this.comparator); } /** * Called to retrieve a view to a list that will be kept sorted and updated * with modifications * @return an unmodifiable view of the list. It's sorted */ public List<T> toListView() { return Collections.unmodifiableList(list); } /** * Repositions the element since element could have been changed * @param element * the element to be repositioned * @throws NoSuchElementException * if there is no element e in list such e == element */ public void modified(T element) throws NoSuchElementException { int index = indexOfElement(element); if ((index == list.size())) { throw new NoSuchElementException("not found: " + element); } list.remove(index); insert(element); } private void insert(T element) { int position = Collections.binarySearch(list, element, comparator); assert position < 0 : "the object must not be in the list"; position = (-position) - 1; list.add(position, element); } private int indexOfElement(T element) { int index = 0; for (T t : list) { if (t == element) { break; } index++; } return index; } /** * Adds the element at the right position keeping the order. * @throws IllegalArgumentException * if the element already existed * @param element */ public void add(T element) { Validate.notNull(element); if (exists(element)) { throw new IllegalArgumentException(element + " already exists. Duplicateds not allowed"); } insert(element); } /** * @param element * @throws IllegalArgumentException * it the element doesn't exist */ public void remove(T element) { int position = indexOfElement(element); if (position == list.size()) { throw new NoSuchElementException(element + " doesn't exist"); } list.remove(position); } private boolean exists(T element) { int index = indexOfElement(element); return index < list.size(); } }