// =============================================================== //
//                                                                 //
//   File      : prompt.cxx                                        //
//   Purpose   : prompt for text (macro-compatible)                //
//                                                                 //
//   Coded by Ralf Westram (coder@reallysoft.de) in October 2017   //
//   http://www.arb-home.de/                                       //
//                                                                 //
// =============================================================== //

#include "prompt.hxx"

#include <aw_window.hxx>
#include <aw_root.hxx>
#include <aw_awar.hxx>

#define PROMPT_AWAR_PREFIX "tmp/prompt/"

#define AWAR_PROMPT_TEXT   PROMPT_AWAR_PREFIX "text"
#define AWAR_PROMPT_INPUT  PROMPT_AWAR_PREFIX "input"
#define AWAR_PROMPT_BUTTON PROMPT_AWAR_PREFIX "button"
#define AWAR_PROMPT_ERROR  PROMPT_AWAR_PREFIX "error"

struct PromptData : virtual Noncopyable {
    ResultHandler  handler;
    const char    *helpfile;
    Widget         help_button;

    PromptData(const ResultHandler& handler_) : handler(handler_), helpfile(NULp) {}
};

static GB_ERROR hidden_ok_pressed() { return "disabled"; }

static void ok_pressed(AW_window *aww, PromptData *pdata) {
    AW_root *awr   = aww->get_root();
    char    *input = awr->awar(AWAR_PROMPT_INPUT)->read_string();

    GB_ERROR error = pdata->handler(input);
    if (error) {
        awr->awar(AWAR_PROMPT_ERROR)->write_string(error);
    }
    else {
        pdata->handler = makeResultHandler(hidden_ok_pressed);
        aww->hide(); // close prompter when handled
    }

    free(input);
}
static void run_help_cb(AW_window *aww, const PromptData *pdata) {
    if (pdata->helpfile) {
        AW_help_popup(NULp, pdata->helpfile);
    }
    else {
        aww->get_root()->awar(AWAR_PROMPT_ERROR)->write_string("No help :-(");
    }
}

static void clear_input_cb(AW_window *aww) {
    aww->get_root()->awar(AWAR_PROMPT_INPUT)->write_string("");
}

void AWT_activate_prompt(const char *title, const char *prompt, const char *defaultResult, const char *button, const ResultHandler& handle_result, const char *helpfile, const char *srt) {
    /*! pops up an text input prompter
     *
     * (macro-capable replacement for aw_input)
     *
     * @param title         window title
     * @param prompt        question or request shown above input field
     * @param defaultResult default value for input field
     * @param button        text shown on "ENTER" button (maxlen: 7)
     * @param handle_result called with entered result (even if empty)
     * @param helpfile      context sensitive helpfile (defaults to NULp)
     * @param srt           SRT command will be applied to userinput (defaults to NULp; should not be dynamic)
     *                      Use e.g. to correct name-prefixes like "tree_" or "ali_"
     *
     * Note that all activated prompts use the same window. Activating a second
     * prompt (while the user did not answer the first one), will hide the first prompt.
     */
    static AW_window_simple *aws = NULp; // one window used for all prompts
    static PromptData        pdata(handle_result);

    pdata.handler  = handle_result;
    pdata.helpfile = helpfile;

    AW_root *awr = AW_root::SINGLETON;
    if (!aws) {
        awr->awar_string(AWAR_PROMPT_TEXT, "");
        awr->awar_string(AWAR_PROMPT_INPUT, "");
        awr->awar_string(AWAR_PROMPT_BUTTON, "OK");
        awr->awar_string(AWAR_PROMPT_ERROR, "");

        aws = new AW_window_simple;
        aws->init(awr, "PROMPT", "Prompt");

        const int PAD      = 10;
        const int IF_YSIZE = 32; // lineheight of attached input field
        const int TX_YSIZE = 18; // lineheight of text (button w/o cb)
        const int BT_YSIZE = 22; // lineheight of button

        aws->at(PAD, PAD);
        aws->auto_space(PAD/2, PAD/2);

        aws->at_attach_to(true, false, -PAD, TX_YSIZE);
        aws->create_button(NULp, AWAR_PROMPT_TEXT);
        aws->at_unattach();

        aws->at_newline();

        WindowCallback ok_cb = makeWindowCallback(ok_pressed, &pdata);

        aws->at_attach_to(true, false, -PAD, IF_YSIZE);
        aws->d_callback(ok_cb); // enable ENTER in textfield to press "ENTER"-button
        aws->create_input_field(AWAR_PROMPT_INPUT, 50);
        aws->at_unattach();

        aws->at_shift(300, 0); // defines minimum window width

        aws->at_newline();

        aws->button_length(8);

        aws->callback(ok_cb);
        aws->highlight();
        aws->create_button("ENTER", AWAR_PROMPT_BUTTON, NULp, "+");

        int xb1 = aws->get_at_xposition();

        aws->callback(AW_POPDOWN);
        aws->create_button("CANCEL", "Cancel");

        int xb2    = aws->get_at_xposition();
        int bwidth = xb2 - xb1 - PAD;

        aws->at_attach(-bwidth-PAD, 0);
        aws->at_attach_to(true, false, -PAD, BT_YSIZE);
        aws->callback(clear_input_cb);
        aws->create_button("CLEAR", "Clear");

        aws->at_attach(2*(-bwidth-PAD), 0);
        aws->at_attach_to(true, false, -bwidth-2*PAD, BT_YSIZE);
        aws->callback(makeWindowCallback(run_help_cb, &pdata));
        aws->create_button("HELP", "Help");
        aws->at_unattach();

        pdata.help_button = aws->get_last_widget();

        aws->at_newline();
        const int ERR_YSIZE = 2*TX_YSIZE;
        aws->at_shift(0, ERR_YSIZE);  // defines minimum height of error display
        aws->at_shift(0, -ERR_YSIZE); // go back

        aws->at_attach_to(true, true, -PAD, -PAD);
        aws->create_button(NULp, AWAR_PROMPT_ERROR, NULp, "-");
        aws->at_unattach();

        aws->recalc_pos_atShow(AW_REPOS_TO_MOUSE);
    }
    else {
        aws->hide(); // hide previously displayed prompt
    }

    // configure active prompt:
    aws->set_window_title(title);
    awr->set_active(pdata.help_button, pdata.helpfile);

    awr->awar(AWAR_PROMPT_TEXT)  ->write_string(prompt);
    awr->awar(AWAR_PROMPT_BUTTON)->write_string(button);
    awr->awar(AWAR_PROMPT_ERROR) ->write_string("");

    AW_awar *awar_input = awr->awar(AWAR_PROMPT_INPUT);
    awar_input->set_srt(srt); // set or reset SRT
    awar_input->write_string(defaultResult);

    aws->recalc_size_atShow(AW_RESIZE_USER); // allows user size + forces minimum size (when shrinked)

    aws->activate();
}
