/*
    Copyright (C) 2014  ABRT team
    Copyright (C) 2014  RedHat Inc

    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 2 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, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

    @brief API for formating of problem data

    These functions can be used to convert a problem data to its string
    representation.

    The output format can be parsed from a string:

        problem_formatter_t *formatter = problem_formatter_new();
        problem_formatter_load_string(formatter, MY_FORMAT_STRING);

    or loaded from a file:

        problem_formatter_t *formatter = problem_formatter_new();
        problem_formatter_load_file(formatter, MY_FORMAT_FILE);

    Once you have configured your formatter you can convert problem_data to
    problem_report by calling:

        problem_report_t *report;
        if (problem_formatter_generate_report(formatter, data, &report) != 0)
            errx(EXIT_FAILURE, "Problem data cannot be converted to problem report.");

    Now you can print the report:

        printf("Problem: %s\n", problem_report_get_summary());
        printf("%s\n",          problem_report_get_description());

        puts("Problem attachments:");
        for (GList *a = problem_report_get_attachments(pr); a != NULL; a = g_list_next(a))
            printf(" %s\n", a->data);

    Format description:

         ----
         %summary:: summary format
         %attach:: elemnt1[,element2]...
         section:: element1[,element2]...
         The literal text line to be added to report.
         ----

         Summary format is a line of text, where %element% is replaced by
         text element's content, and [[...%element%...]] block is used only if
         %element% exists. [[...]] blocks can nest.

         Sections can be:
         - %summary: bug summary format string.

         - %attach: a list of elements to attach.

         - text, double colon (::) and the list of comma-separated elements.
           Text can be empty (":: elem1, elem2, elem3" works),
           in this case "Text:" header line will be omitted.

         - %description: this section is implicit and contains all text
           sections unless another section was specified (%summary and %attach
           are ignored when determining text section's placement)

         - every text element belongs to the last specified section (%summary
           and %attach sections are ignored). If no section was specified,
           the text element belogns to %description.

         - If none of elements exists, the section will not be created.

         - Empty lines are NOT ignored.

         Elements can be:
         - problem directory element names, which get formatted as
           <element_name>: <contents>
           or
           <element_name>:
           :<contents>
           :<contents>
           :<contents>

         - problem directory element names prefixed by "%bare_",
           which is formatted as-is, without "<element_name>:" and colons

         - %oneline, %multiline, %text wildcards, which select all corresponding
           elements for output or attachment

         - %binary wildcard, valid only for %attach section, instructs to attach
           binary elements

         - %short_backtrace is a reserved element that is replaced with contents
           of backtrace file truncated to optimal number of frames

         - %reporter is a reserved element that is replaced by name and version
           of the software that created the report

         - problem directory element names prefixed by "-",
           which excludes given element from all wildcards

         - Nonexistent elements are silently ignored.

    You can add your own section:

        problem_formatter_t *formatter = problem_formatter_new();
        problem_formatter_add_section(formatter, "additional_info", PFFF_REQUIRED);

    and then you can use the section in the formatting string:

        problem_formatter_load_string(formatter,
                "::comment\n"
                "%additional_info:: maps");
        problem_formatter_generate_report(formatter, data, &report);

        printf("Problem: %s\n",         problem_report_get_summary());
        printf("%s\n",                  problem_report_get_description());
        printf("Additional info: %s\n", problem_report_get_section(report, "additiona_info"));

    The lines above are equivalent to the following lines:

        printf("Problem: %s\n",         problem_data_get_content_or_NULL(data, "reason"));
        printf("%s\n",                  problem_data_get_content_or_NULL(data, "comment"));
        printf("Additional info: %s\n", problem_data_get_content_or_NULL(data, "maps"));
*/
#ifndef LIBREPORT_PROBLEM_REPORT_H
#define LIBREPORT_PROBLEM_REPORT_H

#include <glib.h>
#include <stdio.h>
#include "problem_data.h"

#ifdef __cplusplus
extern "C" {
#endif

#define PR_SEC_SUMMARY "summary"
#define PR_SEC_DESCRIPTION "description"

/*
 * The problem report structure represents a problem data formatted according
 * to a format string.
 *
 * A problem report is composed of well-known sections:
 *   - summary
 *   - descritpion
 *   - attach
 *
 * and custom sections accessed by:
 *   problem_report_get_section();
 */
struct problem_report;
typedef struct problem_report problem_report_t;

/*
 * The problem report settings structure contains advance settings
 * for report generating
 */
struct problem_report_settings
{
    int prs_shortbt_max_frames;       ///< generate only max top frames in %short_backtrace
    size_t prs_shortbt_max_text_size; ///< short bt only if it is bigger then this
};

typedef struct problem_report_settings problem_report_settings_t;

/*
 * Helpers for easily switching between FILE and struct strbuf
 */

/*
 * Type of buffer used by Problem report
 */
typedef FILE problem_report_buffer;

/*
 * Wrapper for the proble buffer's formated output function.
 */
#define problem_report_buffer_printf(buf, fmt, ...)\
    fprintf((buf), (fmt), ##__VA_ARGS__)


/*
 * Get a section buffer
 *
 * Use this function if you need to amend something to a formatted section.
 *
 * @param self Problem report
 * @param section_name Name of required section
 * @return Always valid pointer to a section buffer
 */
problem_report_buffer *problem_report_get_buffer(const problem_report_t *self,
        const char *section_name);

/*
 * Get Summary string
 *
 * The returned pointer is valid as long as you perform no further output to
 * the summary buffer.
 *
 * @param self Problem report
 * @return Non-NULL pointer to summary data
 */
const char *problem_report_get_summary(const problem_report_t *self);

/*
 * Get Description string
 *
 * The returned pointer is valid as long as you perform no further output to
 * the description buffer.
 *
 * @param self Problem report
 * @return Non-NULL pointer to description data
 */
const char *problem_report_get_description(const problem_report_t *self);

/*
 * Get Section's string
 *
 * The returned pointer is valid as long as you perform no further output to
 * the section's buffer.
 *
 * @param self Problem report
 * @param section_name Name of the required section
 * @return Non-NULL pointer to description data
 */
const char *problem_report_get_section(const problem_report_t *self,
        const char *section_name);

/*
 * Get GList of the problem data items that are to be attached
 *
 * @param self Problem report
 * @return A pointer to GList (NULL means empty list)
 */
GList *problem_report_get_attachments(const problem_report_t *self);

/*
 * Releases all resources allocated by a problem report
 *
 * @param self Problem report
 */
void problem_report_free(problem_report_t *self);


/*
 * An enum of Extra section flags
 */
enum problem_formatter_section_flags {
    PFFF_REQUIRED = 1 << 0, ///< section must be present in the format spec
};

/*
 * The problem formatter structure formats a problem data according to a format
 * string and stores result a problem report.
 *
 * The problem formatter uses '%reason%' as %summary section format string, if
 * %summary is not provided by a format string.
 */
struct problem_formatter;
typedef struct problem_formatter problem_formatter_t;

/*
 * Constructs a new problem formatter.
 *
 * @return Non-NULL pointer to the new problem formatter
 */
problem_formatter_t *problem_formatter_new(void);

/*
 * Releases all resources allocated by a problem formatter
 *
 * @param self Problem formatter
 */
void problem_formatter_free(problem_formatter_t *self);

/*
 * Adds a new recognized section
 *
 * The problem formatter ignores a section in the format spec if the section is
 * not one of the default nor added by this function.
 *
 * How the problem formatter handles these extra sections:
 *
 * A custom section is something like %description section. %description is the
 * default section where all text (sub)sections are stored. If the formatter
 * finds the custom section in format string, then starts storing text
 * (sub)sections in the custom section.
 *
 * (%description)    |:: comment
 * (%description)    |
 * (%description)    |Package:: package
 * (%description)    |
 * (%additiona_info) |%additional_info::
 * (%additiona_info) |%reporter%
 * (%additiona_info) |User:: user_name,uid
 * (%additiona_info) |
 * (%additiona_info) |Directories:: root,cwd
 *
 *
 * @param self Problem formatter
 * @param name Name of the added section
 * @param flags Info about the added section
 * @return Zero on success. -EEXIST if the name is already known by the formatter
 */
int problem_formatter_add_section(problem_formatter_t *self, const char *name, int flags);

/*
 * Loads a problem format from a string.
 *
 * @param self Problem formatter
 * @param fmt Format
 * @return Zero on success or number of warnings (e.g. missing section,
 * unrecognized section).
 */
int problem_formatter_load_string(problem_formatter_t* self, const char *fmt);

/*
 * Loads a problem format from a file.
 *
 * @param self Problem formatter
 * @param pat Path to the format file
 * @return Zero on success or number of warnings (e.g. missing section,
 * unrecognized section).
 */
int problem_formatter_load_file(problem_formatter_t* self, const char *path);

/*
 * Creates a new problem report, formats the data according to the loaded
 * format string and stores output in the report.
 *
 * @param self Problem formatter
 * @param data Problem data to format
 * @param report Pointer where the created problem report is to be stored
 * @return Zero on success, otherwise non-zero value.
 */
int problem_formatter_generate_report(const problem_formatter_t *self, problem_data_t *data, problem_report_t **report);

/*
 * Returns problem report settings from given formatter
 *
 * @param self Problem formatter
 * @return problem report settings
 */
problem_report_settings_t problem_formatter_get_settings(const problem_formatter_t *self);

/*
 * Sets problem report settings to given formatter
 *
 * @param self Problem formatter
 * @param settings Problem report settings
 */
void problem_formatter_set_settings(problem_formatter_t *self, problem_report_settings_t settings);

#ifdef __cplusplus
}
#endif

#endif // LIBREPORT_PROBLEM_REPORT_H
