QString Mtp3SummaryDialog::summaryToHtml()
{
    summary_tally summary;
    memset(&summary, 0, sizeof(summary_tally));

    QString section_tmpl;
    QString table_begin, table_end;
    QString table_row_begin, table_ul_row_begin, table_row_end;
    QString table_vheader_tmpl, table_hheader15_tmpl, table_hheader25_tmpl;
    QString table_data_tmpl;

    section_tmpl = "<p><strong>%1</strong></p>\n";
    table_begin = "<p><table>\n";
    table_end = "</table></p>\n";
    table_row_begin = "<tr>\n";
    table_ul_row_begin = "<tr style=\"border-bottom: 1px solid gray;\">\n";
    table_row_end = "</tr>\n";
    table_vheader_tmpl = "<td width=\"50%\">%1:</td>"; // <th align="left"> looked odd
    table_hheader15_tmpl = "<td width=\"15%\"><u>%1</u></td>";
    table_hheader25_tmpl = "<td width=\"25%\"><u>%1</u></td>";
    table_data_tmpl = "<td>%1</td>";

    if (cap_file_.isValid()) {
        /* initial computations */
        summary_fill_in(cap_file_.capFile(), &summary);
#ifdef HAVE_LIBPCAP
        summary_fill_in_capture(cap_file_.capFile(), &global_capture_opts, &summary);
#endif
    }

    QString summary_str;
    QTextStream out(&summary_str);

    // File Section
    out << section_tmpl.arg(tr("File"));
    out << table_begin;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Name"))
        << table_data_tmpl.arg(summary.filename)
        << table_row_end;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Length"))
        << table_data_tmpl.arg(file_size_to_qstring(summary.file_length))
        << table_row_end;

    QString format_str = wtap_file_type_subtype_string(summary.file_type);
    if (summary.iscompressed) {
        format_str.append(tr(" (gzip compressed)"));
    }
    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Format"))
        << table_data_tmpl.arg(format_str)
        << table_row_end;

    if (summary.has_snap) {
        out << table_row_begin
            << table_vheader_tmpl.arg(tr("Snapshot length"))
            << table_data_tmpl.arg(summary.snap)
            << table_row_end;
    }

    out << table_end;

    // Data Section
    out << section_tmpl.arg(tr("Data"));
    out << table_begin;

    if (summary.packet_count_ts == summary.packet_count &&
            summary.packet_count >= 1)
    {
        // start time
        out << table_row_begin
            << table_vheader_tmpl.arg(tr("First packet"))
            << table_data_tmpl.arg(time_t_to_qstring((time_t)summary.start_time))
            << table_row_end;

        // stop time
        out << table_row_begin
            << table_vheader_tmpl.arg(tr("Last packet"))
            << table_data_tmpl.arg(time_t_to_qstring((time_t)summary.stop_time))
            << table_row_end;

        // elapsed seconds (capture duration)
        if (summary.packet_count_ts > 1)
        {
            /* elapsed seconds */
            QString elapsed_str;
            unsigned int elapsed_time = (unsigned int)summary.elapsed_time;
            if (elapsed_time/86400)
            {
                elapsed_str = QString("%1 days ").arg(elapsed_time / 86400);
            }

            elapsed_str += QString("%1:%2:%3")
                    .arg(elapsed_time % 86400 / 3600, 2, 10, QChar('0'))
                    .arg(elapsed_time % 3600 / 60, 2, 10, QChar('0'))
                    .arg(elapsed_time % 60, 2, 10, QChar('0'));
            out << table_row_begin
                << table_vheader_tmpl.arg(tr("Elapsed"))
                << table_data_tmpl.arg(elapsed_str)
                << table_row_end;
        }
    }

    // count
    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Packets"))
        << table_data_tmpl.arg(summary.packet_count)
        << table_row_end;

    out << table_end;

    // TRANSLATOR Abbreviation for "not applicable"
    QString n_a = tr("N/A");
    int total_msus = 0;
    int total_bytes = 0;
    double seconds = summary.stop_time - summary.start_time;

    // SI Section
    out << section_tmpl.arg(tr("Service Indicator (SI) Totals"));
    out << table_begin;

    out << table_row_begin
        << table_hheader25_tmpl.arg(tr("SI"))
        << table_hheader15_tmpl.arg(tr("MSUs"))
        << table_hheader15_tmpl.arg(tr("MSUs/s"))
        << table_hheader15_tmpl.arg(tr("Bytes"))
        << table_hheader15_tmpl.arg(tr("Bytes/MSU"))
        << table_hheader15_tmpl.arg(tr("Bytes/s"))
        << table_row_end;

    for (size_t si_code = 0; si_code < MTP3_NUM_SI_CODE; si_code++) {
        int si_msus = 0;
        int si_bytes = 0;
        QString msus_s_str = n_a;
        QString bytes_msu_str = n_a;
        QString bytes_s_str = n_a;

        for (size_t stat_idx = 0; stat_idx < mtp3_num_used; stat_idx++) {
            si_msus += mtp3_stat[stat_idx].mtp3_si_code[si_code].num_msus;
            si_bytes += mtp3_stat[stat_idx].mtp3_si_code[si_code].size;
        }
        total_msus += si_msus;
        total_bytes += si_bytes;

        if (seconds > 0) {
            msus_s_str = QString("%1").arg(si_msus / seconds, 1, 'f', 1);
            bytes_s_str = QString("%1").arg(si_bytes / seconds, 1, 'f', 1);
        }

        if (si_msus > 0) {
            bytes_msu_str = QString("%1").arg((double) si_bytes / si_msus, 1, 'f', 1);
        }

        out << table_row_begin
            << table_data_tmpl.arg(mtp3_service_indicator_code_short_vals[si_code].strptr)
            << table_data_tmpl.arg(si_msus)
            << table_data_tmpl.arg(msus_s_str)
            << table_data_tmpl.arg(si_bytes)
            << table_data_tmpl.arg(bytes_msu_str)
            << table_data_tmpl.arg(bytes_s_str)
            << table_row_end;
    }

    out << table_end;

    // Totals Section

    QString total_msus_s_str = n_a;
    QString total_bytes_msu_str = n_a;
    QString total_bytes_s_str = n_a;

    if (seconds > 0) {
        total_msus_s_str = QString("%1").arg(total_msus / seconds, 1, 'f', 1);
        total_bytes_s_str = QString("%1").arg(total_bytes / seconds, 1, 'f', 1);
    }
    if (total_msus > 0) {
        total_bytes_msu_str = QString("%1").arg((double) total_bytes / total_msus, 1, 'f', 1);
    }

    out << section_tmpl.arg(tr("Totals"));
    out << table_begin;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Total MSUs"))
        << table_data_tmpl.arg(total_msus)
        << table_row_end;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("MSUs/s"))
        << table_data_tmpl.arg(total_msus_s_str)
        << table_row_end;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Total Bytes"))
        << table_data_tmpl.arg(total_bytes)
        << table_row_end;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Average Bytes/MSU"))
        << table_data_tmpl.arg(total_bytes_msu_str)
        << table_row_end;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Average Bytes/s"))
        << table_data_tmpl.arg(total_bytes_s_str)
        << table_row_end;

    out << table_end;

    return summary_str;
}
// Copied from capture_file_properties_dialog.cpp
QString GsmMapSummaryDialog::summaryToHtml()
{
    summary_tally summary;
    memset(&summary, 0, sizeof(summary_tally));

    QString section_tmpl;
    QString table_begin, table_end;
    QString table_row_begin, table_ul_row_begin, table_row_end;
    QString table_vheader_tmpl;
    QString table_data_tmpl;

    section_tmpl = "<p><strong>%1</strong></p>\n";
    table_begin = "<p><table>\n";
    table_end = "</table></p>\n";
    table_row_begin = "<tr>\n";
    table_ul_row_begin = "<tr style=\"border-bottom: 1px solid gray;\">\n";
    table_row_end = "</tr>\n";
    table_vheader_tmpl = "<td width=\"50%\">%1:</td>"; // <th align="left"> looked odd
    table_data_tmpl = "<td>%1</td>";

    if (cap_file_.isValid()) {
        /* initial computations */
        summary_fill_in(cap_file_.capFile(), &summary);
#ifdef HAVE_LIBPCAP
        summary_fill_in_capture(cap_file_.capFile(), &global_capture_opts, &summary);
#endif
    }

    QString summary_str;
    QTextStream out(&summary_str);

    // File Section
    out << section_tmpl.arg(tr("File"));
    out << table_begin;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Name"))
        << table_data_tmpl.arg(summary.filename)
        << table_row_end;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Length"))
        << table_data_tmpl.arg(file_size_to_qstring(summary.file_length))
        << table_row_end;

    QString format_str = wtap_file_type_subtype_string(summary.file_type);
    if (summary.iscompressed) {
        format_str.append(tr(" (gzip compressed)"));
    }
    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Format"))
        << table_data_tmpl.arg(format_str)
        << table_row_end;

    if (summary.has_snap) {
        out << table_row_begin
            << table_vheader_tmpl.arg(tr("Snapshot length"))
            << table_data_tmpl.arg(summary.snap)
            << table_row_end;
    }

    out << table_end;

    // Data Section
    out << section_tmpl.arg(tr("Data"));
    out << table_begin;

    if (summary.packet_count_ts == summary.packet_count &&
            summary.packet_count >= 1)
    {
        // start time
        out << table_row_begin
            << table_vheader_tmpl.arg(tr("First packet"))
            << table_data_tmpl.arg(time_t_to_qstring((time_t)summary.start_time))
            << table_row_end;

        // stop time
        out << table_row_begin
            << table_vheader_tmpl.arg(tr("Last packet"))
            << table_data_tmpl.arg(time_t_to_qstring((time_t)summary.stop_time))
            << table_row_end;

        // elapsed seconds (capture duration)
        if (summary.packet_count_ts > 1)
        {
            /* elapsed seconds */
            QString elapsed_str;
            unsigned int elapsed_time = (unsigned int)summary.elapsed_time;
            if (elapsed_time/86400)
            {
                elapsed_str = QString("%1 days ").arg(elapsed_time / 86400);
            }

            elapsed_str += QString("%1:%2:%3")
                    .arg(elapsed_time % 86400 / 3600, 2, 10, QChar('0'))
                    .arg(elapsed_time % 3600 / 60, 2, 10, QChar('0'))
                    .arg(elapsed_time % 60, 2, 10, QChar('0'));
            out << table_row_begin
                << table_vheader_tmpl.arg(tr("Elapsed"))
                << table_data_tmpl.arg(elapsed_str)
                << table_row_end;
        }
    }

    // count
    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Packets"))
        << table_data_tmpl.arg(summary.packet_count)
        << table_row_end;

    out << table_end;

    // TRANSLATOR Abbreviation for "not applicable"
    QString n_a = tr("N/A");
    QString invoke_rate_str, result_rate_str, total_rate_str;
    QString invoke_avg_size_str, result_avg_size_str, total_avg_size_str;

    // Message averages
    invoke_rate_str = result_rate_str = total_rate_str = n_a;
    invoke_avg_size_str = result_avg_size_str = total_avg_size_str = n_a;

    double seconds = summary.stop_time - summary.start_time;
    int invoke_count = 0, invoke_bytes = 0;
    int result_count = 0, result_bytes = 0;

    for (int i = 0; i < GSM_MAP_MAX_NUM_OPR_CODES; i++) {
        invoke_count += gsm_map_stat.opr_code[i];
        invoke_bytes += gsm_map_stat.size[i];
    }


    for (int i = 0; i < GSM_MAP_MAX_NUM_OPR_CODES; i++) {
        result_count += gsm_map_stat.opr_code_rr[i];
        result_bytes += gsm_map_stat.size_rr[i];
    }

    int total_count = invoke_count + result_count;
    int total_bytes = invoke_bytes + result_bytes;

    /*
     * We must have no un-time-stamped packets (i.e., the number of
     * time-stamped packets must be the same as the number of packets),
     * and at least two time-stamped packets, in order for the elapsed
     * time to be valid.
     */
    if (summary.packet_count_ts > 1 && seconds > 0.0) {
        /* Total number of invokes per second */
        invoke_rate_str = QString("%1").arg(invoke_count / seconds, 1, 'f', 1);
        result_rate_str = QString("%1").arg(result_count / seconds, 1, 'f', 1);
        total_rate_str = QString("%1").arg((total_count) / seconds, 1, 'f', 1);
    }

    /* Average message sizes */
    if (invoke_count > 0) {
        invoke_avg_size_str = QString("%1").arg((double) invoke_bytes / invoke_count, 1, 'f', 1);
    }
    if (result_count > 0) {
        result_avg_size_str = QString("%1").arg((double) result_bytes / result_count, 1, 'f', 1);
    }
    if (total_count > 0) {
        total_avg_size_str = QString("%1").arg((double) total_bytes / total_count, 1, 'f', 1);
    }

    // Invoke Section
    out << section_tmpl.arg(tr("Invokes"));
    out << table_begin;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Total number of Invokes"))
        << table_data_tmpl.arg(invoke_count)
        << table_row_end;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Average number of Invokes per second"))
        << table_data_tmpl.arg(invoke_rate_str)
        << table_row_end;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Total number of bytes for Invokes"))
        << table_data_tmpl.arg(invoke_bytes)
        << table_row_end;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Average number of bytes per Invoke"))
        << table_data_tmpl.arg(invoke_avg_size_str)
        << table_row_end;

    out << table_end;

    // Return Result Section
    out << section_tmpl.arg(tr("Return Results"));
    out << table_begin;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Total number of Return Results"))
        << table_data_tmpl.arg(result_count)
        << table_row_end;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Average number of Return Results per second"))
        << table_data_tmpl.arg(result_rate_str)
        << table_row_end;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Total number of bytes for Return Results"))
        << table_data_tmpl.arg(result_bytes)
        << table_row_end;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Average number of bytes per Return Result"))
        << table_data_tmpl.arg(result_avg_size_str)
        << table_row_end;

    out << table_end;

    // Total Section
    out << section_tmpl.arg(tr("Totals"));
    out << table_begin;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Total number of GSM MAP messages"))
        << table_data_tmpl.arg(total_count)
        << table_row_end;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Average number of GSM MAP messages per second"))
        << table_data_tmpl.arg(total_rate_str)
        << table_row_end;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Total number of bytes for GSM MAP messages"))
        << table_data_tmpl.arg(total_bytes)
        << table_row_end;

    out << table_row_begin
        << table_vheader_tmpl.arg(tr("Average number of bytes per GSM MAP message"))
        << table_data_tmpl.arg(total_avg_size_str)
        << table_row_end;

    out << table_end;

    return summary_str;
}