/******************************
 *      Consol Low I/O        *
 ******************************/
#include    <fmc.h>
#include    "oaklib.h"
#include    "config.h"
#include    "edit.h"

#define FSIZE   16      /*  フォント・サイズ  */
#define PIX_BYTE 1      /* 画面モ−ドにより変化 16色=1 256色=1 32K色=2 */

#define FNT_X   8
#define FNT_Y   16

#define LINE_MAX    256


#define OPEN    wp->opened
#undef TOP_X
#undef TOP_Y
#define TOP_X   wp->top_x
#define TOP_Y   wp->top_y
#define BTM_X   wp->btm_x
#define BTM_Y   wp->btm_y
#define SIZ_X   wp->siz_x
#define CUR_X   (*wp->cur_x)
#define _CUR_X  wp->cur_x
#define CUR_POS wp->cur_pos
#define CUT_X   wp->cut_x
#define CUT_POS wp->cut_pos
#define COL_CHR wp->chr_col
#define BAK_CHR wp->chr_bak
#define CUR_COL wp->cur_col
#define COL_BAK wp->bak_col
#define KAN_COD wp->kan_cod
#define EDITBUF wp->editbuf
#define DSP_X   wp->dsp.x
#define DSP_Y   wp->dsp.y
#define DSP_LEN wp->dsp.len
#define DSP_BUF wp->dsp.buf

static  WIND    act_wind = { FALSE,
                            0,0, 0,0, 0, 0,0, -1,-1, 0,15,2,15, 0, 0,0,0 } ;
static  WIND    *wp = &act_wind ;

static  int     bch = 0xFFFF ;
static  u_int   bec = 0 ;

static  int     mos_x = -1, mos_y = -1 ;

static  char    tmpbuf[ 256 ] ;
static  char    kan_mode[ 16 ] = "" ;
static  char    cutbuf[ LINE_MAX ] ;
static  char    ktype[ LINE_MAX ] ;
static  char    linebuf[ LINE_MAX ] ;
static  int     linelen = 0 ;


void    keyflush( void )
{
    while( kbhit( OFF ) != 0 )
        getch() ;
}

#if 1
int     kbhit( int open_check )
{
    static  u_char  matrix[16] ;
    static  u_int   now_break = OFF, now_copy = OFF ;
    static  u_int   last_break = OFF, last_copy = OFF ;

    if( open_check == ON && OPEN != TRUE )
        return 0 ;

    last_break = now_break, last_copy = now_copy ;
    KYB_matrix( (char *)matrix ) ;
    now_break = ( ( matrix[15] ) & 0x10 ) != 0 ? ON : OFF ;
    now_copy  = ( ( matrix[15] ) & 0x20 ) != 0 ? ON : OFF ;
    if( last_break == ON && now_break == OFF )
    {
        bch = 0x8000, bec = 0x7C00 ;
        return 1 ;
    }
    if( last_copy == ON && now_copy == OFF )
    {
        bch = 0x8000, bec = 0x7D00 ;
        return 1 ;
    }

    if( bch != 0xFFFF || ( bch = KAN_read( 1, &bec ) ) != 0xFFFF )
        return 1 ;
    else
        return 0 ;
}
#else
int     kbhit( int open_check )
{
    if( open_check == ON && OPEN != TRUE )
        return 0 ;

    if( bch != 0xFFFF || ( bch = KAN_read( 1, &bec ) ) != 0xFFFF )
        return 1 ;
    else
        return 0 ;
}
#endif

int     getch( void )
{
    int    ch ;

    do {
        while( kbhit( OFF ) == 0 ) ;
        ch = bch ;  bch = 0xFFFF ;
    } while ( ch == 0 ) ;

    if( ( ch & 0xFF00 ) == 0x8000 )
        ch = 0x8000 | ( bec >> 8 ) ;

    return ch ;
}

void    typecheck( char type[], char buf[], int width )
{
    REGS    int     i ;

    for( i = 0 ; i < width && buf[i] != '\0' ; i ++ )
    {
        if( iskanji( buf[i] ) && iskanji2( buf[i+1] ) )
        {
            type[ i ] = IS_KANJI1 ;
            type[i+1] = IS_KANJI2 ;
            i ++ ;
            continue ;
        }
        type[i] = IS_ANK ;
    }
    type[i] = IS_ANK ;
}


static  void    cur_dsp( int sw )
{
    static  int     pos ;
    static  int     cpos ;
    auto    char    para[8] ;
    auto    int     TOPx = TOP_X ;

    if( ( TOPx % 2 ) == 1 )
        TOPx -- ;

    if( sw == 0 )
    {
        pos = CUR_X * FNT_X + TOPx ;
        if( CUT_X >= 0 )
            cpos = CUT_X * FNT_X + TOPx ;
    }

    EGB_writeMode( egbwork, 0x04 ) ;
    EGB_paintMode( egbwork, 0x22 ) ;
    EGB_color( egbwork, 0, CUR_COL ) ;
    WORD(para+0) = pos ;
    WORD(para+4) = pos + FNT_X - 1 ;
    WORD(para+2) = ( CUT_POS >= 0 ) ? (DSP_Y+7) : (DSP_Y+14) ;
    WORD(para+6) = ( CUT_POS >= 0 ) ? (DSP_Y+8) : (DSP_Y+15) ;
    EGB_rectangle( egbwork, para ) ;

    if( CUT_POS >= 0 && CUT_POS < CUR_POS )
    {
        EGB_color( egbwork, 0, 15 ) ;
        EGB_paintMode( egbwork, 0x22 ) ;
        WORD(para+0) = cpos ;
        WORD(para+2) = DSP_Y ;
        WORD(para+4) = pos - 1 ;
        WORD(para+6) = DSP_Y + 15 ;
        EGB_rectangle( egbwork, para ) ;
    }

    EGB_writeMode( egbwork, 0 ) ;
}


static  void    cflush( void )
{
    cur_dsp( 1 ) ;
    if( DSP_LEN > 0 )
    {
        DSP_X = CUR_POS * FNT_X + TOP_X ;
        wrt( (char *)&linebuf[CUR_POS],writepage, DSP_X,DSP_Y,
                    col_tbl[COL_CHR],col_tbl[BAK_CHR], FSIZE ) ;
        DSP_LEN = 0 ;
    }
    CUR_POS = CUR_X ;
    CUT_POS = CUT_X ;
    cur_dsp( 0 ) ;
}

void    wind_close( void )
{
    if( OPEN != FALSE )
    {
        OPEN = FALSE ;
        MOS_disp( MOS_OFF ) ;
        cflush() ;
        if( CUT_X != -1 )
            cut_paste( FALSE ) ;
        cur_dsp( 1 ) ;
        MOS_disp( MOS_ON ) ;

        strcpy( EDITBUF, linebuf ) ;
    }
}


WIND    *wind_open( int x,int y, int len,int *curpos,
                                    int col, int bak,int cur, char *init )
{
    int     i ;

    if( OPEN != FALSE )
        wind_close() ;

    KYB_clrbuf() ;
    for( i = 0x8001 ; i <= 0x800B ; i ++ )  /*  PF1〜PF11  */
        KYB_asign( 0, i, 1, "1" ) ;
    KYB_asign( 0, 0x801D, 1, "1" ) ;        /*  PF12  */
    KYB_clrbuf() ;

    MOS_disp( MOS_OFF ) ;

    box2( x-2,y-2, x+len*8,y+15+2, 0,0 ) ;

    OPEN = TRUE ;
    TOP_X = x ;
    TOP_Y = y ;
    BTM_X = x + len*8 ;
    BTM_Y = y + 15 ;
    SIZ_X = len + 1 ;
    _CUR_X = curpos ;
    CUT_X = CUT_POS = -1 ;
    CUR_POS = 0 ;
    COL_CHR = col ;
    BAK_CHR = COL_BAK = bak ;
    CUR_COL = cur ;
    KAN_COD = 0 ;
    DSP_X = TOP_X ;
    DSP_Y = TOP_Y ;
    DSP_LEN = 0 ;
    EDITBUF = init ;

    mos_x = mos_y = -1 ;

    if( init == NULL )
    {
        linebuf[0] = '\0' ;
        linelen = 0 ;
        CUR_X = 0 ;
    }
    else
    {
        strcpy( linebuf, init ) ;
        typecheck( ktype, linebuf, LINE_MAX ) ;
        linelen = strlen( init ) ;
        DSP_LEN = 1 ;
        if( CUR_X > linelen )
            CUR_X = linelen ;
        if( ktype[CUR_X] == IS_KANJI2 )
            CUR_X -- ;
    }

    cur_dsp( 0 ) ;
    cflush() ;

    MOS_disp( MOS_ON ) ;

    return wp ;
}

static  int     ins_char( char str[] )
{
    REGS    int     i ;

    if( linelen >= SIZ_X-1 )
        return -1 ;

    for( i = linelen ; i >= 0 ; i -- )
        str[i+1] = str[i] ;
    linelen ++ ;

    return 0 ;
}

static  int    del_char( int pos )
{
    REGS    int     i, len ;

    len = ( ktype[pos] == IS_KANJI1 ) ? 2 : 1 ;

    for( i = pos ; i < linelen ; i ++ )
        linebuf[i] = linebuf[i+len] ;
    if( linelen > 0 )
        linelen -= len ;

    return len ;
}

static  void    chr_out( u_char ch )
{
    if( CUR_X + 1 < SIZ_X )
    {
        if( ins_char( (char *)&linebuf[CUR_X] ) != -1 )
        {
            linebuf[CUR_X ++] = ch ;
            DSP_BUF[DSP_LEN++] = ch ;
            typecheck( ktype, linebuf, LINE_MAX ) ;
            return ;
        }
    }
    putchar( '\x07' ) ; fflush( stdout ) ;
}

static  void    key_del( void )
{
    int     len ;

    if( linelen <= CUR_X )
        return ;
    len = del_char( CUR_X ) ;
    linebuf[linelen] = ' ' ;
    if( len == 2 )
        linebuf[linelen+1] = ' ', linebuf[linelen+2] = '\0' ;
    else
        linebuf[linelen+1] = '\0' ;
    CUR_POS = CUR_X ;
    DSP_LEN = 1 ;
    cflush() ;
    linebuf[linelen] = '\0' ;
    typecheck( ktype, linebuf, LINE_MAX ) ;
}

static  void    key_left( void )
{
    if( CUR_X > 0 )
        CUR_X -- ;
    if( CUR_X > 0 && ktype[CUR_X] == IS_KANJI2 )
        CUR_X -- ;
/*
    if( CUR_X > 1 && ktype[CUR_X-1] == IS_KANJI2 )
        CUR_X -= 2 ;
    else if( CUR_X > 0 )
        CUR_X -- ;
*/
}

static  void    cut_paste( int sw )
{
    int     color ;

    if( sw == TRUE )    /*  開始  */
    {
        wrt( " 範囲指定中 ", writepage, 320,464, COL_0,COL_6, 16 ) ;
        CUT_X = CUR_X ;
    }
    else                /*  終了  */
    {
        color = ( writepage == 0 ) ? 15 : 0 ;

        wrt( "            ",
            writepage, 320,464, col_tbl[color],col_tbl[color], 16 ) ;

        CUT_X = -1 ;
    }
}

static  void    _putch( int ch )
{
    u_char  *p ;
    int     i ;

    if( OPEN == FALSE )     /*  window がオープンしてなければパス  */
        return ;

    if( ( ch & 0xFF00 ) == 0x8000 )   /*  特殊キー  */
    {
        switch( ch )
        {
          case 0x8062:    /*  PF6 : 範囲指定開始  */
            if( CUT_X < 0 )
                cut_paste( TRUE ) ;
            else
                cut_paste( FALSE ) ;
            break ;

          case 0x8063:    /*  PF7 : カット        */
            if( CUT_POS != -1 )
                if( CUT_POS < CUR_POS )             /*  指定されている  */
                {
                    strncpy( cutbuf, &linebuf[CUT_POS], CUR_POS-CUT_POS ) ;
                    cutbuf[CUR_POS-CUT_POS] = '\0' ;
                    cut_paste( FALSE ) ;

                    CUR_X = CUT_POS ;
                    for( i = 0 ; i < kstrlen( (u_char *)cutbuf ) ; i ++ )
                        key_del() ;
                }
                else
                    cut_paste( FALSE ) ;
            break ;

          case 0x8064:    /*  PF8 : コピー        */
            if( CUT_POS != -1 )
            {
                if( CUT_POS < CUR_POS )             /*  指定されている  */
                {
                    strncpy( cutbuf, &linebuf[CUT_POS], CUR_POS-CUT_POS ) ;
                    cutbuf[CUR_POS-CUT_POS] = '\0' ;
                }
                cut_paste( FALSE ) ;
            }
            break ;

          case 0x8065:    /*  PF9 : ペースト      */
            if( CUT_POS != -1 )
            {
                cut_paste( FALSE ) ;
            }
            else if( strlen( cutbuf ) > 0 )
            {
                for( p = (u_char *)cutbuf ; *p != '\0' ; p ++ )
                    putch( *p ) ;
            }
            break ;
        }
        return ;
    }
    else
        ch &= 0xFF ;

    switch( ch )
    {
      case 0x0B:    /*  CTRL-K, HOME  */
        if( ( bec >> 8 ) == 0x4E )  /*  HOME  */
        {
            if( CUR_X > 0 )
                CUR_X = 0 ;
            else
                CUR_X = linelen ;
            cflush() ;
        }
        else                    /*  CTRL-K [行末まで削除] */
        {
            while( CUR_X < linelen )
                key_del() ;
        }
        break ;

      case 0x1D:    /*  左カーソル  */
      case 0x13:    /*  ^S  */
        if( ( bec & 4 ) != 0 )  /*  shift  */
            CUR_X = 0 ;
        else
            key_left() ;
        cflush() ;
        break ;

      case 0x1C:    /*  右カーソル  */
      case 0x04:    /*  ^D  */
        if( ( bec & 4 ) != 0 )  /*  shift  */
            CUR_X = linelen ;
        else
        {
            if( CUR_X < linelen )
                CUR_X ++ ;
            if( CUR_X < linelen && ktype[CUR_X] == IS_KANJI2 )
                CUR_X ++ ;
/*
            if( CUR_X < linelen && iskanji( linebuf[CUR_X] ) )
                CUR_X += 2 ;
            else if( CUR_X < linelen )
                CUR_X ++ ;
*/
        }
        cflush() ;
        break ;

      case 0x08:    /*  BS  */
        if( CUR_X > 0 )
        {
            key_left() ;
            key_del() ;
        }
        break ;

      case 0x15:    /*  CTRL_U [行頭まで削除]  */
        while( CUR_X > 0 )
        {
            key_left() ;
            key_del() ;
        }
        break ;

      case 0x7F:    /*  DEL  */
      case 0x07:    /*  ^G   */
        key_del() ;
        break ;

      default:
        if( KAN_COD != 0 )
        {
            if( iskanji2( ch ) )
            {
                if( CUR_X == ( SIZ_X - 1 ) )
                    chr_out( ' ' ) ;
                chr_out( KAN_COD ) ;
                chr_out( ch ) ;
                KAN_COD = 0 ;
                return ;
            }
            KAN_COD = 0 ;
        }
        if( iskanji( ch ) )
        {
            KAN_COD = ch ;
            return ;
        }
        if( ch >= ' ' )
        {
            chr_out( ch ) ;
            return ;
        }
    }
}

void    putch( int ch )
{
    MOS_disp( MOS_OFF ) ;
    if( ch == 0x1B || ch == 0x0D )
        wind_close() ;
    else
    {
        _putch( ch ) ;
        cflush() ;
    }
    MOS_disp( mos_disp ) ;
}

/*
void    cputs( char *str )
{
    while( *str != '\0' )
        putch( (unsigned char)*(str++) ) ;
}

void    cprintf( char *form,... )
{
    va_list arg ;

    va_start( arg, form ) ;
    vsprintf( tmpbuf, form, arg ) ;
    cputs( tmpbuf ) ;
    va_end( arg ) ;
}
*/


int     lineedit( int *x,int *y, int len,int *curpos,
                    int forcol,int bakcol,int curcol, u_char *buf )
{
    int     ch ;

    mos_ptn( 6 ) ;
    wind_open( *x,*y, len,curpos, forcol,bakcol,curcol, (char *)buf ) ;
    KAN_putsys( 0,0, kan_mode ) ;

    while( 1 )
    {
        ch = getch() ;
        if( ch == 0x05 )    ch = 0x1E ;
        if( ch == 0x18 )    ch = 0x1F ;

        if( ch == 0x1B || ch == '\x0A' || ch == '\x0D' ||
                                ch == '\x1E' || ch == '\x1F' )
            break ;

        MOS_disp( MOS_OFF ) ;
        if( ch != 0xF00 )
            putch( ch ) ;
        cflush() ;
        MOS_disp( MOS_ON ) ;
    }

    wind_close() ;

    strcpy( (char *)buf, linebuf ) ;
    *curpos = CUR_X ;

    if( mos_x != -1 && mos_y != -1 )
        *x = mos_x, *y = mos_y ;

    return ch ;
}

#ifdef SAMPLE
void    main()
{
    auto    char    buf[ 256 ], ch ;

    EGB_init( egbwork, EgbWorkSize ) ;
    EGB_resolution( egbwork, 0, 3 ) ;
    EGB_displayPage( egbwork, 0, 1 ) ;

    strcpy( buf, "Initialize Data 0123456789" ) ;

    while( 1 )
    {
        ch = lineedit( 100,10, 60, 15,8,15, buf ) ;
        if( ch == '\x1B' || ch == '\x0D' )  break ;
        ch = lineedit( 100,34, 60, 15,8,15, buf ) ;
        if( ch == '\x1B' || ch == '\x0D' )  break ;
    }

    wrt( linebuf, writepage, 100,58, COL_15,COL_8, FSIZE ) ;
    while( kbhit( ON ) == 0 ) ;
}
#endif


void    KAN_start( void )
{
    KAN_open( KAN_putstr, KAN_putsys, KAN_putmode ) ;
}

void    KAN_end( void )
{
    KAN_close() ;
}



static  u_short fortbl[] =
{
    0x000F,0x000F,0x000F,0x000F,0x000F,0x000F,0x000F,0x000F,
    0x000F,0x000F,0x000F,0x000F,0x000F,0x000F,0x000F,0x000F,
} ;
static  u_short baktbl[] =
{
    0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
    0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
} ;

static  void    KAN_putstr( int pos, int len, char *str, char *att )
{
    static  int     bak_len = 0 ;
    static  char    *bak_buf[128] = "" ;
    auto    int     i, x, y, n, m ;
    auto    char    *p ;
    auto    char    para[16] ;
    auto    int     TOPx = TOP_X ;

    if( ( TOPx % 2 ) == 1 )
        TOPx -- ;

    MOS_disp( MOS_OFF ) ;

    for( i = 0 ; i < bak_len ; i++ )
    {
        EGB_putBlock( egbwork, 0, bak_buf[i] ) ;
        free( bak_buf[i] ) ;
    }
    cflush() ;
    bak_len = 0 ;
    x = CUR_X ;     y = 0 ;
    if( ( m = len ) > 0 && len == pos )
        m ++ ;

    for( i = 0 ; i < m ; i += n )
    {
        n = ( ( i < len && iskanji( (u_char)*str ) ) ? 2:1 ) ;

#if 0
        if( ( x + n ) > SIZ_X )
#else
        if( ( ( x + n ) * 8 + TOPx ) > 638 )
#endif
        {
            x = 0 ;
            y ++ ;
        }

        if ( (p = (char *)malloc(FNT_X * FNT_Y * n * PIX_BYTE + 14)) == NULL )
            break ;

        DWORD(p+0) = (unsigned int)(p+14) ;
        WORD(p+4) = 0x014 ;                      /* Data Selecter */
        WORD(p+6) = TOPx + x * FNT_X ;
        WORD(p+8) = TOP_Y + y * FNT_Y ;
        WORD(p+10) = WORD(p+6) + n * FNT_X - 1 ;
        WORD(p+12) = WORD(p+8) + FNT_Y - 1 ;
        EGB_getBlock( egbwork, p ) ;
        bak_buf[bak_len++] = p ;

        if( i < len )
        {
            para[0] = *str ;
            if( n == 2 )
                para[1] = *(str+1), para[2] = '\0' ;
            else
                para[1] = '\0' ;
            wrt( para, writepage, WORD(p+6),WORD(p+8),
                col_tbl[fortbl[*att]], col_tbl[baktbl[*att]], FSIZE ) ;
            str += n ;
            att += n ;
        }

        if( i == pos )
        {
            EGB_writeMode( egbwork, MODE_XOR ) ;
            EGB_paintMode( egbwork, 0x022 ) ;
            EGB_color( egbwork, 0, CUR_COL ) ;
            WORD(para+0) = WORD(p+6);
            WORD(para+2) = WORD(p+8);
            WORD(para+4) = WORD(p+10);
            WORD(para+6) = WORD(p+12);
            EGB_rectangle( egbwork, para ) ;
            EGB_writeMode( egbwork, MODE_PSET ) ;
        }
#if 0
        if( ( x += n ) >= SIZ_X )
#else
        x += n ;
        if( ( x * 8 + TOPx ) >= 638 )
#endif
        {
            x = 0 ;
            y ++ ;
        }
    }

    MOS_disp( MOS_ON ) ;
}

static  void    KAN_putsys( int len, char *str, char *att )
{
    static  int     bak_len = 0 ;
    static  char    *bak_buf = "" ;
    auto    int     i, x, y, n ;
    auto    char    *p ;

    MOS_disp( MOS_OFF ) ;

    if( bak_len > 0 )
    {
        EGB_putBlock( egbwork, 0, bak_buf ) ;
        free( bak_buf ) ;
    }

    bak_len = 0 ;
    if( len == 0 )
    {
        MOS_disp( MOS_ON ) ;

        return ;
    }

    if( ( p = bak_buf = 
         (char *)malloc(FNT_X * FNT_Y * len * PIX_BYTE + 14)) == NULL )
    {
        MOS_disp( MOS_ON ) ;
        return ;
    }

    DWORD(p+0) = (u_int)(p+14) ;
    WORD(p+4) = 0x014 ;                  /* Data Selecter */
    WORD(p+6) = x = TOP_X ;
    WORD(p+8) = y = BTM_Y + 8 ;
    WORD(p+10) = x + len * FNT_X - 1 ;
    WORD(p+12) = y + FNT_Y - 1 ;
    EGB_getBlock( egbwork, p ) ;
    bak_len = len ;

    for( i = 0 ; i < len ; i += n )
    {
        n = (iskanji((unsigned char)*str) ? 2:1);

        tmpbuf[0] = *str ;
        tmpbuf[1] = *(str+1) ;
        tmpbuf[2] = '\0' ;

        wrt( tmpbuf, writepage, x,y,
                col_tbl[fortbl[*att]], col_tbl[baktbl[*att]], FSIZE ) ;
        str += n ;
        att += n ;
        x += ( FNT_X * n ) ;
    }

    MOS_disp( MOS_ON ) ;
}

static  void    KAN_putmode( int mode, int shift_status, char *str )
{
#define MODE_X 560
#define MODE_Y 460
    mode = mode, shift_status = shift_status ;  /*  Warnings 回避  */

    MOS_disp( MOS_OFF ) ;

    strcpy( kan_mode, str ) ;
    KAN_dispMode() ;

    MOS_disp( MOS_ON ) ;
}

void    KAN_dispMode( void )        /*  モードを再表示  */
{
    EGB_paintMode( egbwork, 0x22 ) ;
    EGB_color( egbwork, 0, COL_CHR ) ;
    EGB_color( egbwork, 2, COL_BAK ) ;
    WORD(tmpbuf+0) = MODE_X - 2 ;
    WORD(tmpbuf+2) = MODE_Y - 2 ;
    WORD(tmpbuf+4) = MODE_X + 72 + 1 ;
    WORD(tmpbuf+6) = MODE_Y + 16 + 1 ;
    EGB_rectangle( egbwork, tmpbuf ) ;

    wrt( kan_mode, writepage,MODE_X,MODE_Y,
                        col_tbl[COL_CHR],col_tbl[COL_BAK], FSIZE ) ;
}

