From 492a726497785e8072e76a415dbbfdbd498e1b92 Mon Sep 17 00:00:00 2001
From: Steru <jerrydream111@gmail.com>
Date: Thu, 15 Aug 2024 20:41:08 +0200
Subject: Reworked Sport class to work with QObjects instead of JSON objects.

---
 src/model/Competitor.h            |  11 +++
 src/model/CompetitorWithResults.h |   4 +
 src/model/Sport.cpp               | 159 ++++++++++-----------------------
 src/model/Sport.h                 | 179 +++++++++++++++++++-------------------
 4 files changed, 151 insertions(+), 202 deletions(-)

(limited to 'src/model')

diff --git a/src/model/Competitor.h b/src/model/Competitor.h
index 1121a5b..e5b0251 100644
--- a/src/model/Competitor.h
+++ b/src/model/Competitor.h
@@ -39,8 +39,19 @@ public:
     QString getName() { return this->name; }
     QString getNOC() { return this->noc; }
 
+    void setCode(int code) { this->code = code; }
+    void setName(QString name) { this->name = name; }
+    void setNOC(QString noc) { this->noc = noc; }
+
     bool setCompetitor(const QJsonObject &competitor);
 
+    static bool compareName(const Competitor &left, const Competitor &right) {
+        return left.name.compare(right.name) < 0;
+    }
+    static bool compareNOC(const Competitor &left, const Competitor &right) {
+        return left.noc.compare(right.noc) < 0;
+    }
+
 private:
     int code;
     QString name;
diff --git a/src/model/CompetitorWithResults.h b/src/model/CompetitorWithResults.h
index a313db2..f57b773 100644
--- a/src/model/CompetitorWithResults.h
+++ b/src/model/CompetitorWithResults.h
@@ -15,6 +15,7 @@ class CompetitorWithResults : public Competitor {
 
     Q_PROPERTY(QString mark READ mark)
     Q_PROPERTY(QString medalType READ medalType)
+    Q_PROPERTY(QString statistic READ statistic WRITE setStatistic)
 
 public:
     CompetitorWithResults() : Competitor() {
@@ -34,15 +35,18 @@ public:
     }
 
     bool setResults(const QJsonObject &results);
+    void setStatistic(QString stat) { this->statistic = stat; }
 
     QString getMark() { return this->mark; }
     QString getMedalType() { return this->medalType; }
+    QString getStatistic() { return this->statistic; }
 
     static bool compare(CompetitorWithResults lComp, CompetitorWithResults rComp);
 
 private:
     QString mark;
     QString medalType;
+    QString statistic;
 
 };
 
diff --git a/src/model/Sport.cpp b/src/model/Sport.cpp
index c7a9c72..4b822fa 100644
--- a/src/model/Sport.cpp
+++ b/src/model/Sport.cpp
@@ -124,60 +124,16 @@ QJsonArray filter(QJsonArray input, function<bool (QJsonObject)> eval) {
     return output;
 }
 
-// static compare function for specific attribute in competitors
-function<bool (const QJsonValue &left, const QJsonValue &right)> genCompare(QString attribute) {
-    return [attribute](const QJsonValue &left, const QJsonValue &right) {
-        QString l = left.toObject()[attribute].toString();
-        QString r = right.toObject()[attribute].toString();
-        return l.compare(r) < 0;
-    };
-}
-
-// static compare function for the results of a competitor in a specific competition (also called mark)
-bool compareMark(const QJsonValue &left, const QJsonValue &right) {
-    // check if one competitor has no mark
-    QJsonObject l = left.toObject();
-    if (!l.contains("results")) return true;
-    QJsonObject r = right.toObject();
-    if (!r.contains("results")) return false;
-
-    QString lMark = l["results"].toObject()["mark"].toString();
-    QString rMark = r["results"].toObject()["mark"].toString();
-
-    // check if the marks are numerical values
-    if (!lMark.contains(":") && !rMark.contains(":")) return lMark.toFloat() < rMark.toFloat();
-
-    // compare time values if not numerical
-    QString lTime(""), rTime("");
-
-    for (QChar c : lMark) if (c.isDigit()) lTime.append(c);
-    for (QChar c : rMark) if (c.isDigit()) rTime.append(c);
-
-    return lTime.compare(rTime) < 0;
-}
-
-// static compare function for the amount of medals a competitor has gotten
-bool compareMedals(const QJsonValue &left, const QJsonValue &right) {
-    QJsonObject lMedals = left.toObject()["medals"].toObject();
-    QJsonObject rMedals = right.toObject()["medals"].toObject();
-
-    int gold = lMedals["ME_GOLD"].toInt() - rMedals["ME_GOLD"].toInt();
-    int silver = lMedals["ME_SILVER"].toInt() - rMedals["ME_SILVER"].toInt();
-    int bronze = lMedals["ME_BRONZE"].toInt() - rMedals["ME_BRONZE"].toInt();
-
-    return gold < 0 || (gold == 0 && (silver < 0 || (silver == 0 && bronze < 0)));
-}
-
 /**
  * @brief Sport::lastName Reduce the full name to the part that is marked in capital letters (probably last name).
  * @param competitors The competitors of one category.
  */
-void Sport::lastName(QJsonArray &competitors) {
+void Sport::lastName(QList<Competitor> &competitors) {
     // validate competitors
-    if (competitors.isEmpty() || !competitors[0].toObject().contains("name")) return;
+    if (competitors.isEmpty()) return;
 
-    for (int i = 0; i < competitors.size(); ++i) {
-        string fullName = competitors[i].toObject()["name"].toString().toUtf8().constData();
+    for (Competitor comp : competitors) {
+        string fullName = comp.getName().toUtf8().constData();
 
         // regex to identify names, written in CAPS
         regex r("[A-Z']{2,}");
@@ -190,15 +146,10 @@ void Sport::lastName(QJsonArray &competitors) {
         for (string s : m) lastName = lastName + s + " ";
 
         // remove last space
-        QJsonValue nameValue = QJsonValue(QString(lastName.substr(0, lastName.size() - 1).c_str()));
+        QString name = QString(lastName.substr(0, lastName.size() - 1).c_str());
 
-        // create new object with replaced name
-        QJsonObject comp(competitors[i].toObject());
-        comp.remove("name");
-        comp.insert("name", nameValue);
-
-        // replace competitor in array
-        competitors.replace(i, comp);
+        // replace competitor name in list
+        comp.setName(name);
     }
 }
 
@@ -237,8 +188,8 @@ set<QString> Sport::getCategories() {
  * @param category The category to search in.
  * @return An QJsonArray with all competitors as QJsonValueRef, which can be casted to QJsonObject.
  */
-QJsonArray Sport::getCompetitorsByCategory(QString category) {
-    QJsonArray competitors;
+QList<CompetitorWithResults> Sport::getCompetitorsByCategory(QString category) {
+    QList<CompetitorWithResults> competitors;
 
     if (!validateDiscipline()) return competitors;
 
@@ -253,21 +204,21 @@ QJsonArray Sport::getCompetitorsByCategory(QString category) {
 
         // add all competitors from one unit
         for (const QJsonValueRef &compRef : unit["competitors"].toArray()) {
-            competitors.push_back(compRef.toObject());
+            competitors.push_back(CompetitorWithResults(compRef.toObject()));
         }
     }
 
-    return QJsonArray(competitors);
+    return competitors;
 }
 
 /**
  * @brief Sport::getCompetitorsWithMedal Filters all competitors, who have at least one medal. These objects are different from getCompetitorsByCategory !!!
  * @return All competitors, who won at least one medal. Structure of one competitor: {code, name, noc, medals{ME_GOLD, ME_SILVER, ME_BRONZE}}
  */
-QJsonArray Sport::getCompetitorsWithMedal() {
+QList<MedalWinner> Sport::getCompetitorsWithMedal() {
     map<QString, QJsonObject> competitors;
 
-    if (!validateDiscipline()) return QJsonArray();
+    if (!validateDiscipline()) return QList<MedalWinner>();
 
     // filter all units, which have medal events
     QJsonArray units = filter(this->discipline["units"].toArray(), [](QJsonObject unit){
@@ -321,9 +272,9 @@ QJsonArray Sport::getCompetitorsWithMedal() {
     }
 
     // convert map to QJsonArray
-    QJsonArray output;
+    QList<MedalWinner> output;
     for (const pair<QString, QJsonObject> &competitor : competitors) {
-        output.append(competitor.second);
+        output.append(MedalWinner(competitor.second));
     }
 
     return output;
@@ -362,8 +313,8 @@ QJsonObject Sport::createCompetitorWithMedals(QJsonObject comp) {
  * @param competitors The competitors of one category.
  * @param name The (part of the) name to search for.
  */
-void Sport::filterByName(QJsonArray &competitors, QString name) {
-    filterCompetitors(competitors, QString("name"), name);
+void Sport::filterByName(QList<Competitor> &competitors, QString name) {
+    filterCompetitors(competitors, name);
 }
 
 /**
@@ -371,8 +322,8 @@ void Sport::filterByName(QJsonArray &competitors, QString name) {
  * @param competitors The competitors of one category.
  * @param nocShort The (part of the) national olympics comittee short name to search for.
  */
-void Sport::filterByCountry(QJsonArray &competitors, QString nocShort) {
-    filterCompetitors(competitors, QString("noc"), nocShort);
+void Sport::filterByCountry(QList<Competitor> &competitors, QString nocShort) {
+    filterCompetitors(competitors, nocShort);
 }
 
 /**
@@ -381,16 +332,12 @@ void Sport::filterByCountry(QJsonArray &competitors, QString nocShort) {
  * @param attribute The attribute to filter by.
  * @param filter The string, which should be contained.
  */
-void Sport::filterCompetitors(QJsonArray &competitors, QString attribute, QString filter) {
-    for (int i = 0; i < competitors.size(); i++) {
-        QJsonObject comp = competitors[i].toObject();
-
-        if (!comp.contains(attribute) || !comp[attribute].toString().contains(filter, Qt::CaseInsensitive)) {
-            // remove the competitor, if the attribute does not fit the filter string
-            competitors.removeAt(i);
+void Sport::filterCompetitors(QList<Competitor> &competitors, QString filter) {
+    for (qsizetype i = 0; i < competitors.size(); i++) {
+        if (competitors.value(i).getNOC().contains(filter)) {
+            competitors.remove(i);
             i--;
         }
-
     }
 }
 
@@ -398,52 +345,49 @@ void Sport::filterCompetitors(QJsonArray &competitors, QString attribute, QStrin
  * @brief Sport::sortByName Sort the competitors by their name (alphabetical, ascending).
  * @param competitors The competitors of one category.
  */
-void Sport::sortByName(QJsonArray &competitors) {
-    sortCompetitors(competitors, genCompare( QString("name") ));
+void Sport::sortByName(QList<Competitor> &competitors) {
+    if (competitors.isEmpty()) return;
+    sort(competitors.begin(), competitors.end(), Competitor::compareName);
 }
 
 /**
  * @brief Sport::sortByCountry Sort the competitors by their national olympic comittee short name (alphabetical, ascending).
  * @param competitors The competitors of one category.
  */
-void Sport::sortByCountry(QJsonArray &competitors) {
-    sortCompetitors(competitors, genCompare( QString("noc") ));
+void Sport::sortByCountry(QList<Competitor> &competitors) {
+    if (competitors.isEmpty()) return;
+    sort(competitors.begin(), competitors.end(), Competitor::compareNOC);
 }
 
 /**
  * @brief Sport::sortByResult Sort the competitors by their results in one specific category (numerical, ascending).
  * @param competitors The competitors of one category.
  */
-void Sport::sortByResult(QJsonArray &competitors) {
+void Sport::sortByResult(QList<CompetitorWithResults> &competitors) {
     if (competitors.isEmpty()) return;
-
-    QJsonObject comp = competitors[0].toObject();
-
-    if (comp.contains("results")) sortCompetitors(competitors, compareMark);
-    else if (comp.contains("medals")) sortCompetitors(competitors, compareMedals);
+    sort(competitors.begin(), competitors.end(), CompetitorWithResults::compare);
 }
 
 /**
- * @brief Sport::sortCompetitors Sorts the given QJsonArray according to the compare function.
+ * @brief Sport::sortByMedals Sort the competitors by their medal amounts in one specific category (numerical, ascending).
  * @param competitors The competitors of one category.
- * @param compare A function to compare two competitors with each other. This defines the order.
  */
-void Sport::sortCompetitors(QJsonArray &competitors, function<bool (const QJsonValue &left, const QJsonValue &right)> compare) {
-    make_heap(competitors.begin(), competitors.end(), compare);
-    sort_heap(competitors.begin(), competitors.end(), compare);
+void Sport::sortByMedals(QList<MedalWinner> &competitors) {
+    if (competitors.isEmpty()) return;
+    sort(competitors.begin(), competitors.end(), MedalWinner::compare);
 }
 
 /**
  * @brief Sport::reverseOrder Reverses the order of the competitors.
  * @param competitors The competitors of one category.
  */
-void Sport::reverseOrder(QJsonArray &competitors) {
+void Sport::reverseOrder(QList<Competitor> &competitors) {
     int iterations = competitors.size() / 2; // automatically rounds down
 
     for (int i = 0; i < iterations; i++) {
-        QJsonObject temp = competitors[i].toObject();
-        competitors[i] = competitors[competitors.size() - 1 - i].toObject();
-        competitors[competitors.size() - 1 - i] = temp;
+        Competitor temp = competitors.value(i);
+        competitors.replace(i, competitors.value(competitors.size() - 1 - i));
+        competitors.replace(competitors.size() - 1 - i, temp);
     }
 }
 
@@ -452,35 +396,22 @@ void Sport::reverseOrder(QJsonArray &competitors) {
  * Stores the statistic in obj->results->stat for each competitor.
  * @param competitors The competitors of one category.
  */
-void Sport::addRelativeToFirst(QJsonArray &competitors) {
+void Sport::addRelativeToFirst(QList<CompetitorWithResults> &competitors) {
     if (competitors.isEmpty()) return;
 
-    QJsonObject reference = competitors[0].toObject();
-
-    // validate competitors
-    if (!reference.contains("results")) return;
-
-    QString refVal = reference["results"].toObject()["mark"].toString();
+    QString reference = competitors.value(0).getMark();
 
-    for (int i = 0; i < competitors.size(); i++) {
-        QJsonObject competitor = competitors[i].toObject();
-        QJsonObject results = competitor["results"].toObject();
-
-        if (results.contains("stat")) results.remove("stat");
+    for (CompetitorWithResults comp : competitors) {
+        QString results = comp.getMark();
 
         // format relative float value to string with 2 digits after decimal point and sign
         stringstream sstream;
-        sstream << fixed << setprecision(2) << calcRelativeStat(refVal, results["mark"].toString());
+        sstream << fixed << setprecision(2) << calcRelativeStat(reference, results["mark"].toString());
         QString stat(sstream.str().c_str());
         stat.append("%");
         if (stat.at(0).isNumber()) stat = QString("+").append(stat);
 
-        results.insert("stat", stat);
-
-        competitor.remove("results");
-        competitor.insert("results", results);
-
-        competitors.replace(i, competitor);
+        comp.setStatistic(stat);
     }
 
 }
diff --git a/src/model/Sport.h b/src/model/Sport.h
index 6a68570..2ca83a3 100644
--- a/src/model/Sport.h
+++ b/src/model/Sport.h
@@ -1,6 +1,8 @@
 #ifndef ITAT_CHALLANGE_OLYMPICS_SPORT_H
 #define ITAT_CHALLANGE_OLYMPICS_SPORT_H
 
+#include "MedalWinner.h"
+#include "CompetitorWithResults.h"
 #include <QAbstractListModel>
 #include <QNetworkAccessManager>
 #include <qcontainerfwd.h>
@@ -9,33 +11,35 @@
 #include <QJsonObject>
 #include <QJsonDocument>
 #include <QString>
+#include <QList>
 #include "EventInfo.h"
 
 using namespace std;
 
-class SportModel : public QAbstractListModel {
+class SportModel : public QAbstractListModel
+{
   Q_OBJECT
 
   Q_PROPERTY(QString discipline READ discipline WRITE setDiscipline NOTIFY disciplineChanged);
 
-  public: 
-    enum Role {
-      EventName = Qt::UserRole + 1,
-      Competitors
-    };
-
-    explicit SportModel(QObject *parent = nullptr);
+public:
+  enum Role
+  {
+    EventName = Qt::UserRole + 1,
+    Competitors
+  };
 
-    virtual int rowCount(const QModelIndex &parent) const override;
-    virtual QVariant data(const QModelIndex &index, int role) const override;
-    virtual QHash<int, QByteArray> roleNames() const override;
+  explicit SportModel(QObject *parent = nullptr);
 
+  virtual int rowCount(const QModelIndex &parent) const override;
+  virtual QVariant data(const QModelIndex &index, int role) const override;
+  virtual QHash<int, QByteArray> roleNames() const override;
 
-    QString discipline() const;
-    void setDiscipline(const QString &discipline);
-  public slots:
-    void request(QString discipline);
-    void parseData();
+  QString discipline() const;
+  void setDiscipline(const QString &discipline);
+public slots:
+  void request(QString discipline);
+  void parseData();
 
   signals:
     void disciplineChanged();
@@ -47,81 +51,80 @@ class SportModel : public QAbstractListModel {
     QNetworkReply *m_reply = nullptr;
 };
 
-class Sport {
+class Sport
+{
 
 public:
-
-    Sport(QJsonObject discipline) {
-        this->discipline = discipline;
-    }
-
-    set<QString> getCategories();
-    QJsonArray getCompetitorsByCategory(QString category);
-    QJsonArray getCompetitorsWithMedal();
-
-    // filter to change the current competitor array
-    void lastName(QJsonArray &competitors);
-    void filterByName(QJsonArray &competitors, QString name);
-    void filterByCountry(QJsonArray &competitors, QString nocShort);
-
-    // sort functions to change the order of the current competitor array
-    void sortByName(QJsonArray &competitors);
-    void sortByCountry(QJsonArray &competitors);
-    void sortByResult(QJsonArray &competitors);
-    void reverseOrder(QJsonArray &competitors);
-
-    // statistic function(s)
-    void addRelativeToFirst(QJsonArray &competitors);
-
-    void setDiscipline(QJsonObject discipline) {
-        this->discipline = QJsonObject(discipline);
-    }
+  Sport(QJsonObject discipline)
+  {
+    this->discipline = discipline;
+  }
+
+  set<QString> getCategories();
+  QList<CompetitorWithResults> getCompetitorsByCategory(QString category);
+  QList<MedalWinner> getCompetitorsWithMedal();
+
+  // filter to change the current competitor array
+  void lastName(QList<Competitor> &competitors);
+  void filterByName(QList<Competitor> &competitors, QString name);
+  void filterByCountry(QList<Competitor> &competitors, QString nocShort);
+
+  // sort functions to change the order of the current competitor array
+  void sortByName(QList<Competitor> &competitors);
+  void sortByCountry(QList<Competitor> &competitors);
+  void sortByResult(QList<CompetitorWithResults> &competitors);
+  void sortByMedals(QList<MedalWinner> &competitors);
+  void reverseOrder(QList<Competitor> &competitors);
+
+  // statistic function(s)
+  void addRelativeToFirst(QList<CompetitorWithResults> &competitors);
+
+  void setDiscipline(QJsonObject discipline)
+  {
+    this->discipline = QJsonObject(discipline);
+  }
 
 private:
-
-    /*
-     * Analysis of provided competitor objects:
-     *
-     * Attributes:
-     * - code
-     * - noc (national olympics comittee)
-     * - name (sometimes the country name? mostly the competitors name)
-     * - order
-     * [- results] (only if the results are out!)
-     *
-     *
-     * Analysis of provided result objects:
-     *
-     * Attributes:
-     * - position
-     * - mark
-     * - medalType
-     * - irk
-     * [- winnerLoserTie] (only if provided in the discipline?)
-     *
-     * Analysis of where to find the medal winners:
-     *
-     * Search for ... in category name.
-     * - "Bronze"
-     * - "Gold"
-     * - "Final"
-     *
-     * ! ATTENTION !
-     * When searching for "Final" there might be "Final A", "Final B", etc.
-     * The results will only be in ONE of these categories!
-     * -> which is good... cause then we can count occurences.
-     */
-    QJsonObject discipline;
-
-    void filterCompetitors(QJsonArray &competitors, QString attribute, QString filter);
-    void sortCompetitors(QJsonArray &competitors,  function<bool (const QJsonValue &left, const QJsonValue &right)> compare);
-
-    bool validateDiscipline();
-    QJsonObject createCompetitorWithMedals(QJsonObject medalComp);
-
-    float calcRelativeStat(QString ref, QString val);
-
+  /*
+   * Analysis of provided competitor objects:
+   *
+   * Attributes:
+   * - code
+   * - noc (national olympics comittee)
+   * - name (sometimes the country name? mostly the competitors name)
+   * - order
+   * [- results] (only if the results are out!)
+   *
+   *
+   * Analysis of provided result objects:
+   *
+   * Attributes:
+   * - position
+   * - mark
+   * - medalType
+   * - irk
+   * [- winnerLoserTie] (only if provided in the discipline?)
+   *
+   * Analysis of where to find the medal winners:
+   *
+   * Search for ... in category name.
+   * - "Bronze"
+   * - "Gold"
+   * - "Final"
+   *
+   * ! ATTENTION !
+   * When searching for "Final" there might be "Final A", "Final B", etc.
+   * The results will only be in ONE of these categories!
+   * -> which is good... cause then we can count occurences.
+   */
+  QJsonObject discipline;
+
+  void filterCompetitors(QList<Competitor> &competitors, QString filter);
+
+  bool validateDiscipline();
+  QJsonObject createCompetitorWithMedals(QJsonObject medalComp);
+
+  float calcRelativeStat(QString ref, QString val);
 };
 
-
-#endif 
+#endif
-- 
cgit v1.2.3