#include "resultscreater.h"

const QString ResultsCreater::LAA_LOG_BASE64 = " ";

const QString ResultsCreater::BLANK_USER_BASE64 = "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"
                                                  "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"
                                                  "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"
                                                  "tkv9p9vbq0XCgVFUeIY6UXX/SdYLnFIuBAQQoIx57zVal9cXjVb7cFgyBknhEB085plQwzDkHGWy+U21tZXV1fK5VKhUCjkc6Zpflzpd4/7nUzN9vFvgyBwXdey7X5v0Ol2a7V6s9WKIkoIURRyyx5QSjnnhqHn87nt7a1nu7u5XFYOO5bZrbeM4pDIytU0zff96tn5+flVfzhklMptgJOvdry5SDDKuOC6rq2vr+3u7FTK5VKpaJomhAghJLfHPbgw46wsnHPuul69Xq83mrV6o9lsyiXlyYtPGhtZRl1X19ZWXrzYX11ZAUAIPqeB0eewvOKQIAQBgGEYBYFfqzdOTs+6vT4AQCVELrPEB3VMhn1jjBVFkemUc7lcPp8rl0ulUiGXy+dyOXy3xipG58ULy7Zdx/VcbzAcdnrdXrdn205EKWOMjo6Sh7eOv4z7EcYYgnBjY31//9nKSkUfa2hpxxmTLLs4xLiLgRC5nttqt1utbqvd7g8GQRBihBWFTHpExvtiGKVMJhVSVaLrhmmapmlommYYhvxWPp8nBH9yO7K8iOe5YRhRymzHCYMgiiLP813Pc103iiI8Afj9zEUGZHDGM5nM2vrKSrlSqZSKhYKua4xzebTIktuMUT0suTgk0iQQQjDGruvWG83rWqPf73ueH0URm2i70sMEwO/2tnAu2/CoZ6CUKopSqZQJIR+LQ+6MEkLYtu04rhACIYwQRgjITD1x4rZ4d6f8olyRB4BjjA3DyJjmykp5e3trbXUFY+z7/iNaFZI8DnHcLjSENKLdXu+6Vq/VG8OhBaYMG28xaczvPiC9yx/HX4EQFvL558/3tne2MqYp+GhT62PoRm7zuMQhhAAQQkIwhDAKI9f3HccdDq1ut9tqd4fDYZyJK3ZW3nzz9/ypo/rjVn5ryCmXThjjQnBd08rlUrlcKhWLuVw2kzFN00AIUcqWze95dx6XOACYmIvGXX4Yhr1ev9PtDS3LcVzXdX3PD8MojEIZZ/XJjXF3SZYBxi1ejLNHym5KespVVdE1TdcNM2PmspliIV8qFvOFPCEkiqJ4b99jlMWoih6dOCa5cUVAiAkWQtiO02y2O52uZdmWZcvR381rfVA4O4SjQy8RgjJXHYLQMPRcLlsoFCrlyupqRdfVKGJSNxPfetw8bnHETGZipJQyRhnjUURt2xkOLdd1B7blOF4UhL7vM36/hEmYEN3QsxkzI+c8hpHNmvlsVmYdJYQQjCGE/KHiW1qeiDgmg2viKQUAMAxDz/PDMHQ9PwxDRml4/+QWCCFFVXVV1TRVommqqioAQMYY44wz/th7kE/yRMQxyeQMU05xkTQscqoLH+CuFoLLVRouD8kQN2dlwCd8pPKyLNnPkDiaRv6vnFNwCMEsUjP+8YLLE+MJiuNjZjgUeKpG4pP8JcTxl3qjM+Tp28aUB5OKI2UqqThSppKKI2UqqThSppKKI2UqqThSppKKI2UqqThSppKKI2UqqThSppKKI2UqqThSppKKI2UqqThSppKKI2UqqThSppKKI2UqqThSppKKI2UqqThSppKKI2UqqThSppKKI2UqqThSpvL/AR/D/5D3nv3NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAABJRU5ErkJggg==";

ResultsCreater::ResultsCreater(QObject* parent)
    : QObject(parent)
{
}

void ResultsCreater::createContinuousResultsHTML(const QString& filePath,
    const QStringList& resList,
    const int recordSize,
    const QString& competitionName,
    const QString& competitionType,
    const QString& competitionDirector,
    const QString& competitionDirectorAvatar,
    const QStringList& competitionArbitr,
    const QStringList& competitionArbitrAvatar,
    const QString& competitionDate,
    const QString& competitionRound,
    const QString& competitionGroupName)
{

    QString html = "";

    QVector<QStringList> rows;
    QStringList classesNames;
    QString categoryData;
    QStringList dataRow;
    QStringList header;

    // list size must be even
    // first half of the array are the classes names, second half is the content for each class

    if (resList.size() % 2) {
        qDebug() << "ResultsCreater::createContinuousResultsHTML() resList.size() % 2 == 1" + QString::number(resList.size() % 2);
        return;
    }

    // get classes names
    int i;
    for (i = 0; i < resList.size() / 2; i++) {

        classesNames.push_back(QString(resList.at(i)).remove("\""));
    }

    // create html
    html += "<!DOCTYPE html>\n";
    html += "<html lang=\"en\">\n";
    html += getHTMLHeader(getTranslatedString("html-continuous-results")) + "\n";

    html += "<body>\n";
    html += getHTMLBodyScript() + "\n";

    html += "<div class=\"container\">\n";

    // results file header
    html += getResultsHTMLBodyHead(competitionName, competitionType, competitionDirector, competitionDirectorAvatar, competitionArbitr, competitionArbitrAvatar, competitionDate, competitionRound, competitionGroupName);

    header = QStringList() << ("html-continuous-results-order")
                           << ("html-continuous-results-name")
                           << ("html-results-ctnt-tg-shortcut")
                           << ("html-results-ctnt-tp-shortcut")
                           << ("html-results-ctnt-sg-shortcut")
                           << ("html-results-ctnt-altLimits-shortcut")
                           << ("html-results-ctnt-speedSec-shortcut")
                           << ("html-results-ctnt-altSec-shortcut")
                           << ("html-results-ctnt-spaceSec-shortcut")
                           << ("html-results-ctnt-markersOk-shortcut")
                           << ("html-results-ctnt-markersNok-shortcut")
                           << ("html-results-ctnt-markersFalse-shortcut")
                           << ("html-results-ctnt-photosOk-shortcut")
                           << ("html-results-ctnt-photosNok-shortcut")
                           << ("html-results-ctnt-photosFalse-shortcut")
                           << ("html-results-ctnt-landing-shortcut")
                           << ("html-results-ctnt-takeOfF-shortcut")
                           //<< ("html-results-ctnt-circling-shortcut")
                           << ("html-results-ctnt-opposite-shortcut")
                           << ("html-results-ctnt-otherPoints-shortcut")
                           << ("html-results-ctnt-otherPenalty-shortcut")
                           << ("html-results-ctnt-points-shortcut")
                           << ("html-results-ctnt-points1000-shortcut");

    // create legend, skip first two columns - order and name
    int skipCols = 2;
    QStringList headerLegend;
    for (int i = skipCols; i < header.size(); i++) {
        headerLegend.push_back(header.at(i) + "-legend"); // add legend suffix for translation
    }

    // tr legend
    headerLegend = getTranslatedStringList(headerLegend);
    header = getTranslatedStringList(header);

    // add legend into legend array and header row
    for (int i = skipCols; i < header.size(); i++) {

        QString headerItem = header.at(i);
        QString legendItem = headerLegend.at(i - skipCols);

        headerLegend[i - skipCols] = headerItem + " - " + legendItem;
        header[i] = getHeaderItemWithHelp(headerItem, legendItem);
    }

    // results for each category
    for (int j = 0; i < resList.size(); i++, j++) {

        categoryData = resList.at(i);

        // no results for this class
        if (categoryData == "[]") {
            continue;
        }

        int row = 1;

        // add category label
        html += getHTMLH3(classesNames.at(j));

        // add category results header
        rows.append(header);

        // get category results data
        QRegularExpression rx("\\\".*?\\\"", QRegularExpression::DotMatchesEverythingOption);
        QRegularExpressionMatchIterator it = rx.globalMatch(categoryData);
        QString category;
        dataRow.clear();

        int col = 0;

        // get ctnt results data
        while (it.hasNext()) {

            // add row number (order)
            if (dataRow.size() == 0) {

                dataRow.push_back(QString::number(row));
                row++;
            }

            // get data from string
            QRegularExpressionMatch match = it.next();
            if (match.hasMatch()) {

                if (col != 1) { // skip class
                    dataRow.push_back(QString(match.captured(0)).remove("\"") == "-1" ? "" : QString(match.captured(0)).remove("\""));
                } else {
                    category = QString(match.captured(0)).remove("\"") == "-1" ? "" : QString(match.captured(0)).remove("\"");
                }
            }

            // add data to table struct
            if (!(dataRow.size() % (recordSize + 1))) {

                // change name to href for evaluated crews
                if (dataRow[dataRow.size() - 2] != "") {

                    dataRow[1] = "<a href=\"" + dataRow.at(1) + "_" + category + ".html" + "\" class=\"hidden-print\">" + dataRow.at(1) + "</a><div class=\"visible-print-block\">" + dataRow.at(1) + "</div>";
                }

                rows.append(dataRow);
                dataRow.clear();
                col = 0;
            } else {
                col++;
            }
        }

        // echo table and spacer
        html += getHTMLHorizontalTable(rows, QVector<double> { 0.5, 2.1, 0.8, 0.8, 0.8, 1.0, 1.0, 1.0, 1.0 });
    }

    // add legend to html
    html += getPrintOnlyText(headerLegend.join(", "));

    html += "</div>\n";
    html += "</body>\n";
    html += "</html>\n";

    file.writeUTF8(QUrl(filePath + ".html"), html.toUtf8());
}

void ResultsCreater::createStartListHTML(const QString& filename,
    const QStringList& cntList,
    const QString& competitionName,
    const int utc_offset_sec)
{
    Q_UNUSED(competitionName)
    QJsonDocument jsonResponse;
    QJsonObject jsonObject;
    QString html = "";
    QVector<QStringList> rows;

    html += "<!DOCTYPE html>\n";
    html += "<html lang=\"en\">\n";
    html += getHTMLHeader(getTranslatedString("html-start-list")) + "\n";

    html += "<body>\n";
    html += getHTMLBodyScript() + "\n";

    html += "<div class=\"container\">\n";
    /*
        html += "<div class=\"row\">\n";
        html += "   <div class=\"col-md-6\">\n";
        html +=         competitionName + "\n";
        html += "   </div>\n";
        html += "   <div class=\"col-md-6\">\n";
        html += "       <span class=\"pull-right\">" + QDate().currentDate().toString("dd.MM.yyyy") + "  " + QTime().currentTime().toString("hh:mm:ss") + "</span>\n";
        html += "   </div>\n";
        html += "</div>\n";
    */

    html += getHTMLH1(getTranslatedString("html-start-list-title"));

    // track points header row
    rows.append(getTranslatedStringList(QStringList() << ("html-startList-order")
                                                      << ("html-continuous-results-name")
                                                      << ("html-results-ctnt-category")
                                                      << ("html-results-ctnt-aircraft-registration")
                                                      << ("html-results-ctnt-speed")
                                                      << ("html-startList-startTimePrepTime")
                                                      << ("html-results-ctnt-startTime")
                                                      << ("html-startList-startTimeVBT")
                                                      << ("html-results-note")));

    for (int i = 0; i < cntList.size(); ++i) {

        jsonResponse = QJsonDocument::fromJson(cntList.at(i).toUtf8());
        jsonObject = jsonResponse.object();

        rows.append(QStringList() << QString::number(i + 1)
                                  << jsonObject["name"].toString()
                                  << jsonObject["category"].toString()
                                  << jsonObject["aircraft_registration"].toString()
                                  << QString::number(jsonObject["speed"].toInt())
                                  << QTime(0, 0, 0).addSecs(addUtcToTime(QTime::fromString(jsonObject["startTimePrepTime"].toString(), "HH:mm:ss"), utc_offset_sec)).toString("HH:mm:ss")
                                  << "<b>" + QTime(0, 0, 0).addSecs(addUtcToTime(QTime::fromString(jsonObject["startTime"].toString(), "HH:mm:ss"), utc_offset_sec)).toString("HH:mm:ss") + "</b>"
                                  << QTime(0, 0, 0).addSecs(addUtcToTime(QTime::fromString(jsonObject["startTimeVBT"].toString(), "HH:mm:ss"), utc_offset_sec)).toString("HH:mm:ss")
                                  << "");
    }

    html += getHTMLHorizontalTable(rows, QVector<double> { 0.2 / 9.0, 3.1 / 9.0, 0.4 / 9.0, 0.3 / 9.0, 0.4 / 9.0, 0.7 / 9.0, 0.7 / 9.0, 0.7 / 9.0, 2.5 / 9.0 });

    html += "</div>\n";
    html += "</body>\n";
    html += "</html>\n";

    file.writeUTF8(QUrl(filename + ".html"), html.toUtf8());
}

void ResultsCreater::createContestantResultsHTML(const QString& filename,
    const QString& cntJSON,
    const QString& competitionName,
    const QString& competitionType,
    const QString& competitionDirector,
    const QString& competitionDirectorAvatar,
    const QStringList& competitionArbitr,
    const QStringList& competitionArbitrAvatar,
    const QString& competitionDate,
    const QString& competitionRound,
    const QString& competitionGroupName,
    const int utc_offset_sec)
{
    QString html = "";
    QStringList trackPointsList;
    QVector<QStringList> rows;

    QJsonDocument jsonResponse = QJsonDocument::fromJson(cntJSON.toUtf8());
    QJsonObject jsonObject = jsonResponse.object();

    // no results
    if (jsonObject["name"].toString().length() == 1)
        return;

    int tg_time_measured = 0;
    bool sg_hit_measured = false;
    bool tp_hit_measured = false;
    // QString point_alt_type = "";
    int alt_measured = 0;
    double ctntSpeed = jsonObject["speed"].toDouble();

    html += "<!DOCTYPE html>\n";
    html += "<html lang=\"en\">\n";
    html += getHTMLHeader(jsonObject["name"].toString()) + "\n";

    html += "<body>\n";
    html += getHTMLBodyScript() + "\n";
    html += "<div class=\"container\">\n";

    // results file header
    html += getResultsHTMLBodyHead(competitionName, competitionType, competitionDirector, competitionDirectorAvatar, competitionArbitr, competitionArbitrAvatar, competitionDate, competitionRound, competitionGroupName);

    // results header
    html += "<div class=\"row\">";
    html += "   <div class=\"col-xs-4\">";
    html += getHTMLH3(getTranslatedString("html-results-crew-title"));

    QStringList names = jsonObject["name"].toString().split(" – ");
    if (names.length() >= 1) {

        rows.append(QStringList() << getTranslatedString("html-results-ctnt-pilot") << ("<table>" + getUserTableRowRecordWithAvatar(jsonObject["pilotAvatarBase64"].toString(), names[0]) + "</table>"));
    }
    if (names.length() >= 2) {

        rows.append(QStringList() << getTranslatedString("html-results-ctnt-copilot") << ("<table>" + getUserTableRowRecordWithAvatar(jsonObject["copilotAvatarBase64"].toString(), names[1]) + "</table>"));
    }

    rows.append(QStringList() << getTranslatedString("html-results-ctnt-category") << jsonObject["category"].toString());
    rows.append(QStringList() << getTranslatedString("html-results-ctnt-startTime") << QTime(0, 0, 0).addSecs(addUtcToTime(QTime::fromString(jsonObject["startTime"].toString(), "HH:mm:ss"), utc_offset_sec)).toString("HH:mm:ss"));
    rows.append(QStringList() << getTranslatedString("html-results-ctnt-speed") << QString::number(jsonObject["speed"].toDouble()));
    rows.append(QStringList() << getTranslatedString("html-results-ctnt-aircraft-registration") << jsonObject["aircraft_registration"].toString());
    rows.append(QStringList() << getTranslatedString("html-results-ctnt-aircraft-type") << jsonObject["aircraft_type"].toString());

    rows.append(QStringList() << getTranslatedString("html-results-ctnt-classify") << (jsonObject["classify"].toDouble() == 0 ? getTranslatedString("hit-yes") : getTranslatedString("hit-no")));
    rows.append(QStringList() << getTranslatedString("html-results-ctnt-score-points") << (jsonObject["scorePoints"].toDouble() < 0 ? "" : QString::number(jsonObject["scorePoints"].toDouble())));
    // rows.append(QStringList() << getTranslatedString("html-results-ctnt-score-points1000") << (jsonObject["scorePoints1000"].toDouble() < 0 ? "" : QString::number(jsonObject["scorePoints1000"].toDouble())));
    // rows.append(QStringList() << getTranslatedString("html-results-ctnt-class-order") << (jsonObject["classOrder"].toDouble() < 0 ? "" : QString::number(jsonObject["classOrder"].toDouble())));
    html += getHTMLVerticalTable(rows);

    html += "   </div>";
    html += "   <div class=\"col-xs-8\">";

    // trajectory
    QUrl trajectoryImgUrl = QUrl(filename + ".png");
    //    if (!file.file_exists(trajectoryImgUrl)) {
    //        qDebug() << "Image \"" << trajectoryImgUrl << "\" doesn't exists";
    //    }
    html += file.file_exists(trajectoryImgUrl) ? getHTMLResponsiveImage(getImageBase64(trajectoryImgUrl)) : "";

    html += "   </div>";
    html += "</div>";

    // manual values
    html += getHTMLH3(getTranslatedString("html-results-manual-values"));
    rows.append(QStringList() << getBoldText(getTranslatedString("html-results-point-type")) << getBoldText(getTranslatedString("html-results-inserted-value")) << getBoldText(getTranslatedString("html-results-score")));

    // markers
    rows.append(QStringList() << getTranslatedString("html-results-markers") + " " + getItalicText(getTranslatedString("html-results-markers-legend")) << QString::number(jsonObject["markersOk"].toDouble()) + " / " + QString::number(jsonObject["markersNok"].toDouble()) + " / " + QString::number(jsonObject["markersFalse"].toDouble()) << QString::number(jsonObject["markersScore"].toDouble()));
    // photos
    rows.append(QStringList() << getTranslatedString("html-results-photos") + " " + getItalicText(getTranslatedString("html-results-markers-legend")) << QString::number(jsonObject["photosOk"].toDouble()) + " / " + QString::number(jsonObject["photosNok"].toDouble()) + " / " + QString::number(jsonObject["photosFalse"].toDouble()) << QString::number(jsonObject["photosScore"].toDouble()));
    // take off
    rows.append(QStringList() << getTranslatedString("html-results-take-off") + " " + getItalicText(getTranslatedString("html-results-take-off-legend")) << QTime(0, 0, 0).addSecs(addUtcToTime(QTime::fromString(jsonObject["startTime"].toString(), "HH:mm:ss"), utc_offset_sec)).toString("HH:mm:ss") + " / " + (jsonObject["startTimeMeasured"].toString() == "" ? " - " : QTime(0, 0, 0).addSecs(addUtcToTime(QTime::fromString(jsonObject["startTimeMeasured"].toString(), "HH:mm:ss"), utc_offset_sec)).toString("HH:mm:ss")) + " / " + (jsonObject["startTimeDifference"].toString() == "" ? " - " : jsonObject["startTimeDifference"].toString()) << QString::number(jsonObject["startTimeScore"].toDouble()));
    // landing accurancy
    rows.append(QStringList() << getTranslatedString("html-results-landing-accurancy") + " " + getItalicText(getTranslatedString("html-results-point-legend")) << QString::number(jsonObject["landingScore"].toDouble()) << QString::number(jsonObject["landingScore"].toDouble()));
    // circling
    // rows.append(QStringList() << getTranslatedString("html-results-circling") + " " + getItalicText(getTranslatedString("html-results-count-legend")) <<
    //            QString::number(jsonObject["circlingCount"].toDouble()) <<
    //            QString::number(jsonObject["circlingScore"].toDouble()));
    // opposite dir flight
    rows.append(QStringList() << getTranslatedString("html-results-opposite") + " " + getItalicText(getTranslatedString("html-results-count-legend")) << QString::number(jsonObject["oppositeCount"].toDouble()) << QString::number(jsonObject["oppositeScore"].toDouble()));
    // other points
    rows.append(QStringList() << getTranslatedString("html-results-other-points") + " " + getItalicText(getTranslatedString("html-results-point-legend")) << QString::number(jsonObject["otherPoints"].toDouble()) << QString::number(jsonObject["otherPoints"].toDouble()));
    // other penalty
    rows.append(QStringList() << getTranslatedString("html-results-other-penalty") + " " + getItalicText(getTranslatedString("html-results-point-legend")) << QString::number(jsonObject["otherPenalty"].toDouble()) << QString::number(jsonObject["otherPenalty"].toDouble() != 0 ? jsonObject["otherPenalty"].toDouble() * -1 : 0));
    // note
    rows.append(QStringList() << getTranslatedString("html-results-note") << jsonObject["pointNote"].toString() << "-");

    html += getHTMLVerticalTable(rows);

    // track points
    if (jsonObject["wptScoreDetails"].toString() != "") {

        trackPointsList = jsonObject["wptScoreDetails"].toString().split("; ");

        html += getHTMLH3(getTranslatedString("html-results-track-points"));

        // track points header row
        rows.append(getTranslatedStringList(QStringList() << ("html-results-point-name")
                                                          << ("html-results-point-type")
                                                          << ("html-results-point-distance")
                                                          << ("html-results-point-tg-expected")
                                                          << ("html-results-point-tg-measured")
                                                          //<< ("html-results-point-tg-difference")
                                                          //<< ("html-results-tg-score")
                                                          << ("html-results-point-tp-hit")
                                                          //<< ("html-results-tp-score")
                                                          << ("html-results-point-sg-hit")
                                                          //<< ("html-results-sg-score")
                                                          << ("html-results-point-alt-limit")
                                                          //<< ("html-results-point-alt-min")
                                                          //<< ("html-results-point-alt-max")
                                                          << ("html-results-point-alt-measured")
                                                          //<< ("html-results-alt-score")
                                                          << ("html-results-score")));

        // track points content
        for (int k = 0; k < trackPointsList.size(); ++k) {
            jsonResponse = QJsonDocument::fromJson(trackPointsList.at(k).toUtf8());
            jsonObject = jsonResponse.object();

            tg_time_measured = jsonObject["tg_time_manual"].toDouble() < 0 ? jsonObject["tg_time_measured"].toDouble() : jsonObject["tg_time_manual"].toDouble();
            sg_hit_measured = jsonObject["sg_hit_manual"].toDouble() < 0 ? jsonObject["sg_hit_measured"].toBool() : jsonObject["sg_hit_manual"].toBool();
            tp_hit_measured = jsonObject["tp_hit_manual"].toDouble() < 0 ? jsonObject["tp_hit_measured"].toBool() : jsonObject["tp_hit_manual"].toBool();
            alt_measured = jsonObject["alt_manual"].toDouble() < 0 ? jsonObject["alt_measured"].toDouble() : jsonObject["alt_manual"].toDouble();

            // check point type
            bool isTG = (int(jsonObject["type"].toDouble()) & 2) == 2;
            bool isTP = (int(jsonObject["type"].toDouble()) & 1) == 1;
            bool isSG = (int(jsonObject["type"].toDouble()) & 4) == 4;
            bool altLimit = ((jsonObject["alt_min"].toDouble() > 0) || (jsonObject["alt_max"].toDouble() > 0));

            rows.append(QStringList() << jsonObject["title"].toString()
                                      << pointFlagToString(jsonObject["type"].toDouble())
                                      << QString::number(jsonObject["distance_from_vbt"].toDouble() / 1000, 'f', 2)

                                      << (isTG ? "" : getFontColorStartTag("#bfbfbf")) + QTime(0, 0, 0).addSecs(addUtcToTime(jsonObject["tg_time_calculated"].toDouble(), utc_offset_sec)).toString("HH:mm:ss") + (isTG ? "" : getFontColorEndTag())
                                      << (isTG ? "" : getFontColorStartTag("#bfbfbf")) + QTime(0, 0, 0).addSecs(addUtcToTime(tg_time_measured, utc_offset_sec)).toString() + (isTG ? "" : getFontColorEndTag())
                                      << (isTP ? "" : getFontColorStartTag("#bfbfbf")) + (tp_hit_measured ? getTranslatedString("hit-yes") : getTranslatedString("hit-no")) + (isTP ? "" : getFontColorEndTag())
                                      << (isSG ? "" : getFontColorStartTag("#bfbfbf")) + (sg_hit_measured ? getTranslatedString("hit-yes") : getTranslatedString("hit-no")) + (isSG ? "" : getFontColorEndTag())
                                      << ((jsonObject["alt_min"].toDouble() < 0 ? "GND" : QString::number(jsonObject["alt_min"].toDouble())) + " - " + (jsonObject["alt_max"].toDouble() < 0 ? "FL 660" : QString::number(jsonObject["alt_max"].toDouble())))
                                      << (alt_measured < 0 ? "" : QString::number(alt_measured))

                                      << (isTG ? "" : getFontColorStartTag("#bfbfbf")) + (jsonObject["tg_score"].toDouble() < 0 ? "0" : QString::number(jsonObject["tg_score"].toDouble())) + (isTG ? "" : getFontColorEndTag())
                                      << (isTP ? "" : getFontColorStartTag("#bfbfbf")) + (jsonObject["tp_score"].toDouble() < 0 ? "0" : QString::number(jsonObject["tp_score"].toDouble())) + (isTP ? "" : getFontColorEndTag())
                                      << (isSG ? "" : getFontColorStartTag("#bfbfbf")) + (jsonObject["sg_score"].toDouble() < 0 ? "0" : QString::number(jsonObject["sg_score"].toDouble())) + (isSG ? "" : getFontColorEndTag())
                                      << (altLimit ? "" : getFontColorStartTag("#bfbfbf")) + (jsonObject["alt_score"].toDouble() == -1 ? "0" : QString::number(jsonObject["alt_score"].toDouble())) + (altLimit ? "" : getFontColorEndTag()));
        }
        html += getHTMLHorizontalTable(rows);
    }

    // speed sections
    jsonResponse = QJsonDocument::fromJson(cntJSON.toUtf8());
    jsonObject = jsonResponse.object();

    // split array
    QRegularExpression rx("\\{.*?\\}", QRegularExpression::DotMatchesEverythingOption);
    QRegularExpressionMatchIterator i = rx.globalMatch(jsonObject["speedSectionsScoreDetails"].toString());

    if (i.hasNext()) {

        html += getHTMLH3(getTranslatedString("html-results-speed-sections"));

        // speed sections header row
        rows.append(getTranslatedStringList(QStringList() << ("html-results-speed-sec-start-point")
                                                          << ("html-results-speed-sec-end-point")
                                                          << ("html-results-speed-sec-expected")
                                                          << ("html-results-speed-sec-measured")
                                                          << ("html-results-score")));

        // speed sections content
        while (i.hasNext()) {
            QRegularExpressionMatch match = i.next();
            if (match.hasMatch()) {

                jsonResponse = QJsonDocument::fromJson(match.captured(0).toUtf8());
                jsonObject = jsonResponse.object();

                rows.append(QStringList() << jsonObject["startPointName"].toString()
                                          << jsonObject["endPointName"].toString()
                                          << QString::number(ctntSpeed)
                                          << (jsonObject["manualSpeed"].toDouble() < 0 ? QString::number(jsonObject["calculatedSpeed"].toDouble()) : QString::number(jsonObject["manualSpeed"].toDouble()))
                                          << QString::number(jsonObject["speedSecScore"].toDouble()));
            }
        }

        html += getHTMLHorizontalTable(rows, QVector<double> { 1.0 / 7.0, 1.0 / 7.0, 1.0 / 7.0, 1.0 / 7.0, 1.0 / 7.0, 2.0 / 7.0 });
    }

    // altitude sections
    jsonResponse = QJsonDocument::fromJson(cntJSON.toUtf8());
    jsonObject = jsonResponse.object();

    // split array
    rx = QRegularExpression("\\{.*?\\}", QRegularExpression::DotMatchesEverythingOption);
    i = rx.globalMatch(jsonObject["altitudeSectionsScoreDetails"].toString());

    if (i.hasNext()) {

        html += getHTMLH3(getTranslatedString("html-results-altitude-sections"));

        // alt sections header row
        rows.append(getTranslatedStringList(QStringList() << ("html-results-alt-sec-start-point")
                                                          << ("html-results-alt-sec-end-point")
                                                          << ("html-results-alt-sec-min-count")
                                                          << ("html-results-alt-sec-min-time")
                                                          << ("html-results-alt-sec-max-count")
                                                          << ("html-results-alt-sec-max-time")
                                                          << ("html-results-score")));
        // alt sections content
        while (i.hasNext()) {
            QRegularExpressionMatch match = i.next();
            if (match.hasMatch()) {

                jsonResponse = QJsonDocument::fromJson(match.captured(0).toUtf8());
                jsonObject = jsonResponse.object();

                rows.append(QStringList() << jsonObject["startPointName"].toString()
                                          << jsonObject["endPointName"].toString()
                                          << (jsonObject["manualAltMinEntriesCount"].toDouble() < 0 ? QString::number(jsonObject["altMinEntriesCount"].toDouble()) : QString::number(jsonObject["manualAltMinEntriesCount"].toDouble()))
                                          << (jsonObject["manualAltMinEntriesCount"].toDouble() < 0 ? (jsonObject["manualAltMinEntriesTime"].toDouble() < 0 ? QTime(0, 0, 0).addSecs(jsonObject["altMinEntriesTime"].toDouble()).toString("hh:mm:ss") : QTime(0, 0, 0).addSecs(jsonObject["manualAltMinEntriesTime"].toDouble()).toString("hh:mm:ss")) : "")
                                          << (jsonObject["manualAltMaxEntriesCount"].toDouble() < 0 ? QString::number(jsonObject["altMaxEntriesCount"].toDouble()) : QString::number(jsonObject["manualAltMaxEntriesCount"].toDouble()))
                                          << (jsonObject["manualAltMaxEntriesCount"].toDouble() < 0 ? (jsonObject["manualAltMaxEntriesTime"].toDouble() < 0 ? QTime(0, 0, 0).addSecs(jsonObject["altMaxEntriesTime"].toDouble()).toString("hh:mm:ss") : QTime(0, 0, 0).addSecs(jsonObject["manualAltMaxEntriesTime"].toDouble()).toString("hh:mm:ss")) : "")
                                          << QString::number(jsonObject["altSecScore"].toDouble()));
            }
        }

        html += getHTMLHorizontalTable(rows, QVector<double> { 1, 1, 1, 1, 1, 1, 1 });
    }

    // space sections
    jsonResponse = QJsonDocument::fromJson(cntJSON.toUtf8());
    jsonObject = jsonResponse.object();

    // split array
    rx = QRegularExpression("\\{.*?\\}", QRegularExpression::DotMatchesEverythingOption);
    i = rx.globalMatch(jsonObject["spaceSectionsScoreDetails"].toString());

    if (i.hasNext()) {

        html += getHTMLH3(getTranslatedString("html-results-space-sections"));

        // alt sections header row
        rows.append(getTranslatedStringList(QStringList() << ("html-results-space-sec-start-point")
                                                          << ("html-results-space-sec-end-point")
                                                          << ("html-results-space-sec-entries-count")
                                                          << ("html-results-space-sec-entries-time")
                                                          << ("html-results-score")));
        // alt sections content
        while (i.hasNext()) {
            QRegularExpressionMatch match = i.next();
            if (match.hasMatch()) {

                jsonResponse = QJsonDocument::fromJson(match.captured(0).toUtf8());
                jsonObject = jsonResponse.object();

                rows.append(QStringList() << jsonObject["startPointName"].toString()
                                          << jsonObject["endPointName"].toString()
                                          << (jsonObject["manualEntries_out"].toDouble() < 0 ? QString::number(jsonObject["entries_out"].toDouble()) : QString::number(jsonObject["manualEntries_out"].toDouble()))
                                          << (jsonObject["manualEntries_out"].toDouble() < 0 ? (jsonObject["manualTime_spent_out"].toDouble() < 0 ? QTime(0, 0, 0).addSecs(jsonObject["time_spent_out"].toDouble()).toString("hh:mm:ss") : QTime(0, 0, 0).addSecs(jsonObject["manualTime_spent_out"].toDouble()).toString("hh:mm:ss")) : "")
                                          << QString::number(jsonObject["spaceSecScore"].toDouble()));
            }
        }

        html += getHTMLHorizontalTable(rows, QVector<double> { 1.0 / 7.0, 1.0 / 7.0, 1.0 / 7.0, 1.0 / 7.0, 3.0 / 7.0 });
    }

    html += "</div>\n";
    html += "</body>\n";
    html += "</html>\n";

    file.writeUTF8(QUrl(filename + ".html"), html.toUtf8());
}

const inline QString ResultsCreater::getFontColorStartTag(QString color)
{

    if (color == "#bfbfbf") // grey color
        return "<span style=\"color:" + color + "\" class=\"greyText !important\">";
    else
        return "<span style=\"color:" + color + "\">";
}

const inline QString ResultsCreater::getFontColorEndTag()
{

    return "</span>";
}

const inline QString ResultsCreater::getBoldText(const QString text)
{

    return "<b>" + text + "</b>";
}

const inline QString ResultsCreater::getItalicText(const QString text)
{

    return "<i>" + text + "</i>";
}

const QString ResultsCreater::getItalicGreyText(const QString text)
{

    return getItalicText(getFontColorStartTag("#bfbfbf") + text + getFontColorEndTag());
}

const QString ResultsCreater::getResultsHTMLBodyHead(const QString& competitionName,
    const QString& competitionType,
    const QString& competitionDirector,
    const QString& competitionDirectorAvatar,
    const QStringList& competitionArbitr,
    const QStringList& competitionArbitrAvatar,
    const QString& competitionDate,
    const QString& competitionRound,
    const QString& competitionGroupName)
{

    QString html = "";
    QVector<QStringList> rows;

    html += getHTMLH1(competitionName);
    html += "<div class=\"row\">\n";
    html += "   <div class=\"col-xs-4\">\n";

    if (competitionGroupName != "")
        rows.append(QStringList() << getTranslatedString("html-results-competition-group-name") << competitionGroupName);

    if (competitionRound != "")
        rows.append(QStringList() << getTranslatedString("html-results-competition-round") << competitionRound);

    if (competitionType != "")
        rows.append(QStringList() << getTranslatedString("html-results-competition-type") << competitionType);

    if (competitionDate != "")
        rows.append(QStringList() << getTranslatedString("html-results-competition-date") << competitionDate);

    html += getHTMLVerticalTable(rows);
    html += "   </div>\n";

    html += "   <div class=\"col-xs-4\">\n";

    if (competitionDirector != "") {
        rows.append(QStringList() << getTranslatedString("html-results-competition-director") << ("<table>" + getUserTableRowRecordWithAvatar(competitionDirectorAvatar, competitionDirector) + "</table>"));
    }

    // push each arbitr with avatar into table
    for (int i = 0; i < competitionArbitr.size(); i++) {

        QString avatar = i < competitionArbitrAvatar.size() ? competitionArbitrAvatar.at(i) : BLANK_USER_BASE64;
        QString label = (i == 0 ? getTranslatedString("html-results-competition-arbitr") : "");

        if (competitionArbitr.at(i) != "") {
            rows.append(QStringList() << label << ("<table>" + getUserTableRowRecordWithAvatar(avatar, competitionArbitr.at(i)) + "</table>"));
        }
    }

    html += getHTMLVerticalTable(rows);
    html += "   </div>\n";

    html += "   <div class=\"col-xs-4\">\n";
    html += "       <div class=\"row\">\n";
    html += "           <span class=\"pull-right\">\n";
    html += getHTMLRoundedImage(ResultsCreater::LAA_LOG_BASE64, "50px", "auto");
    html += "           </span>\n";
    html += "       </div>\n";
    html += getHTMLSpace(5);
    html += "       <div class=\"row\">\n";
    html += "           <span class=\"pull-right\">" + QDate().currentDate().toString("yyyy-MM-dd ") + "</span>\n";
    html += "       </div>\n";
    html += "       <div class=\"row\">\n";
    html += "           <span class=\"pull-right\">" + QTime().currentTime().toString("hh:mm:ss ") + "</span>\n";
    html += "       </div>\n";
    html += "   </div>\n";
    html += "</div>\n";

    return html;
}

const QString ResultsCreater::getHTMLHorizontalTable(QVector<QStringList>& rows, const QVector<double>& preferedColumnsWidth)
{

    QString htmlTable = "";
    QStringList rowItem;
    QString columnWidthString = "";
    QString headerLastColColSpan = "";

    // calc colspan for header last column
    if ((rows.size() > 1) && (rows.at(0).size() < rows.at(1).size())) {
        headerLastColColSpan = " colspan=\"" + QString::number(rows.at(1).size() - rows.at(0).size() + 1) + "\"";
    }

    htmlTable += getHTMLStartTableTag() + "\n";

    for (int i = 0; i < rows.size(); ++i) {

        rowItem = QStringList(rows.at(i));

        // table content
        htmlTable += "<tr>\n";

        for (int j = 0; j < rowItem.size(); ++j) {

            if (preferedColumnsWidth.size() == rowItem.size()) {

                columnWidthString = " style=\"width: " + QString::number(preferedColumnsWidth.at(j) * 100 / rowItem.size()) + "%\"";
            }

            if (i == 0)
                htmlTable += "   <th" + (columnWidthString != "" ? columnWidthString : (j == (rowItem.size() - 1) ? headerLastColColSpan : "")) + ">" + rowItem.at(j) + "</th>\n";
            else
                htmlTable += "   <td" + columnWidthString + ">" + rowItem.at(j) + "</td>\n";
        }

        htmlTable += "</tr>\n";
    }

    htmlTable += getHTMLEndTableTag() + "\n";

    rows.clear();

    return htmlTable;
}

const QString ResultsCreater::getHTMLVerticalTable(QVector<QStringList>& rows)
{

    QString htmlTable = "";
    QStringList rowItem;

    htmlTable += getHTMLStartTableTag() + "\n";

    for (int i = 0; i < rows.size(); ++i) {

        rowItem = QStringList(rows.at(i));

        // table content
        htmlTable += "<tr>\n";

        for (int j = 0; j < rowItem.size(); ++j) {

            htmlTable += "   <td>" + rowItem.at(j) + "</td>\n";
        }

        htmlTable += "</tr>\n";
    }

    htmlTable += getHTMLEndTableTag() + "\n";

    rows.clear();

    return htmlTable;
}

const inline QString ResultsCreater::getHTMLH1(const QString text)
{

    return "<h1>" + text + "</h1>";
}

const inline QString ResultsCreater::getHTMLH2(const QString text)
{

    return "<h2>" + text + "</h2>";
}

const inline QString ResultsCreater::getHTMLH3(const QString text)
{

    return "<h3>" + text + "</h3>";
}

const inline QString ResultsCreater::getHTMLHeader(const QString title)
{

    return "<head>\n"
           "<meta charset=\"UTF-8\">\n"
           "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n"
           "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />\n"
           "<meta name=\"description\" content=\"\">\n"
           "<meta name=\"author\" content=\"Letecká Amaterská Asociace ČR\">\n"
           "<meta property=\"og:title\" content=\""
        + title + "\"/>\n"

                  "<title>"
        + title + "</title>\n"

                  "<!-- Bootstrap core CSS -->\n"
                  "<link rel=\"stylesheet\" type=\"text/css\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\">\n"
                  "<link href=\"../bin/viewer+/x64/www/css/style.css\" rel=\"stylesheet\">\n"
                  "<link href=\"../bin/viewer+/x86/www/css/style.css\" rel=\"stylesheet\">\n"

                  "<style>"
                  "@media print {"
                  ".table-startlist > tbody > tr > td, .table-startlist > tbody > tr > th, .table-startlist > tfoot > tr > td, .table-startlist > tfoot > tr > th, .table-startlist > thead > tr > td, .table-startlist > thead > tr > th"
                  "{"
                  "padding: 3px;"
                  "}"
                  ".greyText {"
                  "color: #ccc !important;"
                  "},"

                  ".col-xs-1,"
                  ".col-xs-2,"
                  ".col-xs-3,"
                  ".col-xs-4,"
                  ".col-xs-5,"
                  ".col-xs-6,"
                  ".col-xs-7,"
                  ".col-xs-8,"
                  ".col-xs-9,"
                  ".col-xs-10,"
                  ".col-xs-11,"
                  ".col-xs-12 {"
                  "   float: none;"
                  "   width: 100%;"
                  "}"

                  ".container {"
                  "   width: auto;"
                  "}"
                  "}"
                  "</style>"

                  "</head>\n"
                  "\n";
}

const inline QString ResultsCreater::getHTMLBodyScript()
{

    return "<!-- Placed at the end of the document so the pages load faster -->\n"

           "<script>\n"
           "<type=\"text/javascript\" src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js\">\n"
           "<type=\"text/javascript\" src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js\">\n"
           "<type=\"text/javascript\" src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/selectize.min.js\">\n"

           "<type=\"text/javascript\" src=\"../bin/viewer+/x86/www/js/jquery.min.js\">\n"
           "<type=\"text/javascript\" src=\"../bin/viewer+/x86/www/js/bootstrap.min.js\">\n"
           "<type=\"text/javascript\" src=\"../bin/viewer+/x86/www/js/selectize.min.js\">\n"

           "<type=\"text/javascript\" src=\"../bin/viewer+/x64/www/js/jquery.min.js\">\n"
           "<type=\"text/javascript\" src=\"../bin/viewer+/x64/www/js/bootstrap.min.js\">\n"
           "<type=\"text/javascript\" src=\"../bin/viewer+/x64/www/js/selectize.min.js\">\n"
           "</script>\n"

           "<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->\n"
           "\n";
}

const inline QString ResultsCreater::getImageBase64(const QUrl& image)
{

    return QString(file.read(image).toBase64());
}

const inline QString ResultsCreater::getHTMLResponsiveImage(const QString& base64)
{

    return "<img class=\"img-responsive\" src=\"data:image/png;base64," + base64 + "\">";
}

const inline QString ResultsCreater::getHTMLRoundedImage(const QString& base64, const QString heightPx, const QString widthPx)
{

    return "<img style=\"height: " + heightPx + "; width: " + widthPx + ";\" class=\"img-rounded\" src=\"data:image/png;base64," + base64 + "\">";
}

const inline QString ResultsCreater::getHTMLStartTableTag()
{

    return "<table class=\"table table-striped table-startlist\">";
}

const inline QString ResultsCreater::getHTMLEndTableTag()
{

    return "</table>";
}

const inline QString ResultsCreater::getHTMLSpace(const int spaceInPx)
{

    return "<div class=\"col-xs-12\" style=\"height:" + QString::number(spaceInPx) + "px;\"></div>";
}

const inline QString ResultsCreater::getUserTableRowRecordWithAvatar(const QString& avatarBase64,
    const QString& name)
{

    QString avatar = avatarBase64 == "" ? BLANK_USER_BASE64 : avatarBase64;

    return "<tr><td style=\"width:50px; height:42px\">" + getHTMLRoundedImage(avatar, "40px", "40px") + "</td><td>" + name + "</td></tr>";
}

const inline QString ResultsCreater::getHeaderItemWithHelp(const QString shortcut, const QString help)
{

    return "<abbr class=\"hidden-print\" title=\"" + help + "\">" + shortcut + "</abbr><span class=\"visible-print-inline\">" + shortcut + "</span>";
}

const inline QString ResultsCreater::getPrintOnlyText(const QString text)
{

    return "<span class=\"visible-print-inline\">" + text + "</span>";
}

const QStringList ResultsCreater::getTranslatedStringList(QStringList sourceList)
{

    // load qml component, used for localization
    QVariant returnedValue;
    QStringList translatedList;
    QQmlEngine engine;
    QQmlComponent component(&engine, QStringLiteral("qrc:/src/qml/components/MyTranslator.qml"));
    QObject* object = component.create();

    for (int i = 0; i < sourceList.length(); i++) {

        QMetaObject::invokeMethod(object, "myTranslate", Q_RETURN_ARG(QVariant, returnedValue), Q_ARG(QVariant, sourceList.at(i)));
        translatedList.push_back(returnedValue.toString());
    }

    delete object;

    return translatedList;
}

const QString ResultsCreater::getTranslatedString(QString sourceString)
{

    return getTranslatedStringList(QStringList() << sourceString).join("");
}

int ResultsCreater::timeToSec(const QTime& time)
{

    return QTime(0, 0, 0).secsTo(time);
}

int ResultsCreater::addUtcToTime(const int timeSec, const int utcOffsetSec)
{

    if (timeSec <= 0) {
        return 0;
    } else {
        return timeSec + utcOffsetSec;
    }
}

int ResultsCreater::addUtcToTime(const QTime& time, const int utcOffsetSec)
{

    int timeSec = timeToSec(time);

    if (timeSec <= 0) {
        return 0;
    } else {
        return timeSec + utcOffsetSec;
    }
}

int ResultsCreater::subUtcFromTime(const int timeSec, const int utcOffsetSec)
{

    if (timeSec <= 0) {
        return 0;
    } else {
        return timeSec - utcOffsetSec;
    }
}

int ResultsCreater::subUtcFromTime(const QTime& time, const int utcOffsetSec)
{

    int timeSec = timeToSec(time);

    if (timeSec <= 0) {
        return 0;
    } else {
        return timeSec - utcOffsetSec;
    }
}

QString ResultsCreater::pointFlagToString(const unsigned int f)
{

    // original functions was in function.js and ScoreListTableDelegate.qml

    QStringList str;

    QVector<bool> arr;
    unsigned int nMask = f | 0x10000;

    // nMask must be between -2147483648 and 2147483647
    if (nMask > 0x7fffffff) {
        return "ERR - invalid mask value1";
    }
    for (int nShifted = nMask; nShifted;) {

        arr.push_back(bool(nShifted & 1));
        nShifted >>= 1;
    }

    if (arr[0]) {
        // "TP"
        str.push_back("track-list-delegate-ob-short");
    }
    if (arr[1]) {
        // "TG"
        str.push_back("track-list-delegate-tg-short");
    }
    if (arr[2]) {
        // "SG"
        str.push_back("track-list-delegate-sg-short");
    }
    if (arr[3]) {
        // "ALT_MIN"
        str.push_back("track-list-delegate-alt_min-short");
    }
    if (arr[4]) {
        // "ALT_MAX"
        str.push_back("track-list-delegate-alt_max-short");
    }
    if (arr[5]) {
        // "SPD_MIN"
        str.push_back("track-list-delegate-speed_min-short");
    }
    if (arr[6]) {
        // "SPD_MAX"
        str.push_back("track-list-delegate-speed_max-short");
    }
    if (arr[7]) {
        // "sss"
        str.push_back("track-list-delegate-section_speed_start-short");
    }
    if (arr[8]) {
        // "sse"
        str.push_back("track-list-delegate-section_speed_end-short");
    }
    if (arr[9]) {
        // "sas"
        str.push_back("track-list-delegate-section_alt_start-short");
    }
    if (arr[10]) {
        // "sae"
        str.push_back("track-list-delegate-section_alt_end-short");
    }
    if (arr[11]) {
        // "sws"
        str.push_back("track-list-delegate-section_space_start-short");
    }
    if (arr[12]) {
        // "swe"
        str.push_back("track-list-delegate-section_space_end-short");
    }
    if (arr[13]) {
        // "sec_tp"
        str.push_back("track-list-delegate-secret-turn-point-short");
    }
    if (arr[14]) {
        // "sec_tg"
        str.push_back("track-list-delegate-secret-time-gate-short");
    }
    if (arr[15]) {
        // "sec_sg"
        str.push_back("track-list-delegate-secret-space-gate-short");
    }

    return getTranslatedStringList(str).join(", ");
}
