]> git.sesse.net Git - pkanalytics/blob - main.cpp
Do not output a warning for disc transfer during subs; it is not an error.
[pkanalytics] / main.cpp
1 #include <QMediaPlayer>
2 #include <QMainWindow>
3 #include <QApplication>
4 #include <QGridLayout>
5 #include <QShortcut>
6 #include <QInputDialog>
7 #include <QTimer>
8 #include <algorithm>
9 #include <string>
10 #include <map>
11 #include <vector>
12 #include <optional>
13 #include <sqlite3.h>
14 #include "mainwindow.h"
15 #include "events.h"
16 #include "players.h"
17 #include "formations.h"
18 #include "json.h"
19
20 using namespace std;
21
22 sqlite3 *open_db(const char *filename)
23 {
24         sqlite3 *db;
25         int ret = sqlite3_open(filename, &db);
26         if (ret != SQLITE_OK) {
27                 fprintf(stderr, "%s: %s\n", filename, sqlite3_errmsg(db));
28                 exit(1);
29         }
30
31         sqlite3_exec(db, R"(
32                 CREATE TABLE IF NOT EXISTS player (player INTEGER PRIMARY KEY, number VARCHAR, name VARCHAR, gender VARCHAR(1));
33         )", nullptr, nullptr, nullptr);  // Ignore errors.
34
35         sqlite3_exec(db, R"(
36                 CREATE TABLE IF NOT EXISTS match (match INTEGER PRIMARY KEY, description VARCHAR, video_filename VARCHAR);
37         )", nullptr, nullptr, nullptr);  // Ignore errors.
38
39         sqlite3_exec(db, R"(
40                 CREATE TABLE IF NOT EXISTS formation (formation INTEGER PRIMARY KEY, name VARCHAR, offense BOOLEAN NOT NULL);
41         )", nullptr, nullptr, nullptr);  // Ignore errors.
42
43         sqlite3_exec(db, R"(
44                 CREATE TABLE IF NOT EXISTS event (event INTEGER PRIMARY KEY, match INTEGER, t INTEGER, player INTEGER, type VARCHAR, formation INTEGER, FOREIGN KEY (player) REFERENCES player(player), FOREIGN KEY (match) REFERENCES match (match), FOREIGN KEY (formation) REFERENCES formation (formation));
45         )", nullptr, nullptr, nullptr);  // Ignore errors.
46
47         sqlite3_exec(db, "PRAGMA journal_mode=WAL", nullptr, nullptr, nullptr);  // Ignore errors.
48         sqlite3_exec(db, "PRAGMA synchronous=NORMAL", nullptr, nullptr, nullptr);  // Ignore errors.
49         sqlite3_exec(db, "PRAGMA foreign_keys=ON", nullptr, nullptr, nullptr);  // Ignore errors.
50         return db;
51 }
52 int get_match_id(sqlite3 *db, QWidget *parent, int requested_match)
53 {
54         QStringList items;
55         vector<int> ids;
56         bool requested_match_ok = false;
57
58         // Read the list of matches already in the database.
59         sqlite3_stmt *stmt;
60         int ret = sqlite3_prepare_v2(db, "SELECT match, description FROM match ORDER BY match", -1, &stmt, 0);
61         if (ret != SQLITE_OK) {
62                 fprintf(stderr, "SELECT prepare: %s\n", sqlite3_errmsg(db));
63                 abort();
64         }
65         for ( ;; ) {
66                 ret = sqlite3_step(stmt);
67                 if (ret == SQLITE_ROW) {
68                         char buf[256];
69                         snprintf(buf, sizeof(buf), "%s (%d)", sqlite3_column_text(stmt, 1), sqlite3_column_int(stmt, 0));
70                         ids.push_back(sqlite3_column_int(stmt, 0));
71                         if (ids.back() == requested_match) {
72                                 requested_match_ok = true;
73                         }
74                         items.push_back(buf);
75                 } else if (ret == SQLITE_DONE) {
76                         break;
77                 } else {
78                         fprintf(stderr, "SELECT step: %s\n", sqlite3_errmsg(db));
79                         abort();
80                 }
81         }
82         ret = sqlite3_finalize(stmt);
83         if (ret != SQLITE_OK) {
84                 fprintf(stderr, "SELECT finalize: %s\n", sqlite3_errmsg(db));
85                 abort();
86         }
87         items.push_back("Add new…");
88
89         if (requested_match_ok) {
90                 return requested_match;
91         }
92
93         QString chosen_str;
94         {
95                 QInputDialog dialog(parent, Qt::WindowFlags());
96                 dialog.setWindowTitle("Open game");
97                 dialog.setLabelText("Choose game to analyze:");
98                 dialog.setComboBoxItems(items);
99                 dialog.setTextValue(items[items.size() - 2]);
100                 dialog.setOption(QInputDialog::UseListViewForComboBoxItems, true);
101                 if (!dialog.exec()) {
102                         return -1;
103                 }
104                 chosen_str = dialog.textValue();
105         }
106
107         for (unsigned i = 0; i < ids.size(); ++i) {
108                 if (chosen_str == items[i]) {
109                         return ids[i];
110                 }
111         }
112
113         // Must be a new game. Get its name and insert it into the database.
114         bool ok;
115         QString new_game_str = QInputDialog::getText(parent, "New game", "Choose name for new game:", QLineEdit::Normal, "", &ok);
116         if (!ok || new_game_str.isEmpty()) {
117                 return -1;
118         }
119
120         // Insert the new row into the database.
121         ret = sqlite3_prepare_v2(db, "INSERT INTO match (description) VALUES (?)", -1, &stmt, 0);
122         if (ret != SQLITE_OK) {
123                 fprintf(stderr, "INSERT prepare: %s\n", sqlite3_errmsg(db));
124                 abort();
125         }
126
127         QByteArray new_game_utf8 = new_game_str.toUtf8();
128         sqlite3_bind_text(stmt, 1, (const char *)new_game_utf8.data(), new_game_utf8.size(), SQLITE_STATIC);
129
130         ret = sqlite3_step(stmt);
131         if (ret == SQLITE_ROW) {
132                 fprintf(stderr, "INSERT step: %s\n", sqlite3_errmsg(db));
133                 abort();
134         }
135
136         ret = sqlite3_finalize(stmt);
137         if (ret != SQLITE_OK) {
138                 fprintf(stderr, "INSERT finalize: %s\n", sqlite3_errmsg(db));
139                 abort();
140         }
141
142         return sqlite3_last_insert_rowid(db);
143 }
144
145 int main(int argc, char *argv[])
146 {
147         QApplication app(argc, argv);
148         sqlite3 *db = open_db("ultimate.db");
149
150         int requested_match = -1;
151         if (argc >= 2) {
152                 requested_match = atoi(argv[1]);
153         }
154
155         int match_id = get_match_id(db, nullptr, requested_match);
156         if (match_id <= 0) {  // Cancel.
157                 return 0;
158         }
159
160         MainWindow mainWindow(new EventsModel(db, match_id), new PlayersModel(db),
161                               new FormationsModel(db, true), new FormationsModel(db, false),
162                               db, match_id);
163         mainWindow.resize(QSize(1280, 720));
164         mainWindow.show();
165
166         int ret = app.exec();
167
168         // TODO: do this on-demand instead, from a menu
169         export_to_json(db, "ultimate.json");
170
171         return ret;
172 }