/*
    マウス イベント処理ライブラリ

    1990.9.11   Make By ken
*/

#include    <stdio.h>
#include    <stdlib.h>
#include    <egb.h>
#include    <mos.h>
#include    <msdos.cf>
#include    <snd.h>
#include    "tie.h"

#define MAX_EVENT   256
#define MAX_EVT     16

static  int     enable_cancel = TRUE ;
static  int     enable_ground = TRUE ;
static  int     evt_max = 0 ;
static  int     evt_free = ERR ;
static  int     last_node = ERR ;
static  int     max_cancel = 0 ;
static  int     max_ground = 0 ;
static  EVENT   evt_node[ MAX_EVENT ] ;
static  EVT     cancel[ MAX_EVT ] ;
static  EVT     ground[ MAX_EVT ] ;

extern  int     EVT_get_node( void ) ;
extern  void    EVT_free_node( int ) ;
extern  int     EVT_chk( EVENT *, int, int, int ) ;
extern  EVT     *EVT_chk_cancel( int, int ) ;
extern  EVT     *EVT_chk_ground( int, int ) ;

#define padU(x) ( ((x) & 0x01) == 0 ? TRUE : FALSE )
#define padD(x) ( ((x) & 0x02) == 0 ? TRUE : FALSE )
#define padL(x) ( ((x) & 0x04) == 0 ? TRUE : FALSE )
#define padR(x) ( ((x) & 0x08) == 0 ? TRUE : FALSE )
#define padA(x) ( ((x) & 0x10) == 0 ? TRUE : FALSE )
#define padB(x) ( ((x) & 0x20) == 0 ? TRUE : FALSE )


/*  マウスとパッドを区別せず扱う位置情報取得ルーチン  */

/*  マウスとパッドを区別せず扱う位置情報取得ルーチン  */

void    MOS_PAD_rdpos( int *sw, int *x, int *y )
{
    static  int     pad_num = 0 ;
    static  int     count = 0 ;
    auto    int     pad, dt, dx, dy ;

    /*  マウスカーソルの位置を読み込む  */
    MOS_rdpos( sw, x, y ) ;

    /*  パッドによる制御  */
    SND_joy_in_1( 0, &pad ) ;

    if( 0x3F != pad )       /*  どれかON  */
    {
        *sw = ( padB( pad ) ? 2 : 0 ) | ( padA( pad ) ? 1 : 0 ) ;

        if( count ++ >= 10 )
        {
            count = 0 ;

            if( ( dt = pad_num / 5 ) < 1 ) dt = 1 ;
            if( dt > 16 )                  dt = 16 ;

            dx = dy = 0 ;

            if( !padL( pad ) || !padR( pad ) )
                dx = ( padL( pad ) ? (- dt) : ( padR( pad ) ? dt : 0 ) ) ;
            if( !padU( pad ) || !padD( pad ) )
                dy = ( padU( pad ) ? (- dt) : ( padD( pad ) ? dt : 0 ) ) ;

            if( dx != 0 || dy != 0 )
                MOS_setpos( *x += dx, *y += dy ) ;
            pad_num ++ ;
        }
    }
    else
        pad_num = 0 ;
}


/*  イベント待ちループ  */

void    EVT_loop( int min_level, int max_level )
{
    REGS    EVENT   *ep ;
    auto    int     i, sw, x, y ;
    static  int     r_on = FALSE ;

    MOS_PAD_rdpos( &sw, &x, &y ) ;

    /*  右クリックによるキャンセル機能  */
    if( enable_cancel != FALSE )
    {
        if( max_cancel > 0 )
        {
            if( r_on == TRUE && rbtn( sw ) == FALSE )
                EVT_chk_cancel( min_level, max_level ) ;

            r_on = rbtn( sw ) ;
        }
        sw &= 1 ;
    }

    if( last_node != ERR )
    {
        ep = &( evt_node[last_node] ) ;
        if( ep->flg != FALSE &&
                ep->level >= min_level && ep->level <= max_level &&
                EVT_chk( ep, x, y, sw ) != EVT_NON )
            return ;
    }

    last_node = ERR ;

    for( i = 0 ; i < evt_max ; i++ )
    {
        ep = &( evt_node[i] ) ;
        if( ep->flg != FALSE &&
            ep->level >= min_level && ep->level <= max_level &&
            EVT_chk( ep, x, y, sw ) != EVT_NON )
        {
            last_node = i ;
            return ;
        }
    }

    /*  余白のクリックによるイベント  */
    if( enable_ground != FALSE )
    {
        if( max_ground > 0 )
        {
            if( r_on == TRUE && rbtn( sw ) == FALSE )
                EVT_chk_ground( min_level, max_level ) ;
            r_on = rbtn( sw ) ;
        }
    }
}

int     lbtn( int sw )  /*  左ボタンが押されていたら、TRUE  */
{
    return( ( sw & 1 ) != 0 ? TRUE : FALSE ) ;
}
int     rbtn( int sw )  /*  右ボタンが押されていたら、TRUE  */
{
    return( ( sw & 2 ) != 0 ? TRUE : FALSE ) ;
}

void    EVT_control_cancel( int flag )
{
    enable_cancel = flag ;
}

void    EVT_control_ground( int flag )
{
    enable_ground = flag ;
}

static  EVT     *EVT_chk_cancel( int min, int max )
{
    REGS    int     i ;
    REGS    EVT     *cp ;

    for( i = 0 ; i < max_cancel ; i ++ )
    {
        cp = &cancel[i] ;

        if( cp->flg == TRUE && cp->level >= min && cp->level <= max )
        {
            (*cp->proc)() ;
            return cp ;
        }
    }
    return NULL ;
}

static  EVT     *EVT_chk_ground( int min, int max )
{
    REGS    int     i ;
    REGS    EVT     *cp ;

    for( i = 0 ; i < max_ground ; i ++ )
    {
        cp = &ground[i] ;

        if( cp->flg == TRUE && cp->level >= min && cp->level <= max )
        {
            (*cp->proc)() ;
            return cp ;
        }
    }
    return NULL ;
}


/*  イベントの発生をチェック  */

static  int     EVT_chk( REGS EVENT *ep, int x, int y, int sw )
{
    auto    int     on ;

    on = ( x >= ep->x1 && x <= ep->x2 && 
           y >= ep->y1 && y <= ep->y2 ) ? TRUE : FALSE ;

    switch( ep->now )
    {
      case EVT_OFF_MOS:
      case EVT_MOVE_MOS:
      case EVT_DLSEL_MOS:
      case EVT_SELECT_MOS:
        ep->now = EVT_NON ;
        break ;

      case EVT_NON:
        if( on == TRUE )
        {
            ep->now = ( sw != 0 ? EVT_CLIP_MOS:EVT_ON_MOS ) ;
            (*ep->proc)( ep, x, y, sw ) ;
        }
        break ;

      case EVT_ON_MOS:
        if( on == TRUE )
        {
            ep->now = ( sw != 0 ? EVT_CLIP_MOS : EVT_ON_MOS ) ;
            (*ep->proc)( ep, x, y, sw ) ; 
        }
        else
        {
            ep->now = EVT_OFF_MOS ;
            (*ep->proc)( ep, x, y, sw ) ;
        }
        break ;

      case EVT_CLIP_MOS:
        if( on == TRUE )
        {
            if( sw == 0 )   /*  ボタンを離した  */
            {
                ep->now = EVT_SELECT_MOS ;
                (*ep->proc)( ep, x, y, sw ) ;
            }
        }
        else
        {
            ep->now = ( sw != 0 ? EVT_DOLACK_MOS : EVT_MOVE_MOS ) ;
            (*ep->proc)( ep, x, y, sw ) ;
        }
        break ;

      case EVT_DOLACK_MOS:
        if( sw == 0 )       /*  ボタンを離した  */
        {
            ep->now = EVT_DLSEL_MOS ;
            (*ep->proc)( ep, x, y, sw ) ;
        }
        else
        {
            ep->now = EVT_DOLACK_MOS ;
            (*ep->proc)( ep, x, y, sw ) ;
        }
        break ;

      case EVT_REP_MOS:
        if( on == TRUE )
        {
            if( sw == 0 )   /*  ボタンを離した  */
            {
                ep->now = EVT_SELECT_MOS ;
                (*ep->proc)( ep, x, y, sw ) ;
            }
            else
                (*ep->proc)( ep, x, y, sw ) ;
        }
        else
        {
            ep->now = ( sw == 0 ? EVT_DOLACK_MOS : EVT_MOVE_MOS ) ;
            (*ep->proc)( ep, x, y, sw ) ;
        }
        break ;
    }

    return ep->now ;
}

static  int     EVT_get_node( void )
{
    auto    int     no ;

    if( ( no = evt_free ) != ERR )
        evt_free = evt_node[ evt_free ].level ;
    else if( evt_max >= MAX_EVENT )
        return ERR ;
    else
        no = evt_max ++ ;

    return no ;
}

static  void    EVT_free_node( int no )
{
    evt_node[ no ].flg = FALSE ;
    evt_node[ no ].level = evt_free ;
    evt_free = no ;
    if( no == last_node )
        last_node = ERR ;
}

void    EVT_level_free( int level )
{
    auto    int     i ;
    REGS    EVENT   *ep ;
    REGS    EVT     *cp ;

    for( i = 0 ; i < MAX_EVENT ; i ++ )
    {
        ep = &( evt_node[ i ] ) ;
        if( ep->flg != FALSE && ep->level == level )
            EVT_free_node( i ) ;
    }

    for( i = 0 ; i < MAX_EVT ; i ++ )
    {
        cp = &( cancel[ i ] ) ;
        if( cp->flg != FALSE && cp->level == level )
            cp->flg = FALSE ;

        cp = &( ground[ i ] ) ;
        if( cp->flg != FALSE && cp->level == level )
            cp->flg = FALSE ;
    }
}

EVENT   *EVT_set_node( int x1, int y1, int x2, int y2,
                           int level, void (*proc)(), int no, int rep )
{
    auto    int     node ;
    REGS    EVENT   *ep ;

    if( ( node = EVT_get_node() ) == ERR )
        return NULL ;

    ep = &( evt_node[ node ] ) ;
    ep->flg = TRUE ;
    ep->level = level ;
    ep->now = 0 ;
    ep->no = no ;
    ep->x1 = x1 ;
    ep->y1 = y1 ;
    ep->x2 = x2 ;
    ep->y2 = y2 ;
    ep->rep = rep ;
    ep->proc = proc ;

    return ep ;
}

EVT     *EVT_set_cancel( int level, void (*proc)() )
{
    REGS    int     i ;
    auto    EVT     *cp ;

    if( max_cancel < MAX_EVT )
        cp = &cancel[ max_cancel ++ ] ;
    else
    {
        for( i = 0 ; i < MAX_EVT ; i ++ )
            if( cancel[i].flg == FALSE )
            {
                cp = &cancel[ i ] ;
                break ;
            }
        if( i == MAX_EVT )
            return( NULL ) ;
    }

    cp->flg = TRUE ;
    cp->level = level ;
    cp->proc = proc ;

    return cp ;
}

void    EVT_unset_cancel( int level )
{
    REGS    int     i ;
    REGS    EVT     *cp ;

    for( i = 0 ; i < MAX_EVT ; i ++ )
    {
        cp = &( cancel[ i ] ) ;
        if( cp->flg != FALSE && cp->level == level )
            cp->flg = FALSE ;
    }
}

EVT     *EVT_set_ground( int level, void (*proc)() )
{
    REGS    int     i ;
    auto    EVT     *cp ;

    if( max_ground < MAX_EVT )
        cp = &ground[ max_ground ++ ] ;
    else
    {
        for( i = 0 ; i < MAX_EVT ; i ++ )
            if( ground[i].flg == FALSE )
            {
                cp = &ground[ i ] ;
                break ;
            }
        if( i == MAX_EVT )
            return( NULL ) ;
    }

    cp->flg = TRUE ;
    cp->level = level ;
    cp->proc = proc ;

    return cp ;
}

void    EVT_unset_ground( int level )
{
    REGS    int     i ;
    REGS    EVT     *cp ;

    for( i = 0 ; i < MAX_EVT ; i ++ )
    {
        cp = &( ground[ i ] ) ;
        if( cp->flg != FALSE && cp->level == level )
            cp->flg = FALSE ;
    }
}

void    EVT_reset( void )
{
    int     i ;

    evt_max = 0 ;
    evt_free = ERR ;
    last_node = ERR ;
    max_cancel = 0 ;

    for( i = 0 ; i < MAX_EVENT ; i ++ )
    {
        evt_node[ i ].flg = FALSE ;
        evt_node[ i ].level = 0 ;
    }
    for( i = 0 ; i < MAX_EVT ; i ++ )
    {
        cancel[ i ].flg   = ground[ i ].flg   = FALSE ;
        cancel[ i ].level = ground[ i ].level = 0 ;
    }
}
/*

#define XPOS    64
#define YPOS    50
#define XNUM    32
#define YNUM    ((MAX_EVENT/XNUM)+3)
#define XP      16
#define YP      20

void    EVT_print_list( void )
{
    int     i ;
    char    tmp[128] ;

    dsp_box( XPOS-8,YPOS, XPOS+XNUM*XP, YPOS+YP*YNUM, 5,5,5 ) ;
    dsp_box( XPOS-6,YPOS+2, XPOS+XNUM*XP-2, YPOS+YP*YNUM-2, 7,8,5 ) ;

    sprintf( tmp, "MAX_EVENT:%d  evt_max:%3d  evt_free:%3d",
                                        MAX_EVENT, evt_max, evt_free ) ;
    wrt( tmp, writepage, XPOS+32,YPOS+8, COL_15,COL_5, 16 ) ;

    for( i = 0 ; i < MAX_EVENT ; i++ )
        wrt( evt_node[i].flg ? "*" : ".", writepage,
            XPOS+(i%XNUM)*XP,YPOS+YP*2+(i/XNUM)*YP, COL_15,COL_5, 16 ) ;
}
*/
