#include "common.h"
#include <dirent.h>
#include <libgen.h>

bool gSISearch = false;

const int kCacheMax = 200;
const int kCacheNumberMax = 256;

static string_obj* gInputFileName;
static int gSIScrollTop = 0;
static int gSICursor = 0;

static vector_obj* gCandidate;

#if defined(HAVE_MIGEMO_H)
hash_obj* gRegs;
vector_obj* gRegs2;

void regs_new()
{
    gRegs = hash_new(4096);
    gRegs2 = vector_new(4096);

    char tmp[256];
    for(char c='a'; c<='z'; c++) {
        tmp[0] = c;
        tmp[1] = 0;

        const OnigUChar* p
            = migemo_query(gMigemo, (unsigned char*)tmp);
        if(p == NULL) {
            continue;
        }

        regex_t* reg;
        int r;
        OnigErrorInfo err_info;

        if(gKanjiCode == kUtf8) {
            r = onig_new(&reg, p, p + strlen((char*)p)
                , ONIG_OPTION_DEFAULT
                , ONIG_ENCODING_UTF8
                , ONIG_SYNTAX_DEFAULT, &err_info);
        }
        else if(gKanjiCode == kEucjp) {
            r = onig_new(&reg, p, p + strlen((char*)p)
                , ONIG_OPTION_DEFAULT
                , ONIG_ENCODING_EUC_JP
                , ONIG_SYNTAX_DEFAULT
                , &err_info);
        }
        else if(gKanjiCode == kSjis) {
            r = onig_new(&reg, p, p + strlen((char*)p)
                , ONIG_OPTION_DEFAULT
                , ONIG_ENCODING_SJIS
                , ONIG_SYNTAX_DEFAULT
                , &err_info);
        }

        if(r == ONIG_NORMAL) {
            hash_put(gRegs, tmp, reg);
            vector_add(gRegs2, reg);
        }

        migemo_release(gMigemo, (unsigned char*) p);
    }

    for(char c='a'; c<='z'; c++) {
        for(char d='a'; d<='z'; d++) {
            tmp[0] = c;
            tmp[1] = d;
            tmp[2] = 0;

            const OnigUChar* p
                = migemo_query(gMigemo, (unsigned char*)tmp);
            if(p == NULL) {
                continue;
            }

            regex_t* reg;
            int r;
            OnigErrorInfo err_info;

            if(gKanjiCode == kUtf8) {
                r = onig_new(&reg, p, p + strlen((char*)p)
                    , ONIG_OPTION_DEFAULT
                    , ONIG_ENCODING_UTF8
                    , ONIG_SYNTAX_DEFAULT, &err_info);
            }
            else if(gKanjiCode == kEucjp) {
                r = onig_new(&reg, p, p + strlen((char*)p)
                    , ONIG_OPTION_DEFAULT
                    , ONIG_ENCODING_EUC_JP
                    , ONIG_SYNTAX_DEFAULT
                    , &err_info);
            }
            else if(gKanjiCode == kSjis) {
                r = onig_new(&reg, p, p + strlen((char*)p)
                    , ONIG_OPTION_DEFAULT
                    , ONIG_ENCODING_SJIS
                    , ONIG_SYNTAX_DEFAULT
                    , &err_info);
            }

            if(r == ONIG_NORMAL) {
                hash_put(gRegs, tmp, reg);
                vector_add(gRegs2, reg);
            }

            migemo_release(gMigemo, (unsigned char*) p);
        }
    }

    for(char c='a'; c<='z'; c++) {
        for(char d='a'; d<='z'; d++) {
            for(char e='a'; e<='z'; e++) {
                tmp[0] = c;
                tmp[1] = d;
                tmp[2] = e;
                tmp[3] = 0;

                const OnigUChar* p
                    = migemo_query(gMigemo, (unsigned char*)tmp);
                if(p == NULL) {
                    continue;
                }

                regex_t* reg;
                int r;
                OnigErrorInfo err_info;

                if(gKanjiCode == kUtf8) {
                    r = onig_new(&reg, p, p + strlen((char*)p)
                        , ONIG_OPTION_DEFAULT
                        , ONIG_ENCODING_UTF8
                        , ONIG_SYNTAX_DEFAULT, &err_info);
                }
                else if(gKanjiCode == kEucjp) {
                    r = onig_new(&reg, p, p + strlen((char*)p)
                        , ONIG_OPTION_DEFAULT
                        , ONIG_ENCODING_EUC_JP
                        , ONIG_SYNTAX_DEFAULT
                        , &err_info);
                }
                else if(gKanjiCode == kSjis) {
                    r = onig_new(&reg, p, p + strlen((char*)p)
                        , ONIG_OPTION_DEFAULT
                        , ONIG_ENCODING_SJIS
                        , ONIG_SYNTAX_DEFAULT
                        , &err_info);
                }

                if(r == ONIG_NORMAL) {
                    hash_put(gRegs, tmp, reg);
                    vector_add(gRegs2, reg);
                }

                migemo_release(gMigemo, (unsigned char*) p);
            }
        }
    }
}

void regs_release()
{
    hash_delete(gRegs);
    for(int i=0; i<vector_size(gRegs2); i++) {
        onig_free((regex_t*)vector_item(gRegs2, i));
    }
    vector_delete(gRegs2);
}

#endif



bool sisearch_cache_exist()
{
    return access("/tmp/mfiler2", X_OK) == 0;
}

static inline bool is_isearch_char(int key)
{
    return key == 9 || (key >= ' ' && key <= '~')
                && key != '\\';
//                && key != '/'
//                && key != '~'
//                && key != ' '
//                && key != '?';
}

void sisearch_init()
{
    gInputFileName = string_new("");
    gCandidate = vector_new(10);
}

void sisearch_final()
{
    string_delete(gInputFileName);

    for(int i=0; i<vector_size(gCandidate); i++) {
        delete (char*)vector_item(gCandidate, i);
    }
    vector_delete(gCandidate);
}

void sisearch_start()
{
    gSIScrollTop = 0;
    gSICursor = 0;
}

static void get_cache(char* root)
{
    VALUE array = rb_eval_string("$sisearch_except_dir");

    Check_Type(array, T_ARRAY);

    for(int i=0; i<RARRAY(array)->len; i++) {
        if(strcmp(root, RSTRING(rb_ary_entry(array, i))->ptr) == 0) {
            return;
        }
    }

    DIR* dir = opendir(root);

    if(dir) {
        struct dirent* dirent_;
        
        while(dirent_ = readdir(dir)) {
            if(strcmp(dirent_->d_name, ".") != 0 
                && strcmp(dirent_->d_name, "..") != 0)
            {
                struct stat stat_;

                char path[PATH_MAX];
                sprintf(path, "%s%s", root, dirent_->d_name);
                lstat(path, &stat_);

                if(S_ISDIR(stat_.st_mode)) {
                    if(is_all_ascii(dirent_->d_name)) {
                        int l = strlen(dirent_->d_name);
                        
                        if(l < 4) {
                            for(int i= 1; i<l+1; i++) {
                                char tmp[PATH_MAX];
                                memcpy(tmp, dirent_->d_name, i);
                                tmp[i] = 0;

                                char fpath[PATH_MAX];
                                sprintf(fpath
                                    , "/tmp/mfiler2/mfiler2_sisearch_cache_%s"
                                                , tmp);

                                FILE* f = fopen(fpath, "a");
                                char tmp2[PATH_MAX];
                                sprintf(tmp2, "%s\n", path);
                                fprintf(f, tmp2);
                                fclose(f);
                            }
                        }
                        else {
                            for(int i= 1; i<4; i++) {
                                char tmp[PATH_MAX];
                                memcpy(tmp, dirent_->d_name, i);
                                tmp[i] = 0;

                                char fpath[PATH_MAX];
                                sprintf(fpath
                                    , "/tmp/mfiler2/mfiler2_sisearch_cache_%s"
                                                , tmp);

                                FILE* f = fopen(fpath, "a");
                                char tmp2[PATH_MAX];
                                sprintf(tmp2, "%s\n", path);
                                fprintf(f, tmp2);
                                fclose(f);
                            }
                        }
                    }
#if defined(HAVE_MIGEMO_H)
                    else {
                        char fname[PATH_MAX];
                        convert_fname(dirent_->d_name, fname, PATH_MAX);

                        OnigUChar* str = (OnigUChar*)fname;

                        char tmp[256];
                        for(char c='a'; c<='z'; c++) {
                            tmp[0] = c;
                            tmp[1] = 0;

                            OnigRegion* region = onig_region_new();
                            regex_t* reg = (regex_t*)hash_item(gRegs, tmp);

                            int r = onig_search(reg
                                        , str, str + strlen((char*)str)
                                        , str, str + strlen((char*)str)
                                        , region, ONIG_OPTION_NONE);
                            
                            onig_region_free(region, 1);

                            if(r == 0) {
                                char fpath[PATH_MAX];
                                sprintf(fpath
                                    , "/tmp/mfiler2/mfiler2_sisearch_cache_%s"
                                                , tmp);

                                FILE* f = fopen(fpath, "a");
                                char tmp2[PATH_MAX];
                                sprintf(tmp2, "%s\n", path);
                                fprintf(f, tmp2);
                                fclose(f);
                            }
                        }
                        /*
                        for(char c='a'; c<='z'; c++) {
                            for(char d='a'; d<='z'; d++) {
                                tmp[0] = c;
                                tmp[1] = d;
                                tmp[2] = 0;

                                OnigRegion* region = onig_region_new();
                                regex_t* reg = (regex_t*)hash_item(gRegs, tmp);

                                int r = onig_search(reg
                                            , str, str + strlen((char*)str)
                                            , str, str + strlen((char*)str)
                                            , region, ONIG_OPTION_NONE);
                                
                                onig_region_free(region, 1);

                                if(r == 0) {
                                    char fpath[PATH_MAX];
                                    sprintf(fpath
                                     , "/tmp/mfiler2/mfiler2_sisearch_cache_%s"
                                     , tmp);

                                    FILE* f = fopen(fpath, "a");
                                    char tmp2[PATH_MAX];
                                    sprintf(tmp2, "%s\n", path);
                                    fprintf(f, tmp2);
                                    fclose(f);
                                }
                            }
                        }
                        for(char c='a'; c<='z'; c++) {
                            for(char d='a'; d<='z'; d++) {
                                for(char e='a'; e<='z'; e++) {
                                    tmp[0] = c;
                                    tmp[1] = d;
                                    tmp[2] = e;
                                    tmp[3] = 0;

                                    OnigRegion* region = onig_region_new();
                                    regex_t* reg = (regex_t*)hash_item(gRegs
                                                                , tmp);

                                    int r = onig_search(reg
                                                , str, str + strlen((char*)str)
                                                , str, str + strlen((char*)str)
                                                , region, ONIG_OPTION_NONE);
                                    
                                    onig_region_free(region, 1);

                                    if(r == 0) {
                                        char fpath[PATH_MAX];
                                        sprintf(fpath
                                      , "/tmp/mfiler2/mfiler2_sisearch_cache_%s"
                                                        , tmp);

                                        FILE* f = fopen(fpath, "a");
                                        char tmp2[PATH_MAX];
                                        sprintf(tmp2, "%s\n", path);
                                        fprintf(f, tmp2);
                                        fclose(f);
                                    }
                                }
                            }
                        }
                        */
                    }

                    char path2[PATH_MAX];
                    sprintf(path2, "%s/", path);
                    msg_nonstop("entering %s", path2);
                    get_cache(path2);
                }
                else {
                    if(is_all_ascii(dirent_->d_name)) {
                        int l = strlen(dirent_->d_name);
                        
                        if(l < 4) {
                            for(int i= 1; i<l+1; i++) {
                                char tmp[PATH_MAX];
                                memcpy(tmp, dirent_->d_name, i);
                                tmp[i] = 0;

                                char fpath[PATH_MAX];
                                sprintf(fpath
                                    , "/tmp/mfiler2/mfiler2_sisearch_cache_%s"
                                                , tmp);

                                FILE* f = fopen(fpath, "a");
                                char tmp2[PATH_MAX];
                                sprintf(tmp2, "%s\n", path);
                                fprintf(f, tmp2);
                                fclose(f);
                            }
                        }
                        else {
                            for(int i= 1; i<4; i++) {
                                char tmp[PATH_MAX];
                                memcpy(tmp, dirent_->d_name, i);
                                tmp[i] = 0;

                                char fpath[PATH_MAX];
                                sprintf(fpath
                                    , "/tmp/mfiler2/mfiler2_sisearch_cache_%s"
                                                , tmp);

                                FILE* f = fopen(fpath, "a");
                                char tmp2[PATH_MAX];
                                sprintf(tmp2, "%s\n", path);
                                fprintf(f, tmp2);
                                fclose(f);
                            }
                        }
                    }
#if defined(HAVE_MIGEMO_H)
                    else {
                        char fname[PATH_MAX];
                        convert_fname(dirent_->d_name, fname, PATH_MAX);

                        OnigUChar* str = (OnigUChar*)fname;

                        char tmp[256];
                        for(char c='a'; c<='z'; c++) {
                            tmp[0] = c;
                            tmp[1] = 0;

                            OnigRegion* region = onig_region_new();
                            regex_t* reg = (regex_t*)hash_item(gRegs, tmp);

                            int r = onig_search(reg
                                        , str, str + strlen((char*)str)
                                        , str, str + strlen((char*)str)
                                        , region, ONIG_OPTION_NONE);
                            
                            onig_region_free(region, 1);

                            if(r == 0) {
                                char fpath[PATH_MAX];
                                sprintf(fpath
                                    , "/tmp/mfiler2/mfiler2_sisearch_cache_%s"
                                                , tmp);

                                FILE* f = fopen(fpath, "a");
                                char tmp2[PATH_MAX];
                                sprintf(tmp2, "%s\n", path);
                                fprintf(f, tmp2);
                                fclose(f);
                            }
                        }
                        /*
                        for(char c='a'; c<='z'; c++) {
                            for(char d='a'; d<='z'; d++) {
                                tmp[0] = c;
                                tmp[1] = d;
                                tmp[2] = 0;

                                OnigRegion* region = onig_region_new();
                                regex_t* reg = (regex_t*)hash_item(gRegs, tmp);

                                int r = onig_search(reg
                                            , str, str + strlen((char*)str)
                                            , str, str + strlen((char*)str)
                                            , region, ONIG_OPTION_NONE);
                                
                                onig_region_free(region, 1);

                                if(r == 0) {
                                    char fpath[PATH_MAX];
                                    sprintf(fpath
                                     , "/tmp/mfiler2/mfiler2_sisearch_cache_%s"
                                     , tmp);

                                    FILE* f = fopen(fpath, "a");
                                    char tmp2[PATH_MAX];
                                    sprintf(tmp2, "%s\n", path);
                                    fprintf(f, tmp2);
                                    fclose(f);
                                }
                            }
                        }
                        for(char c='a'; c<='z'; c++) {
                            for(char d='a'; d<='z'; d++) {
                                for(char e='a'; e<='z'; e++) {
                                    tmp[0] = c;
                                    tmp[1] = d;
                                    tmp[2] = e;
                                    tmp[3] = 0;

                                    OnigRegion* region = onig_region_new();
                                    regex_t* reg = (regex_t*)hash_item(gRegs
                                                                , tmp);

                                    int r = onig_search(reg
                                                , str, str + strlen((char*)str)
                                                , str, str + strlen((char*)str)
                                                , region, ONIG_OPTION_NONE);
                                    
                                    onig_region_free(region, 1);

                                    if(r == 0) {
                                        char fpath[PATH_MAX];
                                        sprintf(fpath
                                      , "/tmp/mfiler2/mfiler2_sisearch_cache_%s"
                                                        , tmp);

                                        FILE* f = fopen(fpath, "a");
                                        char tmp2[PATH_MAX];
                                        sprintf(tmp2, "%s\n", path);
                                        fprintf(f, tmp2);
                                        fclose(f);
                                    }
                                }
                            }
                        }
                        */
                    }
#endif
                }
            }
        }

        closedir(dir);
    }

//cache_check();

}

BOOL sort_path(void* left, void* right)
{ 
    char* l = (char*) left;
    char* r = (char*) right;

    char* tmp = strdup(l);
    char* l2 = basename(tmp);

    char* tmp2 = strdup(r);
    char* r2 = basename(tmp2);

    if(strcmp(l2, r2) == 0) {
        if(strlen(l) < strlen(r)) {
            free(tmp);
            free(tmp2);
            return TRUE;
        }
        else {
            free(tmp);
            free(tmp2);
            return FALSE;
        }
    }
    else if(strcmp(l2, r2) < 0) {
        free(tmp);
        free(tmp2);
        return TRUE;
    }
    else {
        free(tmp);
        free(tmp2);
        return FALSE;
    }
}

void sort_cache()
{
    msg_nonstop("sorting cache...");
    DIR* dir = opendir("/tmp/mfiler2");

    if(dir) {
        struct dirent* dirent_;

        while(dirent_ = readdir(dir)) {
            if(strcmp(dirent_->d_name, ".") != 0 
                && strcmp(dirent_->d_name, "..") != 0)
            {
                char tmp[PATH_MAX];
                sprintf(tmp, "/tmp/mfiler2/%s", dirent_->d_name);

                vector_obj* v = vector_new(10);

                FILE* f = fopen(tmp, "r");
                if(f == NULL) {
                    fprintf(stderr, "\nfopen\n");
                    exit(1);
                }

                char path[PATH_MAX];
                while(fgets(path, PATH_MAX, f)) {
                    path[strlen(path)-1] = 0;
                    vector_add(v, strdup(path));
                }

                fclose(f);

                vector_sort(v, sort_path);
                FILE* f2 = fopen(tmp, "w");
                if(f2 == NULL) {
                    fprintf(stderr, "\nfopen\n");
                    exit(1);
                }

                for(int i=0; i<vector_size(v); i++) {
                    char* path = (char*)vector_item(v, i);
                    fprintf(f2, "%s\n", path);
                }

                fclose(f2);

                for(int i=0; i<vector_size(v); i++) {
                    free(vector_item(v, i));
                }
                vector_delete(v);
            }
        }

        closedir(dir);
    }
}

void sisearch_get_cache()
{
#if defined(HAVE_MIGEMO_H)
    msg_nonstop("preparing for migemo dictionary...");
    regs_new();
#endif

    system("rm -Rf /tmp/mfiler2");
    system("mkdir /tmp/mfiler2");

    get_cache("/home/minato/");
    sort_cache();

#if defined(HAVE_MIGEMO_H)
    regs_release();
#endif
}

void cache_append_head(char* fpath, char* path)
{
    vector_obj* v = vector_new(10);
    vector_add(v, strdup(path));

    FILE* f = fopen(fpath, "r");
    if(f == NULL) {
        perror("fopen");
    }
    char path2[PATH_MAX];
    while(fgets(path2, PATH_MAX, f)) {
        path2[strlen(path2)-1] = 0;
        if(strcmp(path, path2) != 0) {
            vector_add(v, strdup(path2));
        }
    }
    fclose(f);

    FILE* f2 = fopen(fpath, "w");
    if(f2 == NULL) {
        perror("fopen2");
    }
    for(int i=0; i<vector_size(v); i++) {
        fprintf(f2, "%s\n", vector_item(v, i));
    }
    fclose(f2);

    for(int i=0; i<vector_size(v); i++) {
        free(vector_item(v, i));
    }
    vector_delete(v);
}

void candidate_refresh()
{
    for(int i=0; i<vector_size(gCandidate); i++) {
        delete (char*)vector_item(gCandidate, i);
    }
    vector_delete(gCandidate);

    char* p = string_c_str(gInputFileName);
    char tmp[256];
    if(strlen(p) < 4) {
        strcpy(tmp, p);

        gCandidate = vector_new(10);
        char path[PATH_MAX];
        sprintf(path, "/tmp/mfiler2/mfiler2_sisearch_cache_%s", tmp);
        FILE* f = fopen(path, "r");
        if(f) {
            while(fgets(path, PATH_MAX, f)) {
                path[strlen(path)-1] = 0;

                char* fname = strdup(basename(path));
                if(vector_size(gCandidate) < 256 
                    || strlen(fname) == strlen(p)) 
                {
                    vector_add(gCandidate, strdup(path));
                }
                free(fname);
            }
            fclose(f);
        }
    }
    else {
        memcpy(tmp, p, 3);
        tmp[3] = 0;

        gCandidate = vector_new(10);
        char path[PATH_MAX];
        sprintf(path, "/tmp/mfiler2/mfiler2_sisearch_cache_%s", tmp);
        FILE* f = fopen(path, "r");
        if(f) {
            while(fgets(path, PATH_MAX, f)) {
                path[strlen(path)-1] = 0;
                char* fname = strdup(basename(path));

#if !defined(HAVE_MIGEMO_H)
                if(mystrcasestr(fname, p) == fname) {
                    if(vector_size(gCandidate) < 256
                        || strlen(fname) == strlen(p)) 
                    {
                        vector_add(gCandidate, strdup(path));
                    }
                }
#else
                if(is_all_ascii(fname)) {
                    if(mystrcasestr(fname, p) == fname) {
                        if(vector_size(gCandidate) < 256
                            || strlen(fname) == strlen(p)) 
                        {
                            vector_add(gCandidate, strdup(path));
                        }
                    }
                }
                else {
                    const OnigUChar* p2
                        = migemo_query(gMigemo, (unsigned char*)p);
                    if(p2) {
                        regex_t* reg;
                        int r;
                        OnigErrorInfo err_info;

                        if(gKanjiCode == kUtf8) {
                            r = onig_new(&reg, p2, p2 + strlen((char*)p2)
                                , ONIG_OPTION_DEFAULT
                                , ONIG_ENCODING_UTF8
                                , ONIG_SYNTAX_DEFAULT, &err_info);
                        }
                        else if(gKanjiCode == kEucjp) {
                            r = onig_new(&reg, p2, p2 + strlen((char*)p2)
                                , ONIG_OPTION_DEFAULT
                                , ONIG_ENCODING_EUC_JP
                                , ONIG_SYNTAX_DEFAULT
                                , &err_info);
                        }
                        else if(gKanjiCode == kSjis) {
                            r = onig_new(&reg, p2, p2 + strlen((char*)p2)
                                , ONIG_OPTION_DEFAULT
                                , ONIG_ENCODING_SJIS
                                , ONIG_SYNTAX_DEFAULT
                                , &err_info);
                        }

                        migemo_release(gMigemo, (unsigned char*) p2);

                        if(r == ONIG_NORMAL) {
                            OnigRegion* region = onig_region_new();
                            char fname2[PATH_MAX];
                            convert_fname(fname, fname2, PATH_MAX);
                            OnigUChar* str = (OnigUChar*)fname2;

                            int r = onig_search(reg
                                                , str, str + strlen((char*)str)
                                                , str, str + strlen((char*)str)
                                                , region
                                                , ONIG_OPTION_NONE);

                            if(r == 0 && vector_size(gCandidate) < 256) {
                                vector_add(gCandidate, strdup(path));
                            }

                            onig_region_free(region, 1);

                            onig_free(reg);
                        }
                    }
                }
#endif
                free(fname);
            }
            fclose(f);
        }
    }
}

void sisearch_view()
{
    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();

    for(int i=gSIScrollTop;
        i<vector_size(gCandidate) && i-gSIScrollTop < maxy-3;
        i++) 
    {
        char* item = (char*)vector_item(gCandidate, i);
        char item2[PATH_MAX];
        convert_fname(item, item2, PATH_MAX);

        if(gSICursor == i) {
            mattron(kCAReverse);
            mmvprintw(i-gSIScrollTop, 0, item2);
            mattroff();
        }
        else {
            mmvprintw(i-gSIScrollTop, 0, item2);
        }
    }

    mmvprintw(maxy -2, 0, "//");

    char buf[1024];
    char* str = string_c_str(gInputFileName);
    const int len = strlen(str);
    int i;
    for(i=0; i<maxx-35; i++) {
        if(i<len) {
            buf[i] = str[i];
        }
        else {
            buf[i] = ' ';
        }
    }
    buf[i] = 0;
    mprintw(buf);
}

void sisearch_input(int meta, int key)
{
    if(key == 8 || key == KEY_BACKSPACE || key == KEY_DC) {
        string_erase(gInputFileName, string_length(gInputFileName)-1, 1);
        candidate_refresh();
/*
#if defined(HAVE_MIGEMO_H)
        if(gReg) onig_free(gReg);
        gReg = NULL;
#endif
*/
    }
    else if(key == 14 || key == KEY_DOWN) {
        gSICursor++;
    }
    else if(key == 16 || key == KEY_UP) {
        gSICursor--;
    }
    else if(key == 4 || key == KEY_NPAGE) {    // CTRL-D
        gSICursor+=10;
    }
    else if(key == 21 || key == KEY_PPAGE) {    // CTRL-U
        gSICursor-=10;
    }
    else if(key == 10 || key == 13) {   // CTRL-M, CTRL-J
        char* path = (char*)vector_item(gCandidate, gSICursor);
        if(path) {
            char* tmp = strdup(path);
            char tmp2[PATH_MAX];
            sprintf(tmp2, "%s/", dirname(tmp));
            bool result = true;
            if(strcmp(ActiveDir()->Path(),tmp2) != 0) {
                result = ActiveDir()->Move(tmp2);
            }
            free(tmp);

            if(result) {
                char* str = string_c_str(gInputFileName);

                const int max = strlen(str) < 3 ? strlen(str) : 3;
                for(int i=0; i < max; i++) {
                    char tmp[256];
                    memcpy(tmp, str, i+1);
                    tmp[i+1] = 0;
                    char fpath[PATH_MAX];
                    sprintf(fpath, "/tmp/mfiler2/mfiler2_sisearch_cache_%s"
                                , tmp);
                    cache_append_head(fpath, path);
                }
                char* tmp3 = strdup(path);
                char* fname = basename(tmp3);

                int n = ActiveDir()->FileNum(fname);
                if(n >= 0) {
                    ActiveDir()->MoveCursor(n);
                }
/*
                if(is_all_ascii(fname)) {
                    int n = ActiveDir()->FileNum(fname);
                    if(n >= 0) {
                        ActiveDir()->MoveCursor(n);
                    }
                }
                else {
                    char fname2[PATH_MAX];
                    convert_fname(fname, fname2, PATH_MAX);
                    int n = ActiveDir()->FileNum(fname);

                    if(n >= 0) {
                        ActiveDir()->MoveCursor(n);
                    }
                }
*/
                free(tmp3);
            }
        }

        gSISearch = false;
        string_put(gInputFileName, "");
        vector_clear(gCandidate);
    }
    else if(!is_isearch_char(key)) {
        gSISearch = false;
        string_put(gInputFileName, "");
        vector_clear(gCandidate);

/*
#if defined(HAVE_MIGEMO_H)
        if(gReg) onig_free(gReg);
        gReg = NULL;
#endif
*/
    }
    else {
        if(key == 9)
            string_push_back2(gInputFileName, ' ');
        else
            string_push_back2(gInputFileName, (char)key);

        candidate_refresh();
/*
#if defined(HAVE_MIGEMO_H)
        if(gReg) onig_free(gReg);
        gReg = NULL;
#endif
*/
    }

    while(gSICursor < 0) {
        gSICursor += vector_size(gCandidate);
    }
    while(vector_size(gCandidate) != 0 && gSICursor >= vector_size(gCandidate)) {
        gSICursor -= vector_size(gCandidate);
    }

    const int maxy = mgetmaxy();

    if(gSICursor >= (gSIScrollTop+maxy-3)) {
        gSIScrollTop += gSICursor - (gSIScrollTop+maxy-3) + 1;
    }
    if(gSICursor < gSIScrollTop) {
        gSIScrollTop = gSICursor;
    }

}

