#include <termios.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <wctype.h>
#ifdef __CYGWIN__
#include <ncurses/term.h>
#include <sys/time.h>
#else
#include <term.h>
#endif

#include "mcurses.h"
#include "mdebug.h"
#include "mvector.h"

#define TERM_SIZE_MAX 512

static struct termios gTtySave;
//static struct mttydata gTtySave2;
static char gBuf[TERM_SIZE_MAX][TERM_SIZE_MAX];
static wchar_t gWBuf[TERM_SIZE_MAX][TERM_SIZE_MAX];
static int gBufAttr[TERM_SIZE_MAX][TERM_SIZE_MAX];
static char gBufBfr[TERM_SIZE_MAX][TERM_SIZE_MAX];
static wchar_t gWBufBfr[TERM_SIZE_MAX][TERM_SIZE_MAX];
static int gBufAttrBfr[TERM_SIZE_MAX][TERM_SIZE_MAX];
static int gX = 0, gY = 0;
static int gRealX = 0, gRealY = 0;
static int gBufAttrNow = 0;
static int gCurses = 0;

struct sKeyMap
{
    int mKey;
    char mKeys[kKeyMapKeysMax];
    int mNum;
};

vector_obj* gKeyMap = NULL;

static int wis_2cols(wchar_t c)
{
    wchar_t buf[256];

    buf[0] = c;
    buf[1] = 0;

    return wcswidth(buf, 10) == 2;
}

void madd_keymap(int key, char keys[kKeyMapKeysMax])
{
    int i;

    struct sKeyMap* keymap = (struct sKeyMap*)MALLOC(sizeof(struct sKeyMap));
    keymap->mKey = key;
    keymap->mNum = -1;
    for(i=0; i<kKeyMapKeysMax; i++) {
        keymap->mKeys[i] = keys[i];

        if(keys[i] == 0 && keymap->mNum == -1) {
            keymap->mNum = i;
        }
    }

    vector_add(gKeyMap, keymap);
}

void mcurses_init()
{
    char keymaps[26][kKeyMapKeysMax] = {
        {27,   '[',   'A',   0,   0,  0, 0,0,0,0},   // KEY_UP
        {27,   '[',   'B',   0,   0,  0, 0,0,0,0},   // KYE_DOWN
        {27,   '[',   'C',   0,   0,  0, 0,0,0,0},   // KEY_RIGHT
        {27,   '[',   'D',   0,   0,  0, 0,0,0,0},   // KEY_LEFT
        {27,   '[',   '2',  '~',  0,  0, 0,0,0,0},   // KEY_IC
        {127,   0,     0,    0,   0,  0, 0,0,0,0},   // KEY_DC
        {27,   'O',   'H',   0,   0,  0, 0,0,0,0},   // KEY_HOME
        {27,   'O',   'F',   0,   0,  0, 0,0,0,0},   // KEY_END
        {27,   '[',   '5',  '~',  0,  0, 0,0,0,0},   // KEY_PPAGE PageUp
        {27,   '[',   '6',  '~',  0,  0, 0,0,0,0},   // KEY_NPAGE PageDown
        {27,   '[',   '1',  '1', '~', 0, 0,0,0,0},   // F1
        {27,   '[',   '1',  '2', '~', 0, 0,0,0,0},   // F2
        {27,   '[',   '1',  '3', '~', 0, 0,0,0,0},   // F3
        {27,   '[',   '1',  '4', '~', 0, 0,0,0,0},   // F4
        {27,   '[',   '1',  '5', '~', 0, 0,0,0,0},   // F5
        {27,   '[',   '1',  '7', '~', 0, 0,0,0,0},   // F6
        {27,   '[',   '1',  '8', '~', 0, 0,0,0,0},   // F7
        {27,   '[',   '1',  '9', '~', 0, 0,0,0,0},   // F8
        {27,   '[',   '2',  '0', '~', 0, 0,0,0,0},   // F9
        {27,   '[',   '2',  '1', '~', 0, 0,0,0,0},   // F10
        {27,   '[',   '2',  '3', '~', 0, 0,0,0,0},   // F11
        {27,   '[',   '2',  '4', '~', 0, 0,0,0,0},    // F12
        {27,   'O',   'A',   0,   0,  0, 0,0,0,0},   // KEY_UP
        {27,   'O',   'B',   0,   0,  0, 0,0,0,0},   // KYE_DOWN
        {27,   'O',   'C',   0,   0,  0, 0,0,0,0},   // KEY_RIGHT
        {27,   'O',   'D',   0,   0,  0, 0,0,0,0}    // KEY_LEFT
    };

    gKeyMap = vector_new(10);

    madd_keymap(KEY_UP, keymaps[0]);
    madd_keymap(KEY_DOWN, keymaps[1]);
    madd_keymap(KEY_RIGHT, keymaps[2]);
    madd_keymap(KEY_LEFT, keymaps[3]);
    madd_keymap(KEY_IC, keymaps[4]);
    madd_keymap(KEY_DC, keymaps[5]);
    madd_keymap(KEY_HOME, keymaps[6]);
    madd_keymap(KEY_END, keymaps[7]);
    madd_keymap(KEY_PPAGE, keymaps[8]);
    madd_keymap(KEY_NPAGE, keymaps[9]);
    madd_keymap(KEY_F(1), keymaps[10]);
    madd_keymap(KEY_F(2), keymaps[11]);
    madd_keymap(KEY_F(3), keymaps[12]);
    madd_keymap(KEY_F(4), keymaps[13]);
    madd_keymap(KEY_F(5), keymaps[14]);
    madd_keymap(KEY_F(6), keymaps[15]);
    madd_keymap(KEY_F(7), keymaps[16]);
    madd_keymap(KEY_F(8), keymaps[17]);
    madd_keymap(KEY_F(9), keymaps[18]);
    madd_keymap(KEY_F(10), keymaps[19]);
    madd_keymap(KEY_F(11), keymaps[20]);
    madd_keymap(KEY_F(12), keymaps[21]);
    madd_keymap(KEY_UP, keymaps[22]);
    madd_keymap(KEY_DOWN, keymaps[23]);
    madd_keymap(KEY_RIGHT, keymaps[24]);
    madd_keymap(KEY_LEFT, keymaps[25]);
}

void mcurses_final()
{
    int i;

    for(i=0; i<vector_size(gKeyMap); i++) {
        FREE(vector_item(gKeyMap, i));
    }
    vector_delete(gKeyMap);
}

void minitscr()
{
    struct termios t;
    int x,y;
    int i, j;
    struct sKeyMap* item;

    if(gCurses == 0) {
        tcgetattr(STDIN_FILENO, &gTtySave);
    }

    gCurses++;
    
    if(setupterm(NULL, STDOUT_FILENO, (int*) 0) == ERR) {
        fprintf(stderr, "invalid TERM setting");
        exit(1);
    }
    
    tcgetattr(STDIN_FILENO, &t);

    //putp(tigetstr("smkx"));

   t.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE);

# if defined(IEXTEN) && !defined(__MINT__)
   t.c_lflag &= ~IEXTEN; 
# endif

/*    
# ifdef ONLCR
   t.c_oflag &= ~ONLCR;
# endif
    t.c_iflag &= ~ICRNL;
*/    
    
/*
#ifdef ECHOPRT
    t.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOCTL | ECHOE| ECHOK | ECHOKE
                         | ECHONL | ECHOPRT);
#else
    t.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOCTL | ECHOE | ECHOK | ECHOKE
                  | ECHONL);
#endif
*/
    t.c_iflag |= IGNBRK;
    t.c_iflag &= ~(IXOFF|IXON);
   
    t.c_cc[VMIN] = 0;
    t.c_cc[VTIME] = 0;
    t.c_cc[VLNEXT] = 0;
    t.c_cc[VDISCARD] = 0;
    tcsetattr(STDIN_FILENO, TCSANOW, &t);


    if(gKanjiCode == kUtf) {
        for(x=0; x<TERM_SIZE_MAX; x++) {
            for(y=0; y<TERM_SIZE_MAX; y++) {
                gWBufBfr[y][x] = 0;
                gBufAttrBfr[y][x] = 0;
            }
        }
    }
    else {
        for(x=0; x<TERM_SIZE_MAX; x++) {
            for(y=0; y<TERM_SIZE_MAX; y++) {
                gBufBfr[y][x] = 0;
                gBufAttrBfr[y][x] = 0;
            }
        }
    }
    mclear();
    
    gRealX = 0;
    gRealY = 0;
    gBufAttrNow = 0;
}

void mendwin()
{
/*
    mmove_immediately(0, 0);
    mclear_immediately();
    mrefresh();
*/    

    gCurses--;
    if(gCurses == 0) {
        tcsetattr(STDIN_FILENO, TCSANOW, &gTtySave);
    }

}

void mclear_immediately()
{
    int x, y;

    putp(tigetstr("clear"));
    
    if(gKanjiCode == kUtf) {
        for(x=0; x<TERM_SIZE_MAX; x++) {
            for(y=0; y<TERM_SIZE_MAX; y++) {
                gWBufBfr[y][x] = 0;
                gBufAttrBfr[y][x] = 0;
            }
        }
    }
    else {
        for(x=0; x<TERM_SIZE_MAX; x++) {
            for(y=0; y<TERM_SIZE_MAX; y++) {
                gBufBfr[y][x] = 0;
                gBufAttrBfr[y][x] = 0;
            }
        }
    }

    gX = 0;
    gY = 0;
}

void mclear_buffer()
{
    int x,y;

    if(gKanjiCode == kUtf) {
        for(x=0; x<TERM_SIZE_MAX; x++) {
            for(y=0; y<TERM_SIZE_MAX; y++) {
                gWBufBfr[y][x] = 0;
                gBufAttrBfr[y][x] = 0;
            }
        }
    }
    else {
        for(x=0; x<TERM_SIZE_MAX; x++) {
            for(y=0; y<TERM_SIZE_MAX; y++) {
                gBufBfr[y][x] = 0;
                gBufAttrBfr[y][x] = 0;
            }
        }
    }

    gX = 0;
    gY = 0;
}

void mreset_terminal()
{
    printf("%cc", 27);
}

void mmove_immediately(int y, int x)
{
    putp(tparm(tigetstr("cup"), y, x));
    
    gRealX = x;
    gRealY = y;
}

void mclear()
{
   char space[1024];
   char space2[1024];
   int x, y;

   const int maxx = mgetmaxx();
   const int maxy = mgetmaxy();
   
   for(x=0; x<maxx; x++) {
      space[x] = ' ';
   }
   space[x] = 0;
 
#ifdef __CYGWIN__
   for(x=0; x<maxx-1; x++) {
      space2[x] = ' ';
   }
   space2[x] = 0;
    
   mattron(0);
   for(y=0; y<maxy-1; y++) {
      mmvprintw(y, 0, space);
   }
   mmvprintw(maxy-1, 0, space2);
#else   
   mattron(0);
   for(y=0; y<maxy; y++) {
      mmvprintw(y, 0, space);
   }
#endif

    gX = 0;
    gY = 0;
}

void mclear_online(int y)
{
    char space[1024];
    int x;

    const int maxx = mgetmaxx();

#ifdef __CYGWIN__
    const int maxy = mgetmaxy();
    
    if(y == maxy-1) {
        for(x=0; x<maxx-1; x++) {
            space[x] = ' ';
        }
    }
    else {   
        for(x=0; x<maxx; x++) {
            space[x] = ' ';
        }
    }
#else
    for(x=0; x<maxx; x++) {
        space[x] = ' ';
    }
#endif    
    space[x] = 0;
    
    mattron(0);
    mmvprintw(y, 0, space);
}

void mmove(int y, int x)
{
    gX = x;
    gY = y;    
}

int mmvprintw(int y, int x, char* str, ...)
{
    char buf[BUFSIZ];
    int i;
    char* p;
    wchar_t wbuf[BUFSIZ];
    wchar_t* wp;

    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();
    
    va_list args;
    va_start(args, str);
    i = vsprintf(buf, str, args);
    va_end(args);
    
    mmove(y, x);

    if(gKanjiCode == kUtf) {
        mbstowcs(wbuf, buf, BUFSIZ);

        wp = wbuf;
        while(*wp) {
            if(wis_2cols(*wp)) {
                gWBuf[gY][gX] = *wp;
                gWBuf[gY][gX+1] = 0;
                gBufAttr[gY][gX] = gBufAttrNow;
                gBufAttr[gY][gX+1] = 0;
                gX+=2;
            }
            else {
                gWBuf[gY][gX] = *wp;
                gBufAttr[gY][gX] = gBufAttrNow;
                gX++;
            }

            if(gX >= maxx) {
                gX = 0;
                gY++;
            }
            wp++;
        }
    }
    else {
        p = buf;
        while(*p) {
            gBuf[gY][gX] = *p;
            gBufAttr[gY][gX] = gBufAttrNow;
            gX++;
            if(gX >= maxx) {
                gX = 0;
                gY++;
            }
            p++;
        }
    }
    
    return i;
}

int mprintw(char* str, ...)
{
    char buf[BUFSIZ];
    wchar_t wbuf[BUFSIZ];
    wchar_t* wp;
    int i;
    char* p;

    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();
    
    va_list args;
    va_start(args, str);
    i = vsprintf(buf, str, args);
    va_end(args);

    if(gKanjiCode == kUtf) {
        mbstowcs(wbuf, buf, BUFSIZ);

        wp = wbuf;
        while(*wp) {
            if(wis_2cols(*wp)) {
                gWBuf[gY][gX] = *wp;
                gWBuf[gY][gX+1] = 0;
                gBufAttr[gY][gX] = gBufAttrNow;
                gBufAttr[gY][gX+1] = 0;
                gX+=2;
            }
            else {
                gWBuf[gY][gX] = *wp;
                gBufAttr[gY][gX] = gBufAttrNow;
                gX++;
            }

            if(gX >= maxx) {
                gX = 0;
                gY++;
            }
            wp++;
        }
    }
    else {
        p = buf;
        while(*p) {
            gBuf[gY][gX] = *p;
            gBufAttr[gY][gX] = gBufAttrNow;
            gX++;
            if(gX >= maxx) {
                gX = 0;
                gY++;
            }
            p++;
        }
    }
    
    return i;
}

int mhas_color()
{
    return tigetstr("setaf") == NULL;
}

void mattron(int attrs)
{
    gBufAttrNow = attrs;
}

void mattroff()
{
    gBufAttrNow = 0;
}

int mgetmaxx()
{
    struct winsize ws;
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);

    return ws.ws_col;
}

int mgetmaxy()
{
    struct winsize ws;
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);

#ifdef __CYGWIN__
    return ws.ws_row-1;
#else
    return ws.ws_row;
#endif
}

void mbox(int y, int x, int width, int height)
{
   char hbar[256];
   int i;
   
   hbar[0] = '+';
   for(i=1; i<width-1; i++) {
      hbar[i] = '-';
   }
   hbar[i] = '+';
   hbar[i+1] = 0;

   mmvprintw(y, x, hbar);
   for(i=0; i<height-2; i++) {
       char hbar2[256];
       
       int j;
       hbar2[0] = '|';
       for(j=1; j<width-1; j++) {
           hbar2[j] = ' ';
       }
       hbar2[j] = '|';
       hbar2[j+1] = 0;

       mmvprintw(y + 1 +i, x, hbar2);

/*
       mmvprintw(y + 1 + i, x, "|");
       mmvprintw(y + 1 + i, x + width-1, "|");
*/
   }
   
   mmvprintw(y + height-1, x, hbar);
}

void mrefresh()
{
    int x, y;
    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();
    char* p;
    
    if(gKanjiCode == kUtf) {
        for(y=0; y<maxy; y++) {
            for(x=0; x<maxx; x++) {
                if(gWBuf[y][x] != gWBufBfr[y][x] 
                    || gBufAttr[y][x] != gBufAttrBfr[y][x]
                    
                    || (wis_2cols(gWBuf[y][x])
                        && (gWBuf[y][x] != gWBufBfr[y][x]
                            || gBufAttr[y][x] != gBufAttrBfr[y][x]
                            || gWBuf[y][x+1] != gWBufBfr[y][x+1]
                            || gBufAttr[y][x+1] != gBufAttrBfr[y][x+1]
                            )))
                {
                    putp(tparm(tigetstr("cup"), y, x));
        
                    if(gBufAttr[y][x] & kCAReverse) putp(tigetstr("rev"));
                    if(gBufAttr[y][x] & kCABold) putp(tigetstr("bold"));
                    if(gBufAttr[y][x] & kCAUnderline) putp(tigetstr("rmul"));
                    if(gBufAttr[y][x] & kCABlack) {
                        p = tigetstr("setaf");
                        if(p) putp(tparm(p, 0, 0));
                    }
                    if(gBufAttr[y][x] & kCARed) {
                        p = tigetstr("setaf");
                        if(p) putp(tparm(p, 1, 0));
                    }        
                    if(gBufAttr[y][x] & kCAGreen) {
                        p = tigetstr("setaf");
                        if(p) putp(tparm(p, 2, 0));
                    }
                    if(gBufAttr[y][x] & kCAYellow) {
                        p = tigetstr("setaf");
                        if(p) putp(tparm(p, 3, 0));
                    }        
                    if(gBufAttr[y][x] & kCABlue) {
                        p = tigetstr("setaf");
                        if(p) putp(tparm(p, 4, 0));
                    }        
                    if(gBufAttr[y][x] & kCAMagenta) {
                        p = tigetstr("setaf");
                        if(p) putp(tparm(p, 5, 0));
                    }        
                    if(gBufAttr[y][x] & kCACyan) {
                        p = tigetstr("setaf");
                        if(p) putp(tparm(p, 6, 0));
                    }        
                    if(gBufAttr[y][x] & kCAWhite) {
                        p = tigetstr("setaf");
                        if(p) putp(tparm(p, 7, 0));
                    }        
                    if(gBufAttr[y][x] & kCABackBlack) {
                        p = tigetstr("setab");
                        if(p) putp(tparm(p, 0, 0));
                    }        
                    if(gBufAttr[y][x] & kCABackRed) {
                        p = tigetstr("setab");
                        if(p) putp(tparm(p, 1, 0));
                    }        
                    if(gBufAttr[y][x] & kCABackGreen) {
                        p = tigetstr("setab");
                        if(p) putp(tparm(p, 2, 0));
                    }        
                    if(gBufAttr[y][x] & kCABackYellow) {
                        p = tigetstr("setab");
                        if(p) putp(tparm(p, 3, 0));
                    }        
                    if(gBufAttr[y][x] & kCABackBlue) {
                        p = tigetstr("setab");
                            if(p) putp(tparm(p, 4, 0));
                    }        
                    if(gBufAttr[y][x] & kCABackMagenta) {
                        p = tigetstr("setab");
                        if(p) putp(tparm(p, 5, 0));
                    }
                    if(gBufAttr[y][x] & kCABackCyan) {
                        p = tigetstr("setab");
                        if(p) putp(tparm(p, 6, 0));
                    }
                    if(gBufAttr[y][x] & kCABackWhite) {
                        p = tigetstr("setab");
                        if(p) putp(tparm(p, 7, 0));
                    }        

#if !defined(__CYGWIN__)
                    putwc(gWBuf[y][x], stdout);
#endif
                
                    if(gBufAttr[y][x]) putp(tigetstr("sgr0"));
                }
                
                if(wis_2cols(gWBuf[y][x])) {
                    x++;
                }
            }
        }
    }
    else {
        for(y=0; y<maxy; y++) {
            for(x=0; x<maxx; x++) {
                if(gBuf[y][x] !=0 
                    && (
                        gBuf[y][x] != gBufBfr[y][x] 
                        || gBufAttr[y][x] != gBufAttrBfr[y][x]
                    
                    || (is_kanji(gBuf[y][x])
                        && (gBuf[y][x] != gBufBfr[y][x]
                            || gBufAttr[y][x] != gBufAttrBfr[y][x]
                            || gBuf[y][x+1] != gBufBfr[y][x+1]
                            || gBufAttr[y][x+1] != gBufAttrBfr[y][x+1]
                            ))))
                {
                    putp(tparm(tigetstr("cup"), y, x));
        
                    if(gBufAttr[y][x] & kCAReverse) putp(tigetstr("rev"));
                    if(gBufAttr[y][x] & kCABold) putp(tigetstr("bold"));
                    if(gBufAttr[y][x] & kCAUnderline) putp(tigetstr("rmul"));
                    if(gBufAttr[y][x] & kCABlack) {
                        p = tigetstr("setaf");
                        if(p) putp(tparm(p, 0, 0));
                    }
                    if(gBufAttr[y][x] & kCARed) {
                        p = tigetstr("setaf");
                        if(p) putp(tparm(p, 1, 0));
                    }        
                    if(gBufAttr[y][x] & kCAGreen) {
                        p = tigetstr("setaf");
                        if(p) putp(tparm(p, 2, 0));
                    }
                    if(gBufAttr[y][x] & kCAYellow) {
                        p = tigetstr("setaf");
                        if(p) putp(tparm(p, 3, 0));
                    }        
                    if(gBufAttr[y][x] & kCABlue) {
                        p = tigetstr("setaf");
                        if(p) putp(tparm(p, 4, 0));
                    }        
                    if(gBufAttr[y][x] & kCAMagenta) {
                        p = tigetstr("setaf");
                        if(p) putp(tparm(p, 5, 0));
                    }        
                    if(gBufAttr[y][x] & kCACyan) {
                        p = tigetstr("setaf");
                        if(p) putp(tparm(p, 6, 0));
                    }        
                    if(gBufAttr[y][x] & kCAWhite) {
                        p = tigetstr("setaf");
                        if(p) putp(tparm(p, 7, 0));
                    }        
                    if(gBufAttr[y][x] & kCABackBlack) {
                        p = tigetstr("setab");
                        if(p) putp(tparm(p, 0, 0));
                    }        
                    if(gBufAttr[y][x] & kCABackRed) {
                        p = tigetstr("setab");
                        if(p) putp(tparm(p, 1, 0));
                    }        
                    if(gBufAttr[y][x] & kCABackGreen) {
                        p = tigetstr("setab");
                        if(p) putp(tparm(p, 2, 0));
                    }        
                    if(gBufAttr[y][x] & kCABackYellow) {
                        p = tigetstr("setab");
                        if(p) putp(tparm(p, 3, 0));
                    }        
                    if(gBufAttr[y][x] & kCABackBlue) {
                        p = tigetstr("setab");
                            if(p) putp(tparm(p, 4, 0));
                    }        
                    if(gBufAttr[y][x] & kCABackMagenta) {
                        p = tigetstr("setab");
                        if(p) putp(tparm(p, 5, 0));
                    }
                    if(gBufAttr[y][x] & kCABackCyan) {
                        p = tigetstr("setab");
                        if(p) putp(tparm(p, 6, 0));
                    }
                    if(gBufAttr[y][x] & kCABackWhite) {
                        p = tigetstr("setab");
                        if(p) putp(tparm(p, 7, 0));
                    }        

                    if(is_kanji(gBuf[y][x])) {
                        putchar(gBuf[y][x]);
                        putchar(gBuf[y][x+1]);
                    }
                    else {       
                        putchar(gBuf[y][x]);
                    }
                
                    if(gBufAttr[y][x]) putp(tigetstr("sgr0"));
                }
                
                if(is_kanji(gBuf[y][x])) {
                    x++;
                }
            }
        }
    }
    
    putp(tparm(tigetstr("cup"), gRealY, gRealX));
    
    fflush(stdout);

    if(gKanjiCode == kUtf) {
        for(y=0; y<maxy; y++) {
            for(x=0; x<maxx; x++) {
                gWBufBfr[y][x] = gWBuf[y][x];
                gBufAttrBfr[y][x] = gBufAttr[y][x];
            }
        }    
    }
    else {
        for(y=0; y<maxy; y++) {
            for(x=0; x<maxx; x++) {
                gBufBfr[y][x] = gBuf[y][x];
                gBufAttrBfr[y][x] = gBufAttr[y][x];
            }
        }    
    }
}

static int gKeyBuf[1024];
static int gKeyBufNum = 0;

int mkbuf_exist() 
{
    if(gKeyBufNum > 0) 
        return 1;
    else
        return 0;
}

int mgetch(int* meta)
{
    int i, j;
    int specialkey_check;
    int result;
    char buf[128];
    char tmp[128];
    int n;
    int n2;
    fd_set mask;
    struct timeval tv;
    int on_the_way;
    int match;
    struct sKeyMap* item;
    
static int y = 0;
    
    *meta = 0;
    
    if(gKeyBufNum > 0) {
        while(1) {
            on_the_way = 0;

            /// meta special key ///
            if(gKeyBuf[0] == 27) {
                for(i=0; i<vector_size(gKeyMap); i++) {
                    item = (struct sKeyMap*)vector_item(gKeyMap, i);
                    match = 1;
                        
                    for(j=1; j<gKeyBufNum; j++) {
                        if(gKeyBuf[j] != item->mKeys[j-1]) {
                            match = 0;
                            break;
                        }
                    }
                        
                    if(gKeyBufNum-1 == item->mNum) {
                        match = 0;
                    }
    
                    if(match) {
                        on_the_way = 1;
                        break;
                    }
                }
            }
                
            /// special key ///
            for(i=0; i<vector_size(gKeyMap); i++) {
                item = (struct sKeyMap*)vector_item(gKeyMap, i);
                match = 1;
    
                for(j=0; j<gKeyBufNum; j++) {
                    if(gKeyBuf[j] != item->mKeys[j]) {
                        match = 0;
                        break;
                    }
                }
                    
                if(gKeyBufNum == item->mNum) {
                    match = 0;
                }
    
                if(match) {
                    on_the_way = 1;
                    break;
                }
            }
                
            if(on_the_way) {
                usleep(100000);
    
                if((n2 = read(0, tmp, 10)) < 0) {
                    perror("read");
                    exit(1);
                }
                
                if(n2 != 0)
                    for(i=0; i<n2; i++) gKeyBuf[gKeyBufNum++] = tmp[i];
                else
                    break;
            }
            else
                break;
        }

/*
mmvprintw(y, 10, "gKeyBufNum %d", gKeyBufNum);
for(i=0; i<gKeyBufNum; i++) {
mmvprintw(y,i*5+25, "(%d)", gKeyBuf[i]);
}
y++;
*/

        /// special key - meta ///
        if(gKeyBuf[0] == 27) {
            for(i=0; i<vector_size(gKeyMap); i++) {
                item = (struct sKeyMap*)vector_item(gKeyMap, i);

                specialkey_check = 1;
                    
                if(gKeyBufNum-1 < item->mNum) {
                    specialkey_check = 0;
                }
                else {
                    for(j=0; j<item->mNum; j++) {
                        if(item->mKeys[j] != gKeyBuf[j+1]) {
                            specialkey_check = 0;
                            break;
                        }
                    }
                }
                          
                if(specialkey_check) {
                    memmove(gKeyBuf, gKeyBuf + item->mNum+1,
                            sizeof(int)*(gKeyBufNum-item->mNum-1));
                    gKeyBufNum-=(item->mNum+1);
                    *meta = 1;
                    return item->mKey;
                }
            }
        }
        
        /// special key ///
        for(i=0; i<vector_size(gKeyMap); i++) {
            item = (struct sKeyMap*)vector_item(gKeyMap, i);

            specialkey_check = 1;
                
            if(gKeyBufNum < item->mNum) {
                specialkey_check = 0;
            }
            else {
                for(j=0; j<item->mNum; j++) {
                    if(item->mKeys[j] != gKeyBuf[j]) {
                        specialkey_check = 0;
                        break;
                    }
                }
            }
                      
            if(specialkey_check) {
                memmove(gKeyBuf, gKeyBuf + item->mNum,
                             sizeof(int)*(gKeyBufNum-item->mNum));
                gKeyBufNum-=item->mNum;
                return item->mKey;
            }
        }
    
        if(gKeyBuf[0] == 27 && gKeyBufNum > 1) {
            result = gKeyBuf[1];
            memmove(gKeyBuf, gKeyBuf + 2, sizeof(int)*(gKeyBufNum-2));
            gKeyBufNum-=2;
        
            *meta = 1;
            return result;
        }
        else {
            if(gKeyBufNum == 1) {
                gKeyBufNum--;
                return gKeyBuf[0];
            }
            else {
                result = gKeyBuf[0];
                memmove(gKeyBuf, gKeyBuf + 1, sizeof(int)*(gKeyBufNum-1));
                gKeyBufNum--;
                return result;
            }
        }
    }
    else {
        while(1) {
            n = 0;
            while(n == 0) {
                if((n = read(0, buf, 10)) < 0) {
                    perror("read");
                    exit(1);
                }
            }

            while(1) {
                on_the_way = 0;

                /// meta special key ///
                if(buf[0] == 27) {
                    for(i=0; i<vector_size(gKeyMap); i++) {
                        item = (struct sKeyMap*)vector_item(gKeyMap, i);

                        match = 1;
                    
                        for(j=1; j<n; j++) {
                            if(buf[j] != item->mKeys[j-1]) {
                                match = 0;
                                break;
                            }
                        }
                        
                        if(n-1 == item->mNum) {
                            match = 0;
                        }
    
                        if(match) {
                            on_the_way = 1;
                            break;
                        }
                    }
                }
            

                /// special key ///
                for(i=0; i<vector_size(gKeyMap); i++) {
                    item = (struct sKeyMap*)vector_item(gKeyMap, i);
                    match = 1;
    
                    for(j=0; j<n; j++) {
                        if(buf[j] != item->mKeys[j]) {
                            match = 0;
                            break;
                        }
                    }
                    
                    if(n == item->mNum) {
                        match = 0;
                    }
    
                    if(match) {
                        on_the_way = 1;
                        break;
                    }
                }
                
                if(on_the_way) {
                    usleep(100000);
    
                    if((n2 = read(0, tmp, 10)) < 0) {
                        perror("read");
                        exit(1);
                    }

                    if(n2 != 0)
                        for(i=0; i<n2; i++) buf[n++] = tmp[i];
                    else
                        break;
                }
                else
                    break;
            }

/*
mmvprintw(y, 10, "read1 n %d", n);            
for(i=0; i<n; i++) {
mmvprintw(y, i*5 + 25, "(%d)", buf[i]);
}
mrefresh();
y++;
*/

            /// meta special key ///
            if(buf[0] == 27) {
                for(i=0; i<vector_size(gKeyMap); i++) {
                    item = (struct sKeyMap*)vector_item(gKeyMap, i);
                    specialkey_check = 1;
                    
                    if(n-1 < item->mNum) {
                         specialkey_check = 0;
                    }
                    else {
                        for(j=0; j<item->mNum; j++) {
                            if(item->mKeys[j] != buf[j+1]) {
                                specialkey_check = 0;
                                break;
                            }
                        }
                    }
                          
                    if(specialkey_check) {
                        if(n-1 > item->mNum) {
                            for(j=item->mNum+1; j<n; j++) {
                                gKeyBuf[gKeyBufNum++] = buf[j];
                            }
                        }

                        *meta = 1;
                        return item->mKey;
                    }
                }
            }
            

            /// special key ///
            for(i=0; i<vector_size(gKeyMap); i++) {
                item = (struct sKeyMap*)vector_item(gKeyMap, i);
                specialkey_check = 1;
                
                if(n < item->mNum) {
                    specialkey_check = 0;
                }
                else {
                    for(j=0; j<item->mNum; j++) {
                        if(item->mKeys[j] != buf[j]) {
                            specialkey_check = 0;
                            break;
                        }
                    }
                }
                      
                if(specialkey_check) {
                    if(n > item->mNum) {
                        for(j=item->mNum; j<n; j++) {
                            gKeyBuf[gKeyBufNum++] = buf[j];
                        }
                    }
                    
                    return item->mKey;
                }
            }

            //// other key ///
            if(buf[0] == 27 && n>1) {
                for(i=2; i<n; i++) {
                    gKeyBuf[gKeyBufNum++] = buf[i];
                }
                    
                *meta = 1;
                return buf[1];
            }
            else {
                for(i=1; i<n; i++) {
                    gKeyBuf[gKeyBufNum++] = buf[i];
                }
                    
                return buf[0];
            }
        }
    }
}

enum eKanjiCode gKanjiCode = kUtf;

int is_kanji(unsigned char c)
{
    if(gKanjiCode == kEuc) {
        return c >= 0xA1 && c <= 0xFE;
//        return c >= 161 && c <= 254;
    }
    else if(gKanjiCode == kSjis) {
        return c >= 0x81 && c <= 0x9f || c >= 0xE0 && c <= 0xff;
    }
    else if(gKanjiCode == kUtf) {
        return !(c>=' ' && c<='~');
    }
}

int mis_curses()
{
    return gCurses;
}

int str_termlen(char* mbs)
{
/*
    int i;
    int english_words;
    wchar_t* wcs;
    int all_size, len;
    
    wcs = (wchar_t*)malloc(sizeof(wchar_t)*(strlen(mbs)+1)*5);
    len = strlen(mbs);
    english_words = 0;
    for(i=0; i<len; i++) {
        if(mbs[i] >= ' ' && mbs[i] <= '~') {
            english_words++;
        }
    }
    
    mbstowcs(wcs, mbs, (strlen(mbs)+1)*5);
    
    all_size = wcslen(wcs);

    free(wcs);
    
    return (all_size-english_words)*2 + english_words;
*/
    int result;
    wchar_t* wcs;

    wcs = (wchar_t*)malloc(sizeof(wchar_t)*((strlen(mbs)+1)*5));
    mbstowcs(wcs, mbs, (strlen(mbs)+1)*5);
    result = wcswidth(wcs, wcslen(wcs));
    free(wcs);

    return result;
}

int wcs_termlen(wchar_t* wcs)
{
/*
    int english_words;
    int i;
    int len;
    
    len = wcslen(wcs);
    english_words = 0;
    for(i=0; i<len; i++) {
        if(wcs[i] >= ' ' && wcs[i] <= '~') {
            english_words++;
        }
    }
    
    return (len-english_words)*2 + english_words;
*/
    return wcswidth(wcs, wcslen(wcs));
}

void str_cut(char* mbs, int termsize, char* dest_mbs, int dest_byte)
{
    wchar_t* wcs;
    wchar_t* tmp;
    int i;

    wcs = (wchar_t*)malloc(sizeof(wchar_t)*(strlen(mbs)+1)*5);
    tmp = (wchar_t*)malloc(sizeof(wchar_t)*(strlen(mbs)+1)*5);

    mbstowcs(wcs, mbs, (strlen(mbs)+1)*5);

    for(i=0; i<wcslen(wcs); i++) {
        tmp[i] = wcs[i];
        tmp[i+1] = 0;

        if(wcs_termlen(tmp) > termsize) {
            tmp[i] = 0;
            break;
        }
    }

    wcstombs(dest_mbs, tmp, dest_byte);

    free(wcs);
    free(tmp);
}

void str_cut2(char* mbs, int termsize, char* dest_mbs, int dest_byte)
{
    int i;

    wchar_t* wcs;
    wchar_t* tmp;
    wcs = (wchar_t*)malloc(sizeof(wchar_t)*(strlen(mbs)+1)*5);
    tmp = (wchar_t*)malloc(sizeof(wchar_t)*(strlen(mbs)+1)*5);

    mbstowcs(wcs, mbs, (strlen(mbs)+1)*5);

    i = 0;
    while(1) {
        if(i < wcslen(wcs)) {
            tmp[i] = wcs[i];
            tmp[i+1] = 0;
        }
        else {
            tmp[i] = ' ';
            tmp[i+1] = 0;
        }

        if(wcs_termlen(tmp) > termsize) {
            tmp[i] = 0;

            if(wcs_termlen(tmp) != termsize) {
                tmp[i] = ' ';
                tmp[i+1] = 0;
            }
            break;
        }

        i++;
    }

    wcstombs(dest_mbs, tmp, dest_byte);

    free(wcs);
    free(tmp);
}

void str_cut3(char* mbs, int termsize, char* dest_mbs, int dest_byte)
{
    wchar_t* wcs;
    wchar_t* tmp;
    int i;
    int j;

    wcs = (wchar_t*)malloc(sizeof(wchar_t)*(strlen(mbs)+1)*5);
    tmp = (wchar_t*)malloc(sizeof(wchar_t)*(strlen(mbs)+1)*5);

    if(str_termlen(mbs) <= termsize) {
        str_cut2(mbs, termsize, dest_mbs, dest_byte);
    }
    else {
        mbstowcs(wcs, mbs, (strlen(mbs)+1)*5);

        i = wcslen(wcs)-1;
        j = 0;
        while(1) {
            tmp[j++] = wcs[i--];
            tmp[j] = 0;

            if(wcs_termlen(tmp) > termsize) {
                tmp[j-1] = 0;
                i+=2;

                if(wcs_termlen(tmp) == termsize) {
                    wcscpy(tmp, wcs + i);
                    break;
                }
                else {
                    tmp[0] = ' ';
                    wcscpy(tmp + 1, wcs + i);
                    break;
                }
            }
        }

        wcstombs(dest_mbs, tmp, dest_byte);
    }

    free(wcs);
    free(tmp);
}

int str_utflen(char* mbs)
{
    int result;
    wchar_t* wcs;
    
    wcs = (wchar_t*)malloc(sizeof(wchar_t)*(strlen(mbs)+1)*5);

    mbstowcs(wcs, mbs, (strlen(mbs)+1)*5);

    result = wcslen(wcs);

    free(wcs);

    return result;
}

char* str_utfpos2pointer(char* mbs, int pos)
{
    char* result;
    wchar_t* wcs;
    char* tmp;
    
    if(pos<0) return mbs;
    if(pos >= str_utflen(mbs)) return mbs + strlen(mbs);

    tmp = (char*)malloc(sizeof(char)*(strlen(mbs)+1));
    wcs = (wchar_t*)malloc(sizeof(wchar_t)*(strlen(mbs)+1)*5);

    mbstowcs(wcs, mbs, (strlen(mbs)+1)*5);

    wcs[pos] = 0;

    wcstombs(tmp, wcs, strlen(mbs)+1);

    result = mbs + strlen(tmp);

    free(wcs);
    free(tmp);

    return result;
}

int str_pointer2utfpos(char* mbs, char* point)
{
    char* mbs2;
    int result;

    mbs2 = strdup(mbs);
    *(mbs2 + (point-mbs)) = 0;

    result = str_utflen(mbs2);

    free(mbs2);

    return result;
}

int str_termpos(char* mbs, int utfpos)
{
    char* mbs2;
    int result;
    char* point;

    mbs2 = strdup(mbs);
    point = str_utfpos2pointer(mbs2, utfpos);
    if(point == NULL) {
        if(utfpos < 0) 
            result = -1;
        else
            result = str_termlen(mbs2);
    }
    else {
        *(mbs2 + (point-mbs2)) = 0;
        result = str_termlen(mbs2);
    }

    free(mbs2);

    return result;
}
