/*
	cursus - Race series management program
	Copyright 2011  Simon Arlott

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU 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 General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package eu.lp0.cursus.scoring;

import java.util.Comparator;
import java.util.SortedSet;

import com.google.common.collect.Iterators;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Ordering;
import com.google.common.collect.PeekingIterator;
import com.google.common.collect.TreeMultimap;

import eu.lp0.cursus.db.data.Pilot;

public class GenericOverallPositionData<T extends ScoredData & RacePointsData & OverallPointsData> extends AbstractOverallPositionData<T> {
	private final EqualPositioning equalPositioning;

	public enum EqualPositioning {
		ALWAYS, IF_REQUIRED;
	}

	public GenericOverallPositionData(T scores, EqualPositioning equalPositioning) {
		super(scores);

		this.equalPositioning = equalPositioning;
	}

	@Override
	public LinkedListMultimap<Integer, Pilot> getOverallPositionsWithOrder() {
		// Invert race points with ordered lists of pilots
		Comparator<Pilot> racePlacings = new PilotRacePlacingComparator(scores.getRacePoints());
		TreeMultimap<Integer, Pilot> invOverallPoints = TreeMultimap.create(Ordering.natural(), racePlacings);
		Multimaps.invertFrom(Multimaps.forMap(scores.getOverallPoints()), invOverallPoints);

		// Calculate overall positions
		LinkedListMultimap<Integer, Pilot> overallPositions = LinkedListMultimap.create();
		int position = 1;

		for (Integer points : invOverallPoints.keySet()) {
			SortedSet<Pilot> pilots = invOverallPoints.get(points);

			switch (equalPositioning) {
			case ALWAYS:
				// Always put pilots with the same points in the same position
				overallPositions.putAll(position, pilots);
				position += pilots.size();
				break;

			case IF_REQUIRED:
				// Try to put pilots with the same points in separate positions
				PeekingIterator<Pilot> it = Iterators.peekingIterator(pilots.iterator());
				while (it.hasNext()) {
					Pilot pilot = it.next();
					overallPositions.put(position, pilot);

					// If this pilot does not compare equally with the next pilot, use the next position
					if (!it.hasNext() || racePlacings.compare(it.peek(), pilot) != 0) {
						position++;
					}
				}
				break;
			}
		}

		return overallPositions;
	}
}
@@ -743,26 +743,107 @@
 va.util.
-Comparator
+ArrayList;%0Aimport java.util.Collections;%0Aimport java.util.Comparator;%0Aimport java.util.List
 ;%0Aimport
@@ -1813,16 +1813,88 @@
 nts());%0A
+%09%09Comparator%3CPilot%3E fallbackOrdering = new PilotRaceNumberComparator();%0A
 %09%09TreeMu
@@ -1975,28 +1975,70 @@
 ural(), 
-racePlacings
+Ordering.from(racePlacings).compound(fallbackOrdering)
 );%0A%09%09Mul
@@ -2238,16 +2238,72 @@
 eate();%0A
+%09%09List%3CPilot%3E collectedPilots = new ArrayList%3CPilot%3E();%0A
 %09%09int po
@@ -2865,39 +2865,28 @@
 %09%09%09%09
-overallPositions.put(position, 
+collectedPilots.add(
 pilo
@@ -2916,24 +2916,16 @@
 lot 
-does not 
 compare
+s
  equ
@@ -2954,40 +2954,33 @@
 ot, 
-use
+add
  the
- next position
+m too
 %0A%09%09%09%09%09
-if
+while
  (
-!
 it.h
@@ -2992,10 +2992,10 @@
 t() 
-%7C%7C
+&&
  rac
@@ -3034,17 +3034,17 @@
 ot) 
-!
+=
 = 0) %7B%0A%09
 %09%09%09%09
@@ -3035,24 +3035,263 @@
 t) == 0) %7B%0A%09
+%09%09%09%09%09collectedPilots.add(it.next());%0A%09%09%09%09%09%7D%0A%0A%09%09%09%09%09// Sort them by an arbitrary order%0A%09%09%09%09%09Collections.sort(collectedPilots, fallbackOrdering);%0A%0A%09%09%09%09%09// Add them all to this position%0A%09%09%09%09%09overallPositions.putAll(position, collectedPilots);%0A
 %09%09%09%09%09positio
@@ -3295,22 +3295,46 @@
 tion++;%0A
+%0A
 %09%09%09%09%09
-%7D
+collectedPilots.clear();
 %0A%09%09%09%09%7D%0A%09

use a fallback ordering when race placings are identical