// vim: ts=4 sw=4 expandtab ft=c

// Copyright (C) 1998-2000,2002-2006 The University of Melbourne.
// Copyright (C) 2014, 2016, 2018 The Mercury team.
// This file is distributed under the terms specified in COPYING.LIB.

// mercury_trace_help.c
//
// Main author: Zoltan Somogyi.
//
// Help system for the internal debugger.
// Most of the implementation is in browser/help.m;
// this is only the interface.

// Some header files refer to files automatically generated by the Mercury
// compiler for modules in the browser and library directories.
//
// XXX Figure out how to prevent these names from encroaching on the user's
// name space.

#include "mercury_imp.h"
#include "mercury_layout_util.h"
#include "mercury_array_macros.h"
#include "mercury_deep_copy.h"

#include "mercury_trace_help.h"
#include "mercury_trace_internal.h"
#include "mercury_trace_util.h"

#include "type_desc.mh"
#include "io.mh"

#include "mdb.help.mh"

#include <stdio.h>

MR_Word             MR_trace_help_system;
static  MR_TypeInfo MR_trace_help_system_type;

static  const char  *MR_trace_help_add_node(MR_Word path, const char *name,
                        int slot, const char *text);
static  void        MR_trace_help_ensure_init(void);

// Used for completion of arguments of the `help' command.
static  char        **MR_help_words = NULL;
static  int         MR_help_word_max = 0;
static  int         MR_help_word_next = 0;

static  void        MR_trace_add_help_word(const char *word);
static  char        *MR_trace_get_help_word(int slot);

const char *
MR_trace_add_cat(const char *category, int slot, const char *text)
{
    MR_Word path;

    MR_trace_help_ensure_init();
    MR_trace_add_help_word(category);

    MR_TRACE_USE_HP(
        path = MR_list_empty();
    );
    return MR_trace_help_add_node(path, category, slot, text);
}

const char *
MR_trace_add_item(const char *category, const char *item, int slot,
    const char *text)
{
    MR_Word     path;
    char        *category_on_heap;

    MR_trace_help_ensure_init();
    MR_trace_add_help_word(item);

    MR_TRACE_USE_HP(
        MR_make_aligned_string_copy(category_on_heap, category);
        path = MR_list_empty();
        path = MR_string_list_cons((MR_Word) category_on_heap, path);
    );

    return MR_trace_help_add_node(path, item, slot, text);
}

static const char *
MR_trace_help_add_node(MR_Word path, const char *name, int slot,
    const char *text)
{
    MR_Word result;
    char    *msg;
    char    *name_on_heap;
    char    *text_on_heap;
    MR_bool error;

    MR_TRACE_USE_HP(
        MR_make_aligned_string_copy(name_on_heap, name);
        MR_make_aligned_string_copy(text_on_heap, text);
    );

    MR_TRACE_CALL_MERCURY(
        ML_HELP_add_help_node(path, slot, name_on_heap, text_on_heap,
            &result, MR_trace_help_system, &MR_trace_help_system);
        error = ML_HELP_result_is_error(result, &msg);
    );

    MR_trace_help_system = MR_make_permanent(MR_trace_help_system,
        MR_trace_help_system_type);

    return (error ? msg : NULL);
}

void
MR_trace_help(void)
{
    MercuryFile mdb_out;

    MR_trace_help_ensure_init();

    MR_c_file_to_mercury_file(MR_mdb_out, &mdb_out);

    MR_TRACE_CALL_MERCURY(
        ML_HELP_print_top_level_help_nodes(MR_wrap_output_stream(&mdb_out),
            MR_trace_help_system);
    );
}

void
MR_trace_help_word(const char *word)
{
    char        *word_on_heap;
    MercuryFile mdb_out;

    MR_trace_help_ensure_init();

    MR_TRACE_USE_HP(
        MR_make_aligned_string_copy(word_on_heap, word);
    );

    MR_c_file_to_mercury_file(MR_mdb_out, &mdb_out);
    MR_TRACE_CALL_MERCURY(
        ML_HELP_print_help_for_name(MR_wrap_output_stream(&mdb_out),
            MR_trace_help_system, word_on_heap);
    );
}

void
MR_trace_help_cat_item(const char *category, const char *item)
{
    MR_Word     path;
    MR_Word     result;
    char        *msg;
    char        *category_on_heap;
    char        *item_on_heap;
    MR_bool     error;
    MercuryFile mdb_out;

    MR_trace_help_ensure_init();

    MR_TRACE_USE_HP(
        MR_make_aligned_string_copy(category_on_heap, category);
        MR_make_aligned_string_copy(item_on_heap, item);
        path = MR_list_empty();
        path = MR_string_list_cons((MR_Word) item_on_heap, path);
        path = MR_string_list_cons((MR_Word) category_on_heap, path);
    );

    MR_c_file_to_mercury_file(MR_mdb_out, &mdb_out);
    MR_TRACE_CALL_MERCURY(
        ML_HELP_print_help_node_at_path(MR_wrap_output_stream(&mdb_out),
            MR_trace_help_system, path, &result);
        error = ML_HELP_result_is_error(result, &msg);
    );

    if (error) {
        printf("error in the trace help system: %s\n", msg);
    }
}

static void
MR_trace_help_ensure_init(void)
{
    static  MR_bool done = MR_FALSE;
    MR_Word     typeinfo_type;
    MR_Word     MR_trace_help_system_type_word;

    if (! done) {
        MR_TRACE_CALL_MERCURY(
            typeinfo_type = ML_get_type_info_for_type_info();
            ML_HELP_help_system_type(&MR_trace_help_system_type_word);
            MR_trace_help_system_type = (MR_TypeInfo)
                MR_trace_help_system_type_word;
            ML_HELP_init(&MR_trace_help_system);
        );

        MR_trace_help_system_type = (MR_TypeInfo) MR_make_permanent(
            (MR_Word) MR_trace_help_system_type, (MR_TypeInfo) typeinfo_type);
        MR_trace_help_system = MR_make_permanent(MR_trace_help_system,
            MR_trace_help_system_type);
        done = MR_TRUE;
    }
}

// Add the help categories and items to a sorted array for use in completion.

static void
MR_trace_add_help_word(const char *word)
{
    MR_bool found;
    int slot;

    MR_bsearch(MR_help_word_next, slot, found,
        strcmp(MR_help_words[slot], word));
    if (!found) {
        MR_ensure_room_for_next(MR_help_word, char *, 100);
        MR_prepare_insert_into_sorted(MR_help_words, MR_help_word_next, slot,
            strcmp(MR_help_words[slot], word));
        MR_help_words[slot] = MR_copy_string(word);
    }
}

MR_CompleterList *
MR_trace_help_completer(const char *word, size_t word_len)
{
    return MR_trace_sorted_array_completer(word, word_len,
        MR_help_word_next, MR_trace_get_help_word);
}

static char *
MR_trace_get_help_word(int slot)
{
    return MR_help_words[slot];
}
