This is in roboleague.XmlIO. At the top of storeDivisionSeasons(...), add this line:
storeDivisionSeasonsAverages(parent, seasons);
Now make that work by adding these functions:
protected void storeDivisionSeasonsAverages(Element parent,
DivisionSeason[] seasons) {
Element element = parent.getOwnerDocument().createElement("SEASON");
parent.appendChild(element);
element.setAttribute("number", "Overall Averages");
element
.setAttribute("finished", isFinished(seasons) ? "true"
: "false");
storeCompetitorTotals(element, getTotalsAverages(seasons));
storeGroupings(element, getGroupingsAverages(seasons));
}
private boolean isFinished(DivisionSeason[] seasons) {
for (DivisionSeason season : seasons) {
if (!season.getCompleted()) {
return false;
}
}
return true;
}
private CompetitorResults[] getTotalsAverages(DivisionSeason[] seasons) {
TallySet tallies = new TallySet();
for (DivisionSeason season : seasons) {
CompetitorResults[] finalTotals = season.getFinalTotals();
if (finalTotals != null) {
for (CompetitorResults results : finalTotals) {
tallies.tally(results);
}
}
}
return tallies.getAverages();
}
private Collection getGroupingsAverages(DivisionSeason[] seasons) {
Map<Grouping, TallySet> tallies = new HashMap<Grouping, TallySet>();
for (DivisionSeason season : seasons) {
Collection groupings = season.getGroupings();
for (Object resultsObj : groupings) {
Grouping grouping = (Grouping) resultsObj;
if (grouping.getTerminated()) {
TallySet tally;
Grouping key = findGrouping(grouping, tallies.keySet());
if (key == null) {
tally = new TallySet();
tallies.put(grouping, tally);
} else {
tally = tallies.get(key);
}
for (CompetitorResults results : grouping.competitorResults) {
tally.tally(results);
}
}
}
}
Collection<Grouping> avgs = new ArrayList<Grouping>();
for (TallySet tally : tallies.values()) {
avgs.add(new Grouping(tally.getAverages()));
}
return avgs;
}
private Grouping findGrouping(Grouping grouping, Iterable<Grouping> space) {
for (Grouping g : space) {
if (isMatch(grouping, g)) {
return g;
}
}
return null;
}
private boolean isMatch(Grouping g1, Grouping g2) {
if (g1.competitors.length != g2.competitors.length) {
return false;
}
for (Competitor c : g1.competitors) {
if (!contains(g2, c)) {
return false;
}
}
return true;
}
private boolean contains(Grouping grouping, Competitor competitor) {
for (Competitor c2 : grouping.competitors) {
if (competitor.id.equals(c2.id)) {
return true;
}
}
return false;
}
private Collection<CompetitorResults> average(
Map<Competitor, CompetitorResults> avgs,
Map<Competitor, Integer> numSeasons) {
List<CompetitorResults> results = new ArrayList<CompetitorResults>(avgs
.values());
for (int i = 0; i < results.size(); ++i) {
CompetitorResults result = results.get(i);
int seasonCount = numSeasons.get(result.competitor);
result.score /= seasonCount;
result.survival /= seasonCount;
result.lastSurvivorBonus /= seasonCount;
result.bulletDamage /= seasonCount;
result.bulletDamageBonus /= seasonCount;
result.ramDamage /= seasonCount;
result.ramDamageBonus /= seasonCount;
result.firsts /= seasonCount;
result.seconds /= seasonCount;
result.thirds /= seasonCount;
}
Collections.sort(results);
for (int i = 0; i < results.size(); ++i) {
results.get(i).rank = i + i;
}
return results;
}
class TallySet {
Map<Competitor, ResultsTally> tallies = new HashMap<Competitor, ResultsTally>();
void tally(CompetitorResults results) {
ResultsTally tally = tallies.get(results.competitor);
if (tally == null) {
tally = new ResultsTally(results.competitor);
tallies.put(results.competitor, tally);
}
tally.tally(results);
}
public CompetitorResults[] getAverages() {
CompetitorResults[] avgs = new CompetitorResults[tallies.size()];
int i = 0;
for (ResultsTally tally : tallies.values()) {
avgs[i++] = tally.getAvg();
}
Arrays.sort(avgs);
for (i = 0; i < avgs.length; ++i) {
avgs[i].rank = i + 1;
}
return avgs;
}
}
class ResultsTally {
CompetitorResults tally;
int numTallied = 0;
ResultsTally(Competitor competitor) {
tally = new CompetitorResults(competitor);
}
void tally(CompetitorResults results) {
assert results.competitor == tally.competitor;
tally.score += results.score;
tally.survival += results.survival;
tally.lastSurvivorBonus += results.lastSurvivorBonus;
tally.bulletDamage += results.bulletDamage;
tally.bulletDamageBonus += results.bulletDamageBonus;
tally.ramDamage += results.ramDamage;
tally.ramDamageBonus += results.ramDamageBonus;
tally.firsts += results.firsts;
tally.seconds += results.seconds;
tally.thirds += results.thirds;
++numTallied;
}
CompetitorResults getAvg() {
CompetitorResults avg = new CompetitorResults(tally.competitor);
avg.score = tally.score / numTallied;
avg.survival = tally.survival / numTallied;
avg.lastSurvivorBonus = tally.lastSurvivorBonus / numTallied;
avg.bulletDamage = tally.bulletDamage / numTallied;
avg.bulletDamageBonus = tally.bulletDamageBonus / numTallied;
avg.ramDamage = tally.ramDamage / numTallied;
avg.ramDamageBonus = tally.ramDamageBonus / numTallied;
avg.firsts = tally.firsts / numTallied;
avg.seconds = tally.seconds / numTallied;
avg.thirds = tally.thirds / numTallied;
return avg;
}
}
Finally make sure next time we load this Roboleague doesn't try to read in our new avarages & do strange things with them as a season of their own by modifying restoreDivisionSeasons()'s for loop to be:
for (int i = 0; i < nodeList.getLength(); i++) {
Element element = (Element) nodeList.item(i);
String numebrAttribute = element.getAttribute("number");
try {
int number = Integer.valueOf(numebrAttribute).intValue();
Collection groupings = restoreGroupings(element, allCompetitors);
boolean completed = element.getAttribute("finished").equals(
"true");
result.add(new DivisionSeason(number, groupings, completed));
} catch (NumberFormatException err) {
assert numebrAttribute.contains("Overall Averages");
}
}
Now the next time a Division's html results are created, you have overal averages at the bottom! (B.t.w., if someone can get these to show up at the top it would be awesome!).