/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
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 .
Melin Software HB - software@melin.nu - www.melin.nu
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
************************************************************************/
#include "stdafx.h"
#include "oEvent.h"
#include "classconfiginfo.h"
#include "meos_util.h"
void ClassConfigInfo::clear() {
individual.clear();
relay.clear();
patrol.clear();
legNStart.clear();
raceNStart.clear();
legResult.clear();
raceNRes.clear();
rogainingClasses.clear();
timeStart.clear();
hasMultiCourse = false;
hasMultiEvent = false;
hasRentedCard = false;
classWithoutCourse.clear();
maximumLegNumber = 0;
results = false;
starttimes = false;
}
bool ClassConfigInfo::empty() const {
return individual.empty() && rogainingClasses.empty()
&& relay.empty() && patrol.empty()
&& raceNStart.empty() && rogainingTeam.empty();
}
void ClassConfigInfo::getIndividual(set &sel, bool forStartList) const {
sel.insert(individual.begin(), individual.end());
if (forStartList)
sel.insert(rogainingClasses.begin(), rogainingClasses.end());
}
void ClassConfigInfo::getRelay(set &sel) const {
sel.insert(relay.begin(), relay.end());
}
void ClassConfigInfo::getTeamClass(set &sel) const {
sel.insert(relay.begin(), relay.end());
sel.insert(patrol.begin(), patrol.end());
if (!raceNStart.empty())
sel.insert(raceNRes[0].begin(), raceNRes[0].end());
}
bool ClassConfigInfo::hasTeamClass() const {
return !relay.empty() || !patrol.empty() || !raceNRes.empty();
}
void ClassConfigInfo::getPatrol(set &sel) const {
sel.insert(patrol.begin(), patrol.end());
}
void ClassConfigInfo::getRogaining(set &sel) const {
sel.insert(rogainingClasses.begin(), rogainingClasses.end());
}
void ClassConfigInfo::getRogainingTeam(set &sel) const {
sel.insert(rogainingTeam.begin(), rogainingTeam.end());
}
void ClassConfigInfo::getRaceNStart(int race, set &sel) const {
if (size_t(race) < raceNStart.size() && !raceNStart[race].empty())
sel.insert(raceNStart[race].begin(), raceNStart[race].end());
else
sel.clear();
}
void ClassConfigInfo::getLegNStart(int leg, set &sel) const {
if (size_t(leg) < legNStart.size() && !legNStart[leg].empty())
sel.insert(legNStart[leg].begin(), legNStart[leg].end());
else
sel.clear();
}
void ClassConfigInfo::getRaceNRes(int race, set &sel) const {
if (size_t(race) < raceNRes.size() && !raceNRes[race].empty())
sel.insert(raceNRes[race].begin(), raceNRes[race].end());
else
sel.clear();
}
void ClassConfigInfo::getLegNRes(int leg, set &sel) const {
map >::const_iterator res = legResult.find(leg);
if (res != legResult.end())
sel.insert(res->second.begin(), res->second.end());
else
sel.clear();
}
void oEvent::getClassConfigurationInfo(ClassConfigInfo &cnf) const
{
oClassList::const_iterator it;
cnf.clear();
cnf.hasMultiEvent = hasPrevStage() || hasNextStage();
map> runnerPerClass;
for (it = Classes.begin(); it != Classes.end(); ++it) {
if (it->isRemoved())
continue;
cnf.maximumLegNumber = max(cnf.maximumLegNumber, it->getNumStages());
ClassType ct = it->getClassType();
if (it->getCourse() == 0)
cnf.classWithoutCourse.push_back(it->getName()); //MultiCourse not analysed...
if (it->isQualificationFinalBaseClass())
cnf.knockout.push_back(it->getId());
if (Courses.empty() || (it->getCourse(false) == nullptr && it->getCourse(0,0, false) == nullptr) ||
(it->getCourse(false) && it->getCourse(false)->getNumControls() == 0)) {
if (!it->isQualificationFinalBaseClass()) {
// No course.
if (runnerPerClass.empty()) {
for (auto &r : Runners) {
if (!r.skip() && r.getClassRef(false) != nullptr)
runnerPerClass[r.getClassId(true)].push_back(&r);
}
}
map punches;
int cntSample = 0;
for (auto r : runnerPerClass[it->getId()]) {
if (r->getCard()) {
for (auto &p : r->getCard()->punches) {
int tc = p.getTypeCode();
if (tc > 30)
++punches[tc];
}
if (++cntSample > 10)
break;
}
}
bool single = true, extra = true;
if (cntSample > 3) {
int usedControlCodes = 0;
for (auto &p : punches) {
if (p.second >= cntSample / 2)
usedControlCodes++;
}
if (usedControlCodes == 1)
extra = false;
else if (usedControlCodes > 1)
single = false;
}
if (single)
cnf.lapcountsingle.push_back(it->getId());
if (extra)
cnf.lapcountextra.push_back(it->getId());
}
}
if ( !it->hasCoursePool() ) {
for (size_t k = 0; k< it->MultiCourse.size(); k++) {
if (it->MultiCourse[k].size() > 1)
cnf.hasMultiCourse = true;
}
}
if (ct == oClassIndividual) {
if (it->isRogaining())
cnf.rogainingClasses.push_back(it->getId());
else
cnf.individual.push_back(it->getId());
if (cnf.timeStart.empty())
cnf.timeStart.resize(1);
cnf.timeStart[0].push_back(it->getId());
}
else if ((ct == oClassPatrol || ct == oClassRelay) && it->isRogaining()) {
cnf.rogainingTeam.push_back(it->getId());
}
else if (ct == oClassPatrol)
cnf.patrol.push_back(it->getId());
else if (ct == oClassRelay) {
cnf.relay.push_back(it->getId());
if (cnf.legNStart.size() < it->getNumStages())
cnf.legNStart.resize(it->getNumStages());
for (size_t k = 0; k < it->getNumStages(); k++) {
StartTypes st = it->getStartType(k);
if (st == STDrawn || st == STHunting) {
cnf.legNStart[k].push_back(it->getId());
if (cnf.timeStart.size() <= k)
cnf.timeStart.resize(k+1);
cnf.timeStart[k].push_back(it->getId());
}
LegTypes lt = it->getLegType(k);
if (!it->isOptional(k) && !it->isParallel(k) && lt != LTGroup) {
int trueN, order;
it->splitLegNumberParallel(k, trueN, order);
cnf.legResult[trueN].push_back(it->getId());
}
}
}
else if (ct == oClassIndividRelay) {
if (cnf.raceNStart.size() < it->getNumStages())
cnf.raceNStart.resize(it->getNumStages());
if (cnf.raceNRes.size() < it->getNumStages())
cnf.raceNRes.resize(it->getNumStages());
for (size_t k = 0; k < it->getNumStages(); k++) {
StartTypes st = it->getStartType(k);
if (st == STDrawn || st == STHunting) {
cnf.raceNStart[k].push_back(it->getId());
if (cnf.timeStart.size() <= k)
cnf.timeStart.resize(k+1);
cnf.timeStart[k].push_back(it->getId());
}
LegTypes lt = it->getLegType(k);
if (lt != LTIgnore && lt != LTExtra && lt != LTGroup)
cnf.raceNRes[k].push_back(it->getId());
}
}
}
oRunnerList::const_iterator rit;
for (rit = Runners.begin(); rit != Runners.end(); ++rit) {
if (rit->isRemoved())
continue;
if (rit->getDCI().getInt("CardFee") != 0) {
cnf.hasRentedCard = true;
}
RunnerStatus st = rit->getStatus();
if (st != StatusUnknown && st != StatusDNS && st != StatusNotCompetiting)
cnf.results = true;
if (rit->getStartTime() > 0)
cnf.starttimes = true;
}
}