// =============================================================== //
//                                                                 //
//   File      : MG_extendeds.cxx                                  //
//   Purpose   :                                                   //
//                                                                 //
//   Institute of Microbiology (Technical University Munich)       //
//   http://www.arb-home.de/                                       //
//                                                                 //
// =============================================================== //

#include "merge.hxx"

#include <db_scanner.hxx>
#include <sel_boxes.hxx>
#include <prompt.hxx>
#include <aw_msg.hxx>
#include <aw_root.hxx>
#include <arbdbt.h>

#define AWAR_EX_NAME_SRC AWAR_MERGE_TMP_SRC "extended_name"
#define AWAR_EX_NAME_DST AWAR_MERGE_TMP_DST "extended_name"
#define AWAR_EX_NAME(db) awar_name_tmp(db, "extended_name")

void MG_create_extendeds_awars(AW_root *aw_root, AW_default aw_def) {
    aw_root->awar_string(AWAR_EX_NAME_SRC, "", aw_def);
    aw_root->awar_string(AWAR_EX_NAME_DST, "", aw_def);
}

static GB_ERROR extended_rename_handler(const char *dest, DbSel db) {
    GBDATA     *gbmain = get_gb_main(db);
    AW_root    *awr    = AW_root::SINGLETON;
    const char *source = awr->awar(AWAR_EX_NAME(db))->read_char_pntr();

    GB_ERROR error = GB_begin_transaction(gbmain);
    if (!error) {
        GBDATA *gb_sai_data     = GBT_get_SAI_data(gbmain);
        if (!gb_sai_data) error = GB_await_error();
        else {
            GBDATA *gb_sai      = GBT_find_SAI_rel_SAI_data(gb_sai_data, source);
            GBDATA *gb_dest_sai = GBT_find_SAI_rel_SAI_data(gb_sai_data, dest);

            if (gb_dest_sai) error  = GBS_global_string("SAI '%s' already exists", dest);
            else if (!gb_sai) error = "Please select a SAI";
            else error              = GBT_write_string(gb_sai, "name", dest);
        }
    }
    error = GB_end_transaction(gbmain, error);

    return error;
}

static void extended_rename_cb(AW_window *aww, DbSel db) {
    ResultHandler  handler = makeResultHandler(extended_rename_handler, db);
    const char    *source  = aww->get_root()->awar(AWAR_EX_NAME(db))->read_char_pntr();
    AWT_activate_prompt("Rename SAI", "Enter the new name of the SAI:", source, "Rename", handler);
}

static void MG_extended_delete_cb(AW_window *aww, DbSel db) {
    GBDATA   *gbmain = get_gb_main(db);
    GB_ERROR  error  = GB_begin_transaction(gbmain);

    if (!error) {
        char   *source    = aww->get_root()->awar(AWAR_EX_NAME(db))->read_string();
        GBDATA *gb_sai    = GBT_find_SAI(gbmain, source);
        if (gb_sai) error = GB_delete(gb_sai);
        else    error     = "Please select a SAI first";

        free(source);
    }
    GB_end_transaction_show_error(gbmain, error, aw_message);
}

static void MG_transfer_extended(AW_window *aww) {
    AW_root *awr     = aww->get_root();
    char    *sainame = awr->awar(AWAR_EX_NAME_SRC)->read_string();

    GB_ERROR error    = GB_begin_transaction(GLOBAL_gb_dst);
    if (!error) error = GB_begin_transaction(GLOBAL_gb_src);

    if (!error) {
        GBDATA *gb_src = GBT_find_SAI(GLOBAL_gb_src, sainame);

        if (!gb_src) error = "Please select the SAI you want to transfer";
        else {
            GBDATA *gb_dst_sai_data     = GBT_get_SAI_data(GLOBAL_gb_dst);
            if (!gb_dst_sai_data) error = GB_await_error();
            else {
                GBDATA *gb_dest_sai = GBT_find_SAI_rel_SAI_data(gb_dst_sai_data, sainame);
                if (gb_dest_sai) {
                    error = GBS_global_string("SAI '%s' exists, delete it first", sainame);
                }
                if (!error) {
                    gb_dest_sai             = GB_create_container(gb_dst_sai_data, "extended");
                    if (!gb_dest_sai) error = GB_await_error();
                    else error              = GB_copy_dropProtectMarksAndTempstate(gb_dest_sai, gb_src);
                }
            }
        }
    }

    error = GB_end_transaction(GLOBAL_gb_dst, error);
    error = GB_end_transaction(GLOBAL_gb_src, error);
    if (error) aw_message(error);

    free(sainame);
}

static void map_extended(AW_root *aw_root, DbScanner *scanner, DbSel db) {
    GBDATA *gb_main = get_gb_main(db);
    GB_transaction ta(gb_main);
    GBDATA *gb_sai  = GBT_find_SAI(gb_main, aw_root->awar(AWAR_EX_NAME(db))->read_char_pntr());
    scanner->Map(gb_sai, CHANGE_KEY_PATH);
}

// -------------------------
//      MG_SAI_selector

static void mg_select_sai1(GBDATA*, AW_root *aw_root, const char *item_name) {
    aw_root->awar(AWAR_EX_NAME_SRC)->write_string(item_name);
}
static void mg_select_sai2(GBDATA*, AW_root *aw_root, const char *item_name) {
    aw_root->awar(AWAR_EX_NAME_DST)->write_string(item_name);
}

static GBDATA *mg_get_first_sai_data1(GBDATA*, AW_root*, QUERY_RANGE) {
    return GBT_get_SAI_data(GLOBAL_gb_src);
}
static GBDATA *mg_get_first_sai_data2(GBDATA*, AW_root*, QUERY_RANGE) {
    return GBT_get_SAI_data(GLOBAL_gb_dst);
}

static GBDATA *mg_get_selected_sai1(GBDATA*, AW_root *aw_root) {
    GB_transaction  ta(GLOBAL_gb_src);
    const char     *sai_name = aw_root->awar(AWAR_EX_NAME_SRC)->read_char_pntr();
    return sai_name[0] ? GBT_find_SAI(GLOBAL_gb_src, sai_name) : NULp;
}
static GBDATA *mg_get_selected_sai2(GBDATA*, AW_root *aw_root) {
    GB_transaction  ta(GLOBAL_gb_dst);
    const char     *sai_name = aw_root->awar(AWAR_EX_NAME_DST)->read_char_pntr();
    return sai_name[0] ? GBT_find_SAI(GLOBAL_gb_dst, sai_name) : NULp;
}

static MutableItemSelector MG_SAI_selector[2];

static void mg_initialize_SAI_selectors() {
    static bool initialized = false;
    if (!initialized) {
        MG_SAI_selector[0] = MG_SAI_selector[1] = SAI_get_selector();

        for (int s = 0; s <= 1; ++s) {
            MutableItemSelector& sel = MG_SAI_selector[s];

            sel.update_item_awars        = s ? mg_select_sai2 : mg_select_sai1;
            sel.get_first_item_container = s ? mg_get_first_sai_data2 : mg_get_first_sai_data1;
            sel.get_selected_item = s ? mg_get_selected_sai2 : mg_get_selected_sai1;
        }

        initialized = true;
    }
}


AW_window *MG_create_merge_SAIs_window(AW_root *awr) {
    AW_window_simple *aws = new AW_window_simple;

    mg_initialize_SAI_selectors();

    aws->init(awr, "MERGE_SAI", "MERGE SAI");
    aws->load_xfig("merge/extended.fig");

    aws->at("close");
    aws->callback(AW_POPDOWN);
    aws->create_button("CLOSE", "CLOSE", "C");

    aws->at("help");
    aws->callback(makeHelpCallback("mg_extendeds.hlp"));
    aws->create_button("HELP", "HELP", "H");

    aws->at("ex1");
    awt_create_SAI_selection_list(GLOBAL_gb_src, aws, AWAR_EX_NAME_SRC);
    DbScanner *scanner = DbScanner::create(GLOBAL_gb_src, "merge_sai1", aws, "info1", NULp, NULp, DB_SCANNER, NULp, MG_SAI_selector[0]);
    aws->get_root()->awar(AWAR_EX_NAME_SRC)->add_callback(makeRootCallback(map_extended, scanner, SRC_DB));

    aws->at("ex2");
    awt_create_SAI_selection_list(GLOBAL_gb_dst, aws, AWAR_EX_NAME_DST);
    scanner = DbScanner::create(GLOBAL_gb_dst, "merge_sai2", aws, "info2", NULp, NULp, DB_SCANNER, NULp, MG_SAI_selector[1]);
    aws->get_root()->awar(AWAR_EX_NAME_DST)->add_callback(makeRootCallback(map_extended, scanner, DST_DB));

    aws->button_length(20);

    aws->at("delete1");
    aws->callback(makeWindowCallback(MG_extended_delete_cb, SRC_DB));
    aws->create_button("DELETE_SAI_DB1", "Delete SAI");

    aws->at("delete2");
    aws->callback(makeWindowCallback(MG_extended_delete_cb, DST_DB));
    aws->create_button("DELETE_SAI_DB2", "Delete SAI");

    aws->at("rename1");
    aws->callback(makeWindowCallback(extended_rename_cb, SRC_DB));
    aws->create_button("RENAME_SAI_DB1", "Rename SAI");

    aws->at("rename2");
    aws->callback(makeWindowCallback(extended_rename_cb, DST_DB));
    aws->create_button("RENAME_SAI_DB2", "Rename SAI");

    aws->at("transfer");
    aws->callback(MG_transfer_extended);
    aws->create_button("TRANSFER_SAI", "Transfer SAI");

    aws->button_length(0);
    aws->shadow_width(1);
    aws->at("icon");
    aws->callback(makeHelpCallback("mg_extendeds.hlp"));
    aws->create_button("HELP_MERGE", "#merge/icon.xpm");

    return aws;
}
