327 lines
14 KiB
C++
327 lines
14 KiB
C++
#include "calculate_parking_tickets_tariff.h"
|
|
|
|
#include <cstdio>
|
|
#include <string>
|
|
#include <algorithm>
|
|
|
|
#include <QDebug>
|
|
#include <QDateTime>
|
|
|
|
#include <rapidjson/filereadstream.h>
|
|
#include <rapidjson/document.h>
|
|
#include <rapidjson/encodings.h>
|
|
#include <rapidjson/error/en.h>
|
|
#include "rapidjson/stringbuffer.h"
|
|
#include <rapidjson/writer.h>
|
|
#include <rapidjson/prettywriter.h>
|
|
|
|
using namespace rapidjson;
|
|
|
|
#define DAY_TARIFF_START "day_tariff_start"
|
|
#define DAY_TARIFF_END "day_tariff_end"
|
|
#define NIGHT_TARIFF_START "night_tariff_start"
|
|
#define NIGHT_TARIFF_END "night_tariff_end"
|
|
#define FREE_OF_CHARGE_DAY_TARIFF "free_of_charge_day_tariff"
|
|
#define FREE_OF_CHARGE_NIGHT_TARIFF "free_of_charge_night_tariff"
|
|
#define UNIT_SCALE_FACTOR "unit_scale_factor"
|
|
#define UNIT_DEFINITION "unit_definition"
|
|
#define VAT "vat"
|
|
#define MAX_PARKING_PRICE "max_parking_price"
|
|
#define MAX_PRICE_FOR_24_HOURS "max_price_for_24_hours"
|
|
#define MAX_PARKING_TIME "max_parking_time"
|
|
#define TARIFF_VERSION "version"
|
|
#define TARIFF_FEATURES "tariff_features"
|
|
#define WAITING_PERIOD "waiting_period"
|
|
#define PARKING_TIME_MIN "parking_time_min"
|
|
#define PARKING_TIME_MAX "parking_time_max"
|
|
#define BASIC_TARIFF "basic_tariff"
|
|
#define MAX_PRICE_24H_AFTER_ARRIVAL "max_price_24h_after_arrival"
|
|
#define MAX_PRICE_AT_MIDNIGHT "max_price_at_midnight"
|
|
|
|
static const char *weekStr[] {
|
|
"week1", "week2", "week3"
|
|
};
|
|
static const char *weekDayStr[] {
|
|
"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"
|
|
};
|
|
static const int constexpr STEP_PRICE = 1;
|
|
static const int constexpr STEP_NEXT = 2;
|
|
|
|
parking_tariff_t *parking_tariff_t::parseTariff(const char *confFile) {
|
|
parking_tariff_t *tariff = 0;
|
|
|
|
FILE* fp = fopen(confFile, "r");
|
|
if (fp) {
|
|
fseek(fp, 0 , SEEK_END);
|
|
long const bufSize = ftell(fp) + 1024;
|
|
fseek(fp, 0 , SEEK_SET);
|
|
char *readBuffer = (char *)malloc(bufSize);
|
|
if (readBuffer) {
|
|
memset(readBuffer, 0x00, bufSize);
|
|
|
|
FileReadStream is(fp, readBuffer, bufSize);
|
|
Document d;
|
|
|
|
if (d.ParseStream(is).HasParseError()) {
|
|
fprintf(stderr, "\nError(offset %u): %s\n",
|
|
(unsigned)d.GetErrorOffset(),
|
|
GetParseError_En(d.GetParseError()));
|
|
free(readBuffer);
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
|
|
tariff = new parking_tariff_t();
|
|
|
|
if (d.HasMember(TARIFF_VERSION)) {
|
|
Value::MemberIterator o = d.FindMember(TARIFF_VERSION);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string version = o->value.GetString();
|
|
strncpy(tariff->tariff_version, version.c_str(),
|
|
std::min((int)version.size(),
|
|
(int)sizeof(tariff->tariff_version)-1));
|
|
tariff->tariff_version[sizeof(tariff->tariff_version)-1] = '\0';
|
|
|
|
}
|
|
if (d.HasMember(TARIFF_FEATURES)) {
|
|
Value::MemberIterator o = d.FindMember(TARIFF_FEATURES);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsArray());
|
|
int const s = o->value.Size();
|
|
if (s > 0) {
|
|
// TODO
|
|
} else {
|
|
tariff->tariff_features = 0;
|
|
memset(tariff->_tariff_features, 0x00,
|
|
sizeof(tariff->_tariff_features));
|
|
}
|
|
}
|
|
if (d.HasMember(DAY_TARIFF_START)) {
|
|
Value::MemberIterator o = d.FindMember(DAY_TARIFF_START);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string s = o->value.GetString();
|
|
tariff->day_tariff_start = std::stoi(s);
|
|
}
|
|
if (d.HasMember(DAY_TARIFF_END)) {
|
|
Value::MemberIterator o = d.FindMember(DAY_TARIFF_END);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string s = o->value.GetString();
|
|
tariff->day_tariff_end = std::stoi(s);
|
|
}
|
|
if (d.HasMember(NIGHT_TARIFF_START)) {
|
|
Value::MemberIterator o = d.FindMember(NIGHT_TARIFF_START);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string s = o->value.GetString();
|
|
tariff->night_tariff_start = std::stoi(s);
|
|
}
|
|
if (d.HasMember(NIGHT_TARIFF_END)) {
|
|
Value::MemberIterator o = d.FindMember(NIGHT_TARIFF_END);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string s = o->value.GetString();
|
|
tariff->night_tariff_end = std::stoi(s);
|
|
}
|
|
if (d.HasMember(WAITING_PERIOD)) {
|
|
Value::MemberIterator o = d.FindMember(WAITING_PERIOD);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string wp = o->value.GetString();
|
|
tariff->waiting_period = std::stoi(wp);
|
|
}
|
|
if (d.HasMember(FREE_OF_CHARGE_DAY_TARIFF)) {
|
|
Value::MemberIterator o = d.FindMember(FREE_OF_CHARGE_DAY_TARIFF);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string foc = o->value.GetString();
|
|
tariff->free_of_charge_day_tariff = std::stoi(foc);
|
|
}
|
|
if (d.HasMember(FREE_OF_CHARGE_NIGHT_TARIFF)) {
|
|
Value::MemberIterator o = d.FindMember(FREE_OF_CHARGE_NIGHT_TARIFF);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string foc = o->value.GetString();
|
|
tariff->free_of_charge_night_tariff = std::stoi(foc);
|
|
}
|
|
if (d.HasMember(UNIT_SCALE_FACTOR)) {
|
|
Value::MemberIterator o = d.FindMember(UNIT_SCALE_FACTOR);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string usf = o->value.GetString();
|
|
tariff->unit_scale_factor = std::stof(usf);
|
|
}
|
|
if (d.HasMember(UNIT_DEFINITION)) {
|
|
Value::MemberIterator o = d.FindMember(UNIT_DEFINITION);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string udef = o->value.GetString();
|
|
tariff->unit_definition = std::stoi(udef);
|
|
}
|
|
if (d.HasMember(VAT)) {
|
|
Value::MemberIterator o = d.FindMember(VAT);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string vat = o->value.GetString();
|
|
tariff->vat = std::stof(vat);
|
|
}
|
|
if (d.HasMember(MAX_PARKING_PRICE)) {
|
|
Value::MemberIterator o = d.FindMember(MAX_PARKING_PRICE);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string mp = o->value.GetString();
|
|
if (mp == "unlimited") {
|
|
tariff->max_parking_price_units = ~0;
|
|
} else {
|
|
tariff->max_parking_price_units = (uint32_t)std::stoul(mp);
|
|
}
|
|
}
|
|
if (d.HasMember(PARKING_TIME_MIN)) {
|
|
Value::MemberIterator o = d.FindMember(PARKING_TIME_MIN);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string mp = o->value.GetString();
|
|
tariff->parking_time_min = (uint32_t)std::stoul(mp);
|
|
}
|
|
if (d.HasMember(PARKING_TIME_MAX)) {
|
|
Value::MemberIterator o = d.FindMember(PARKING_TIME_MAX);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string mp = o->value.GetString();
|
|
if (mp == "unlimited") {
|
|
tariff->parking_time_max = ~0;
|
|
} else {
|
|
tariff->parking_time_max = (uint32_t)std::stoul(mp);
|
|
}
|
|
}
|
|
if (d.HasMember(MAX_PRICE_FOR_24_HOURS)) {
|
|
Value::MemberIterator o = d.FindMember(MAX_PRICE_FOR_24_HOURS);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string mp = o->value.GetString();
|
|
if (mp == "unlimited") {
|
|
tariff->max_price_for_24_hours = ~0;
|
|
} else if (mp == "n/a") {
|
|
tariff->max_price_for_24_hours = 0;
|
|
} else {
|
|
tariff->max_price_for_24_hours = (uint32_t)std::stoul(mp);
|
|
}
|
|
}
|
|
if (d.HasMember(BASIC_TARIFF)) {
|
|
Value::MemberIterator o = d.FindMember(BASIC_TARIFF);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string s = o->value.GetString();
|
|
tariff->basic_tariff = (s == "1");
|
|
}
|
|
if (d.HasMember(MAX_PRICE_24H_AFTER_ARRIVAL)) {
|
|
Value::MemberIterator o = d.FindMember(MAX_PRICE_24H_AFTER_ARRIVAL);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string s = o->value.GetString();
|
|
tariff->max_price_24h_after_arrival = (uint32_t)std::stoul(s);
|
|
}
|
|
if (d.HasMember(MAX_PRICE_AT_MIDNIGHT)) {
|
|
Value::MemberIterator o = d.FindMember(MAX_PRICE_AT_MIDNIGHT);
|
|
assert(o != d.MemberEnd());
|
|
assert(o->value.IsString());
|
|
std::string s = o->value.GetString();
|
|
tariff->max_price_at_midnight = (uint32_t)std::stoul(s);
|
|
}
|
|
|
|
QDate today = QDate::currentDate();
|
|
|
|
int const todayWeekDay = today.dayOfWeek(); // qt: 1 (mon) - 7 (sun)
|
|
if (todayWeekDay > Qt::Monday) {
|
|
today = today.addDays(Qt::Monday - todayWeekDay);
|
|
if (!today.isValid()) {
|
|
qFatal("Setting today failed");
|
|
}
|
|
}
|
|
|
|
assert(today.dayOfWeek() == Qt::Monday);
|
|
QDate monday = today;
|
|
|
|
// "week1" : {
|
|
for (int w = 0; w < 3; ++w) {
|
|
assert(d.HasMember(weekStr[w]));
|
|
|
|
// "Monday": {
|
|
for (int j = Qt::Monday - 1; j < Qt::Sunday; ++j) {
|
|
QDateTime startMinute(monday.addDays(w*7+j), QTime( 0, 0));
|
|
|
|
Value::MemberIterator wObj = d.FindMember(weekStr[w]);
|
|
assert(wObj != d.MemberEnd());
|
|
assert(wObj->value.IsObject());
|
|
|
|
Value::MemberIterator stepsForDay = wObj->value.FindMember(weekDayStr[j]);
|
|
assert(stepsForDay != wObj->value.MemberEnd());
|
|
assert(stepsForDay->value.IsObject());
|
|
|
|
// name : time, price, next-tariff-step
|
|
// "000000" : [ "00:00", "800000", "000001" ],
|
|
// "000001" : [ "07:00", "350000", "000002" ],
|
|
// ...
|
|
// "000014" : [ "20:00", "800000", "000011" ]
|
|
// },
|
|
int k = 0;
|
|
for (Value::ConstMemberIterator step = stepsForDay->value.MemberBegin();
|
|
step != stepsForDay->value.MemberEnd(); ++step) {
|
|
|
|
assert(step->name.IsString());
|
|
assert(step->value.IsArray());
|
|
|
|
QString name(step->name.GetString());
|
|
|
|
int const week = name.midRef(0, 1).toInt();
|
|
int const weekDay = name.midRef(1, 1).toInt();
|
|
int const stepIndex = name.midRef(2).toInt();
|
|
|
|
assert(w == week);
|
|
assert(j == weekDay);
|
|
assert(k == stepIndex);
|
|
|
|
uint32_t price_units = QString(step->value[STEP_PRICE].GetString()).toUInt();
|
|
QString next = QString(step->value[STEP_NEXT].GetString());
|
|
|
|
int const nextWeek = next.midRef(0, 1).toInt();
|
|
int const nextWeekDay = next.midRef(1, 1).toInt();
|
|
int const nextStepIndex = next.midRef(2).toInt();
|
|
|
|
//qDebug() << startMinute.addSecs(stepIndex*60)
|
|
// << "(" << week << weekDay << stepIndex << ")"
|
|
// << "(" << nextWeek << nextWeekDay << nextStepIndex << ")";
|
|
|
|
tariff->m_tariffSteps[week][weekDay][stepIndex] =
|
|
TariffStep(startMinute.addSecs(stepIndex*60),
|
|
price_units,
|
|
&tariff->m_tariffSteps[nextWeek][nextWeekDay][nextStepIndex]);
|
|
|
|
++k;
|
|
}
|
|
}
|
|
}
|
|
free(readBuffer);
|
|
|
|
#if 0
|
|
for (int w = 0; w < 3; ++w) {
|
|
for (int j = Qt::Monday - 1; j < Qt::Sunday; ++j) {
|
|
for (int k = 0; k < MIN_PER_DAY; ++k) {
|
|
//if (tariff->m_tariffSteps[w][j][k].next()) {
|
|
TariffStep const *s = &tariff->m_tariffSteps[w][j][k];
|
|
qDebug() << s->dateTime() << s->price() << "next:" << s->next()->dateTime();
|
|
//}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
fclose(fp);
|
|
}
|
|
|
|
return tariff;
|
|
}
|
|
|