/**
 * test-keyboard.c
 *
 * Copyright (c) 2012
 *      libchewing Core Team. See ChangeLog for details.
 *
 * See the file "COPYING" for information on usage and redistribution
 * of this file.
 */

#ifdef HAVE_CONFIG_H
#    include <config.h>
#endif

#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include "chewing.h"
#include "testhelper.h"

static const char *const KEYBOARD_STRING[] = {
    "KB_DEFAULT",
    "KB_HSU",
    "KB_IBM",
    "KB_GIN_YIEH",
    "KB_ET",
    "KB_ET26",
    "KB_DVORAK",
    "KB_DVORAK_HSU",
    "KB_DACHEN_CP26",
    "KB_HANYU_PINYIN",
    "KB_THL_PINYIN",
    "KB_MPS2_PINYIN",
    "KB_CARPALX",
};

static const int KEYBOARD_DEFAULT_TYPE = 0;

FILE *fd;

void test_set_keyboard_type()
{
    ChewingContext *ctx;
    size_t i;
    char *keyboard_string;
    int keyboard_type;

    ctx = chewing_new();
    start_testcase(ctx, fd);

    keyboard_string = chewing_get_KBString(ctx);
    ok(strcmp(keyboard_string, KEYBOARD_STRING[KEYBOARD_DEFAULT_TYPE]) == 0,
       "`%s' shall be `%s'", keyboard_string, KEYBOARD_STRING[KEYBOARD_DEFAULT_TYPE]);
    chewing_free(keyboard_string);
    keyboard_type = chewing_get_KBType(ctx);
    ok(keyboard_type == KEYBOARD_DEFAULT_TYPE, "`%d' shall be `%d'", keyboard_type, KEYBOARD_DEFAULT_TYPE);

    for (i = 0; i < ARRAY_SIZE(KEYBOARD_STRING); ++i) {
        ok(chewing_set_KBType(ctx, i) == 0, "return shall be 0");

        keyboard_string = chewing_get_KBString(ctx);
        ok(strcmp(keyboard_string, KEYBOARD_STRING[i]) == 0, "`%s' shall be `%s'", keyboard_string, KEYBOARD_STRING[i]);
        chewing_free(keyboard_string);
        keyboard_type = chewing_get_KBType(ctx);
        ok(keyboard_type == (int) i, "`%d' shall be `%d'", keyboard_type, (int) i);
    }

    // The invalid KBType will reset KBType to default value.
    ok(chewing_set_KBType(ctx, -1) == -1, "return shall be -1");
    keyboard_type = chewing_get_KBType(ctx);
    ok(keyboard_type == KEYBOARD_DEFAULT_TYPE, "`%d' shall be `%d'", keyboard_type, KEYBOARD_DEFAULT_TYPE);

    ok(chewing_set_KBType(ctx, ARRAY_SIZE(KEYBOARD_STRING) + 1), "return shall be -1");
    keyboard_type = chewing_get_KBType(ctx);
    ok(keyboard_type == KEYBOARD_DEFAULT_TYPE, "`%d' shall be `%d'", keyboard_type, KEYBOARD_DEFAULT_TYPE);

    chewing_delete(ctx);
}

void test_KBStr2Num()
{
    int i;
    int ret;

    start_testcase(NULL, fd);

    for (i = 0; i < (int) ARRAY_SIZE(KEYBOARD_STRING); ++i) {
        // XXX: chewing_KBStr2Num shall accept const char *.
        ret = chewing_KBStr2Num(KEYBOARD_STRING[i]);
        ok(ret == i, "%d shall be %d", ret, i);
    }
}

void test_enumerate_keyboard_type()
{
    ChewingContext *ctx;
    size_t i;
    char *keyboard_string;

    ctx = chewing_new();
    start_testcase(ctx, fd);

    ok(chewing_kbtype_Total(ctx) == ARRAY_SIZE(KEYBOARD_STRING),
       "total keyboard_string type shall be %d", ARRAY_SIZE(KEYBOARD_STRING));

    chewing_kbtype_Enumerate(ctx);
    for (i = 0; i < ARRAY_SIZE(KEYBOARD_STRING); ++i) {
        ok(chewing_kbtype_hasNext(ctx) == 1, "shall have next keyboard_string type");
        keyboard_string = chewing_kbtype_String(ctx);
        ok(strcmp(keyboard_string, KEYBOARD_STRING[i]) == 0, "`%s' shall be `%s'", keyboard_string, KEYBOARD_STRING[i]);
        chewing_free(keyboard_string);
    }
    ok(chewing_kbtype_hasNext(ctx) == 0, "shall not have next keyboard_string type");
    keyboard_string = chewing_kbtype_String(ctx);
    ok(strcmp(keyboard_string, "") == 0, "`%s' shall be `%s'", keyboard_string, "");
    chewing_free(keyboard_string);

    chewing_delete(ctx);
}

void test_hsu_po_to_bo()
{
    // https://github.com/chewing/libchewing/issues/170
    ChewingContext *ctx;

    ctx = chewing_new();
    start_testcase(ctx, fd);

    chewing_set_KBType(ctx, chewing_KBStr2Num("KB_HSU"));

    type_keystroke_by_string(ctx, "p");
    ok_bopomofo_buffer(ctx, "\xE3\x84\x86" /* ㄆ */ );

    type_keystroke_by_string(ctx, "b");
    ok_bopomofo_buffer(ctx, "\xE3\x84\x85" /* ㄅ */ );

    chewing_delete(ctx);
}

void test_hsu()
{
    test_hsu_po_to_bo();
}

void test_et26_po_to_bo()
{
    // https://github.com/chewing/libchewing/issues/170
    ChewingContext *ctx;

    ctx = chewing_new();
    start_testcase(ctx, fd);

    chewing_set_KBType(ctx, chewing_KBStr2Num("KB_ET26"));

    type_keystroke_by_string(ctx, "p");
    ok_bopomofo_buffer(ctx, "\xE3\x84\x86" /* ㄆ */ );

    type_keystroke_by_string(ctx, "b");
    ok_bopomofo_buffer(ctx, "\xE3\x84\x85" /* ㄅ */ );

    chewing_delete(ctx);
}

void test_et26()
{
    test_et26_po_to_bo();
}

int main(int argc, char *argv[])
{
    char *logname;
    int ret;

    putenv("CHEWING_PATH=" CHEWING_DATA_PREFIX);
    putenv("CHEWING_USER_PATH=" TEST_HASH_DIR);

    ret = asprintf(&logname, "%s.log", argv[0]);
    if (ret == -1)
        return -1;
    fd = fopen(logname, "w");
    assert(fd);
    free(logname);

    test_set_keyboard_type();
    test_KBStr2Num();
    test_enumerate_keyboard_type();

    test_hsu();
    test_et26();

    fclose(fd);

    return exit_status();
}
