/*
*openPilotLog - A FOSS Pilot Logbook Application
*Copyright (C) 2020-2023 Felix Turowsky
*
*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 .
*/
#include "statistics.h"
#include "src/database/database.h"
/*!
* \brief OPL::Statistics::totalTime Looks up Total Blocktime in the flights database
* \param TimeFrame - The timeframe used for the calculations.
* \return Amount of Total Block Time in minutes
*/
int OPL::Statistics::totalTime(TimeFrame time_frame)
{
QString statement;
QDate start;
QString start_date;
switch (time_frame) {
case TimeFrame::AllTime:
statement = QStringLiteral("SELECT SUM(tblk) FROM flights");
break;
case TimeFrame::CalendarYear:
start.setDate(QDate::currentDate().year(), 1, 1);
start_date = QString::number(start.toJulianDay());
start_date.append(QLatin1Char('\''));
start_date.prepend(QLatin1Char('\''));
statement = QLatin1String("SELECT SUM(tblk) FROM flights WHERE doft >= ") + start_date;
break;
case TimeFrame::Rolling12Months:
start = QDate::fromJulianDay(QDate::currentDate().toJulianDay() - 365);
start_date = QString::number(start.toJulianDay());
start_date.append(QLatin1Char('\''));
start_date.prepend(QLatin1Char('\''));
statement = QLatin1String("SELECT SUM(tblk) FROM flights WHERE doft >= ") + start_date;
break;
case TimeFrame::Rolling28Days:
start = QDate::fromJulianDay(QDate::currentDate().toJulianDay() - 28);
start_date = QString::number(start.toJulianDay());
start_date.append(QLatin1Char('\''));
start_date.prepend(QLatin1Char('\''));
statement = QLatin1String("SELECT SUM(tblk) FROM flights WHERE doft >= ") + start_date;
break;
}
auto db_return = DB->customQuery(statement, 1);
if (!db_return.isEmpty())
return db_return.first().toInt();
return 0;
}
/*!
* \brief OPL::Statistics::currencyTakeOffLanding Returns the amount of Take Offs and
* Landings performed in the last x days. If no vallue for days is provided, 90 is used,
* as per EASA regulations
* \return QVector{#TO,#LDG}
*/
QVector OPL::Statistics::countTakeOffLanding(int days)
{
QString startDate = QString::number(QDate::fromJulianDay(QDate::currentDate().toJulianDay() - days).toJulianDay());
// QString startdate = start.toString(Qt::ISODate);
startDate.append(QLatin1Char('\''));
startDate.prepend(QLatin1Char('\''));
QString statement = QLatin1String("SELECT "
" SUM(IFNULL(flights.toDay,0) + IFNULL(flights.toNight,0)) AS 'TO', "
" SUM(IFNULL(flights.ldgDay,0) + IFNULL(flights.ldgNight,0)) AS 'LDG' "
" FROM flights "
" WHERE doft >=") + startDate;
QVector result = DB->customQuery(statement, 2);
// make sure a value is returned instead of NULL
for (const auto &var : result) {
if (var.isNull())
result.replace(result.indexOf(var), 0);
}
return result;
}
QVector> OPL::Statistics::totals()
{
QString statement = QStringLiteral("SELECT "
"printf('%02d',CAST(SUM(tblk) AS INT)/60)||':'||printf('%02d',CAST(SUM(tblk) AS INT)%60) AS 'TOTAL', "
"printf('%02d',CAST(SUM(tSPSE) AS INT)/60)||':'||printf('%02d',CAST(SUM(tSPSE) AS INT)%60) AS 'SP SE', "
"printf('%02d',CAST(SUM(tSPME) AS INT)/60)||':'||printf('%02d',CAST(SUM(tSPME) AS INT)%60) AS 'SP ME', "
"printf('%02d',CAST(SUM(tNIGHT) AS INT)/60)||':'||printf('%02d',CAST(SUM(tNIGHT) AS INT)%60) AS 'NIGHT', "
"printf('%02d',CAST(SUM(tIFR) AS INT)/60)||':'||printf('%02d',CAST(SUM(tIFR) AS INT)%60) AS 'IFR', "
"printf('%02d',CAST(SUM(tPIC) AS INT)/60)||':'||printf('%02d',CAST(SUM(tPIC) AS INT)%60) AS 'PIC', "
"printf('%02d',CAST(SUM(tPICUS) AS INT)/60)||':'||printf('%02d',CAST(SUM(tPICUS) AS INT)%60) AS 'PICUS', "
"printf('%02d',CAST(SUM(tSIC) AS INT)/60)||':'||printf('%02d',CAST(SUM(tSIC) AS INT)%60) AS 'SIC', "
"printf('%02d',CAST(SUM(tDual) AS INT)/60)||':'||printf('%02d',CAST(SUM(tDual) AS INT)%60) AS 'DUAL', "
"printf('%02d',CAST(SUM(tFI) AS INT)/60)||':'||printf('%02d',CAST(SUM(tFI) AS INT)%60) AS 'INSTRUCTOR', "
"printf('%02d',CAST(SUM(tSIM) AS INT)/60)||':'||printf('%02d',CAST(SUM(tSIM) AS INT)%60) AS 'SIMULATOR', "
"printf('%02d',CAST(SUM(tMP) AS INT)/60)||':'||printf('%02d',CAST(SUM(tMP) AS INT)%60) AS 'MultPilot', "
"CAST(SUM(toDay) AS INT) AS 'TO Day', CAST(SUM(toNight) AS INT) AS 'TO Night', "
"CAST(SUM(ldgDay) AS INT) AS 'LDG Day', CAST(SUM(ldgNight) AS INT) AS 'LDG Night' "
"FROM flights");
QVector columns = {QLatin1String("total"), QLatin1String("spse"), QLatin1String("spme"),
QLatin1String("night"), QLatin1String("ifr"), QLatin1String("pic"),
QLatin1String("picus"), QLatin1String("sic"), QLatin1String("dual"),
QLatin1String("fi"), QLatin1String("sim"), QLatin1String("multipilot"),
QLatin1String("today"), QLatin1String("tonight"), QLatin1String("ldgday"),
QLatin1String("ldgnight")
};
QSqlQuery query(statement);
QVector> output;
QString value;
query.next();
for (const auto &column : columns) {
value = query.value(columns.indexOf(column)).toString();
if (!value.isEmpty()) {
output.append(QPair{column, value});
} else {
output.append(QPair{column, QLatin1String("00:00")});
}
}
return output;
}
/*!
* \brief Calculates the date of expiry for the take-off and landing currency.
*
* The default value for days is 90.
* \return
*/
QDate OPL::Statistics::currencyTakeOffLandingExpiry(int expiration_days)
{
int number_of_days = 0;
QVector takeoff_landings;
// Check if enough take-offs and landings exist within the expiration period, if that's not the case
// we are out of currency and we can stop right there.
takeoff_landings = countTakeOffLanding(expiration_days);
if (takeoff_landings[0].toInt() < 3 || takeoff_landings[1].toInt() < 3)
return QDate::currentDate();
// Go back in time to find a point at which number of Take-Offs and Landings >= 3
for (int i=0; i <= expiration_days; i++) {
takeoff_landings = countTakeOffLanding(i);
//DEB << takeoff_landings;
if (takeoff_landings[0].toInt() >= 3 && takeoff_landings[1].toInt() >= 3) {
number_of_days = i;
//DEB << "Loop position i =" << i;
break;
}
}
// The expiration date of currency is now currentDate - number of days + expiration_days (default 90)
QDate expiration_date = QDate::fromJulianDay(QDate::currentDate().toJulianDay() - number_of_days);
//DEB << expiration_date.addDays(expiration_days);
return expiration_date.addDays(expiration_days);;
}