calculate_parking/calculate_parking_tickets/calculate_parking_tickets_algorithms.cpp

324 lines
12 KiB
C++

#include "calculate_parking_tickets_algorithms.h"
#include "calculate_parking_tickets_global.h"
#include "calculate_parking_tickets_tariff_step.h"
#include "calculate_parking_tickets_utils.h"
#include "calculate_parking_tickets_tariff.h"
#include "calculate_parking_tickets_day.h"
#include <QDebug>
#include <QDateTime>
#include <cmath>
/* BEGRIFFE
bezahltes Parken am Ende der Parkdauer vor Einsteigen ins Auto:
pay on foot parking
bezahltes Parken am Anfang der Parkdauer und Quittung an der Windschutzscheibe
pay and display parking
Parkdauer
parking time
Parkschein
parking voucher
Parkgutschein
parking voucher
Maximale Parkdauer
maximal parking time
*/
#if 0
bool get_price(parking_tariff_t const *tariff, QDateTime const &qdt,
uint32_t &price_units) {
QDate const &qdate = qdt.date();
QTime const &qtime = qdt.time();
qDebug() << qdate << qtime;
if (!TUtils::isHoliday(tariff, qdate)) {
int const dayOfWeek = qdate.dayOfWeek();
switch (dayOfWeek) {
case Qt::Monday:
return Monday::price(tariff, qtime, &price_units);
case Qt::Tuesday:
return Tuesday::price(tariff, qtime, &price_units);
case Qt::Wednesday:
return Wednesday::price(tariff, qtime, &price_units);
case Qt::Thursday:
return Thursday::price(tariff, qtime, &price_units);
case Qt::Friday:
return Friday::price(tariff, qtime, &price_units);
case Qt::Saturday:
return Saturday::price(tariff, qtime, &price_units);
case Qt::Sunday:
return Sunday::price(tariff, qtime, &price_units);
}
}
return false;
// return Holiday::price(tariff, qtime, &price_units);
}
#endif
#ifdef __cplusplus
extern "C" {
#endif
static bool checkCalculatePreConditions(parking_tariff_t const* tariff,
minute_t startMinute, // CET
minute_t endMinute, // CET
struct price_t *price) {
if (startMinute > endMinute) {
qCritical() << "startMinute > endMinute ("
<< startMinute << endMinute << ")";
return false;
}
minute_t const parkingTime = endMinute - startMinute;
if (parkingTime == 0) {
qCritical() << "startMinute == endMinute => no parking time";
return false;
}
if (tariff->max_parking_time != -1) {
if (parkingTime > tariff->max_parking_time) {
qCritical() << "parkingTime" << parkingTime
<< ">" << tariff->max_parking_time;
return false;
}
}
minute_t const effectiveStartMinute = startMinute + tariff->free_of_charge;
QDateTime const start = TUtils::fromMinutes(startMinute);
//QDateTime const effStart = TUtils::fromMinutes(effectiveStartMinute);
QDateTime const end = TUtils::fromMinutes(endMinute);
if (effectiveStartMinute > endMinute) {
fprintf(stderr,
"[start:%02d:%02d, ende:%02d:%02d]: %ld free minutes. no charge.\n",
start.time().hour(), start.time().minute(),
end.time().hour(), end.time().minute(), tariff->free_of_charge);
memset(price, 0x00, sizeof(*price));
return false;
}
// start algorithm
return true;
}
#define DEBUG_INTERNAL 1
TariffStep const *
compute_price_for_parking_ticket_internal(parking_tariff_t const *tariff,
minute_t startMinute, // CET
minute_t endMinute, // CET
struct price_t *price) {
TariffStep const *stepDbg = nullptr;
QDateTime const start = TUtils::fromMinutes(startMinute);
QDateTime const end = TUtils::fromMinutes(endMinute);
int const minute = start.time().minute();
int const hour = start.time().hour();
int const day = start.date().dayOfWeek()-Qt::Monday;
int const week = 0;
// printf("%d%d%04d\n", week, day, hour*60+minute);
TariffStep const *step = &tariff->m_tariffSteps[week][day][hour*60+minute];
// TODO: tageslimit muss beruecksichtigt werden
stepDbg = step;
uint32_t price_units = 0;
if (tariff->max_price_for_24_hours == (uint32_t)(-1)) {
while (step->dateTime() < end) {
price_units += step->price();
step = step->next();
}
} else {
QDateTime stepDateTime = step->dateTime();
QDateTime nextStepDateTime;
// QDateTime prevStepDateTime;
QDateTime _24hDateTime = stepDateTime;
uint32_t _24h_price_units = 0;
long t0 = _24hDateTime.toSecsSinceEpoch();
bool dbg = true;
while (stepDateTime < end) {
long const t1 = stepDateTime.toSecsSinceEpoch();
uint32_t const price_units_tmp = step->price();
step = step->next();
nextStepDateTime = step->dateTime();
long const diff = t1 - t0;
if (diff < SECS_PER_DAY) {
_24h_price_units += price_units_tmp;
if (_24h_price_units > tariff->max_price_for_24_hours) {
_24h_price_units = tariff->max_price_for_24_hours;
if (dbg) {
#if DEBUG_INTERNAL
fprintf(stderr,
"[%s:%02d:%02d %d]\n",
stepDateTime.date().toString().toStdString().c_str(),
stepDateTime.time().hour(), stepDateTime.time().minute(),
_24h_price_units);
dbg = false;
#endif
}
} else {
#if DEBUG_INTERNAL
dbg = true;
fprintf(stderr,
"[%s:%02d:%02d %d]\n",
stepDateTime.date().toString().toStdString().c_str(),
stepDateTime.time().hour(), stepDateTime.time().minute(),
_24h_price_units);
#endif
}
} else {
price_units += _24h_price_units;
_24h_price_units = price_units_tmp;
#if DEBUG_INTERNAL
fprintf(stderr,
"[%s:%02d:%02d 24h max. %d]\n",
stepDateTime.date().toString().toStdString().c_str(),
stepDateTime.time().hour(), stepDateTime.time().minute(),
price_units);
fprintf(stderr,
"[%s:%02d:%02d %d]\n",
stepDateTime.date().toString().toStdString().c_str(),
stepDateTime.time().hour(), stepDateTime.time().minute(),
_24h_price_units);
#endif
_24hDateTime = stepDateTime;
t0 = _24hDateTime.toSecsSinceEpoch();
}
// prevStepDateTime = stepDateTime;
stepDateTime = nextStepDateTime;
}
price_units += _24h_price_units;
}
price->units = price_units;
price->netto = roundf((price->units * tariff->unit_scale_factor) / tariff->unit_definition);
price->vat_percentage = tariff->vat;
price->vat = price->netto * price->vat_percentage;
price->brutto = price->netto + price->vat;
return stepDbg;
}
bool compute_price_for_parking_ticket(parking_tariff_t const *tariff,
minute_t startMinute, // CET
minute_t endMinute, // CET
struct price_t *price) {
if (!checkCalculatePreConditions(tariff, startMinute, endMinute, price)) { // CET
return false;
}
// minute_t const parkingTime = endMinute - startMinute;
memset(price, 0x00, sizeof(*price));
minute_t const effectiveStartMinute = startMinute + tariff->free_of_charge;
QDateTime const start = TUtils::fromMinutes(startMinute);
QDateTime const effStart = TUtils::fromMinutes(effectiveStartMinute);
QDateTime const end = TUtils::fromMinutes(endMinute);
//qDebug() << effStart;
//qDebug() << end;
TariffStep const *stepDbg =
compute_price_for_parking_ticket_internal(tariff,
effectiveStartMinute,
endMinute, price);
if (stepDbg) {
#if 0
if (tariff->free_of_charge == 0) {
fprintf(stderr,
"[EINFAHRT: %s:%02d:%02d, AUSFAHRT: %s:%02d:%02d]\n\t",
effStart.date().toString().toStdString().c_str(),
effStart.time().hour(), effStart.time().minute(),
end.date().toString().toStdString().c_str(),
end.time().hour(), end.time().minute());
} else {
fprintf(stderr,
"[EINFAHRT: %s:%02d:%02d, %ld Minuten frei -> "
"EFF. EINFAHRT: %s:%02d:%02d, AUSFAHRT: %s:%02d:%02d]\n\t",
start.date().toString().toStdString().c_str(),
start.time().hour(), start.time().minute(),
tariff->free_of_charge,
effStart.date().toString().toStdString().c_str(),
effStart.time().hour(), effStart.time().minute(),
end.date().toString().toStdString().c_str(),
end.time().hour(), end.time().minute());
}
int cnt = -1;
while (stepDbg->dateTime() < end) {
// qDebug() << price_units << step->price();
fprintf(stderr, "%s %02d:%02d +%u |",
(++cnt == 0) ? "|" : "",
stepDbg->dateTime().time().hour(),
stepDbg->dateTime().time().minute(),
stepDbg->price());
//price_units += stepDbg->price();
//qDebug() << price_units << step->price();
stepDbg = stepDbg->next();
}
#endif
if (price->units > tariff->max_parking_price_units) {
qCritical() << "gesamt" << price->units
<< ">" << tariff->max_parking_price_units;
return false;
}
fprintf(stderr, " : gesamt %.2f (netto: %.2f)\n", price->brutto/100, price->netto/100);
return true;
} else {
qCritical() << "compute_price_for_parking_ticket";
}
return false;
}
bool compute_duration_for_parking_ticket(parking_tariff_t const *tariff,
minute_t start_parking_time,
minute_t *end_parking_time,
struct price_t const *price) {
price_t p;
for (int i = 0; i < tariff->max_parking_time; ++i) {
minute_t end_time = start_parking_time + i;
if (compute_price_for_parking_ticket(tariff, start_parking_time,
end_time, &p)) {
if (p.netto >= price->netto) {
*end_parking_time = end_time;
return true;
}
}
}
return false;
}
bool compute_price_for_tages_ticket(parking_tariff_t *tariff,
time_t parking_time_start, // minutes
struct price_t *price) {
QDateTime dateTime = TUtils::fromMinutes(parking_time_start).addDays(1);
dateTime.setTime(QTime(0, 0));
time_t parking_time_end = dateTime.toSecsSinceEpoch() / 60;
return compute_price_for_parking_ticket(tariff, parking_time_start,
parking_time_end, price);
}
bool compute_price_for_24h_ticket(parking_tariff_t *tariff,
time_t parking_time_start, // minutes
struct price_t *price) {
QDateTime dateTime = TUtils::fromMinutes(parking_time_start).addDays(1);
time_t parking_time_end = dateTime.toSecsSinceEpoch() / 60;
return compute_price_for_parking_ticket(tariff, parking_time_start,
parking_time_end, price);
}
#ifdef __cplusplus
}
#endif