eu.lp0.cursus.scoring.scores.impl.GenericOverallPositionData.java Source code

Java tutorial

Introduction

Here is the source code for eu.lp0.cursus.scoring.scores.impl.GenericOverallPositionData.java

Source

/*
   cursus - Race series management program
   Copyright 2012-2014  Simon Arlott
    
   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 eu.lp0.cursus.scoring.scores.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
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.Sets;
import com.google.common.collect.TreeMultimap;

import eu.lp0.cursus.db.data.Pilot;
import eu.lp0.cursus.db.data.Race;
import eu.lp0.cursus.scoring.data.OverallPointsData;
import eu.lp0.cursus.scoring.data.RaceDiscardsData;
import eu.lp0.cursus.scoring.data.RacePenaltiesData;
import eu.lp0.cursus.scoring.data.RacePointsData;
import eu.lp0.cursus.scoring.data.ScoredData;
import eu.lp0.cursus.scoring.scores.base.AbstractOverallPositionData;
import eu.lp0.cursus.util.PilotRaceNumberComparator;

public class GenericOverallPositionData<T extends ScoredData & RacePointsData & RacePenaltiesData & RaceDiscardsData & OverallPointsData>
        extends AbstractOverallPositionData<T> {
    private final EqualPositioning equalPositioning;
    protected final PilotRacePlacingComparator.PlacingMethod placingMethod;
    private final boolean allSimulatedToEnd;

    public enum EqualPositioning {
        ALWAYS, IF_REQUIRED;
    }

    public GenericOverallPositionData(T scores, EqualPositioning equalPositioning,
            PilotRacePlacingComparator.PlacingMethod placingMethod) {
        this(scores, equalPositioning, placingMethod, false);
    }

    public GenericOverallPositionData(T scores, EqualPositioning equalPositioning,
            PilotRacePlacingComparator.PlacingMethod placingMethod, boolean allSimulatedToEnd) {
        super(scores);

        this.equalPositioning = equalPositioning;
        this.placingMethod = placingMethod;
        this.allSimulatedToEnd = allSimulatedToEnd;
    }

    @Override
    protected LinkedListMultimap<Integer, Pilot> calculateOverallPositionsWithOrder() {
        // Invert race points with ordered lists of pilots
        Comparator<Pilot> racePlacings = new PilotRacePlacingComparator<T>(scores, placingMethod);
        Comparator<Pilot> fallbackOrdering = new PilotRaceNumberComparator();
        TreeMultimap<Integer, Pilot> invOverallPoints = TreeMultimap.create(Ordering.natural(),
                Ordering.from(racePlacings).compound(fallbackOrdering));
        Multimaps.invertFrom(Multimaps.forMap(scores.getOverallPoints()), invOverallPoints);

        // Calculate overall positions
        LinkedListMultimap<Integer, Pilot> overallPositions = LinkedListMultimap.create();
        List<Pilot> collectedPilots = new ArrayList<Pilot>(scores.getPilots().size());
        LinkedList<SortedSet<Pilot>> pilotPointsOrdering = new LinkedList<SortedSet<Pilot>>();
        int position = 1;

        if (allSimulatedToEnd) {
            final Map<Pilot, ? extends Set<Race>> simulatedPilotPoints = scores.getSimulatedPilotPoints();
            Predicate<Pilot> allSimulatedPilot = new Predicate<Pilot>() {
                private final int raceCount = scores.getRaces().size();

                @Override
                public boolean apply(Pilot input) {
                    return simulatedPilotPoints.get(input).size() == raceCount;
                }
            };

            for (Integer points : invOverallPoints.keySet()) {
                SortedSet<Pilot> pilots = Sets.filter(invOverallPoints.get(points),
                        Predicates.not(allSimulatedPilot));
                if (!pilots.isEmpty()) {
                    pilotPointsOrdering.add(pilots);
                }
            }
            for (Integer points : invOverallPoints.keySet()) {
                SortedSet<Pilot> pilots = Sets.filter(invOverallPoints.get(points), allSimulatedPilot);
                if (!pilots.isEmpty()) {
                    pilotPointsOrdering.add(pilots);
                }
            }
        } else {
            for (Integer points : invOverallPoints.keySet()) {
                pilotPointsOrdering.add(invOverallPoints.get(points));
            }
        }

        for (SortedSet<Pilot> pilots : pilotPointsOrdering) {
            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();
                    collectedPilots.add(pilot);

                    // If this pilot compares equally with the next pilot, add them too
                    while (it.hasNext() && racePlacings.compare(it.peek(), pilot) == 0) {
                        collectedPilots.add(it.next());
                    }

                    // Sort them by an arbitrary order
                    Collections.sort(collectedPilots, fallbackOrdering);

                    // Add them all to this position
                    overallPositions.putAll(position, collectedPilots);
                    position += collectedPilots.size();

                    collectedPilots.clear();
                }
                break;
            }
        }

        return overallPositions;
    }
}