/*
	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.LinkedListMultimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Ordering;
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> getOverallPositions() {
		// 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.keys()) {
			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
				Pilot prevPilot = null;
				for (Pilot pilot : pilots) {
					// If this pilot does not compare equally with the previous pilot, use the next position
					if (prevPilot != null && racePlacings.compare(prevPilot, pilot) != 0) {
						position++;
					}
					overallPositions.put(position, pilot);
					prevPilot = pilot;
				}
				// Update the position after the last pilot added
				if (prevPilot != null) {
					position++;
				}
				break;
			}
		}

		return overallPositions;
	}
}
@@ -784,16 +784,60 @@
 edSet;%0A%0A
+import com.google.common.collect.Iterators;%0A
 import c
@@ -968,16 +968,66 @@
 dering;%0A
+import com.google.common.collect.PeekingIterator;%0A
 import c
@@ -2468,63 +2468,182 @@
 %09%09%09P
-ilot prevPilot = null;%0A%09%09%09%09for (Pilot pilot : pilots) %7B
+eekingIterator%3CPilot%3E it = Iterators.peekingIterator(pilots.iterator());%0A%09%09%09%09while (it.hasNext()) %7B%0A%09%09%09%09%09Pilot pilot = it.next();%0A%09%09%09%09%09overallPositions.put(position, pilot);%0A
 %0A%09%09%09
@@ -2699,16 +2699,12 @@
 the 
-previous
+next
  pil
@@ -2742,28 +2742,28 @@
 if (
-prevPilot !
+it.peek() =
 = null 
-&&
+%7C%7C
  rac
@@ -2780,25 +2780,25 @@
 compare(
-prevPilot
+it.peek()
 , pilot)
@@ -2835,182 +2835,8 @@
 %09%09%7D%0A
-%09%09%09%09%09overallPositions.put(position, pilot);%0A%09%09%09%09%09prevPilot = pilot;%0A%09%09%09%09%7D%0A%09%09%09%09// Update the position after the last pilot added%0A%09%09%09%09if (prevPilot != null) %7B%0A%09%09%09%09%09position++;%0A
 %09%09%09%09

simplify by using a PeekingIterator