/*
 * netball - balls bounce around - like ball.c but TELNET version
 *
 */

#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <rtos.h>
#include <telnetd.h>
#include <string.h>

#define MAXBALLS 400
#define SCALE 3
#define RANDOMNESS 2

#define MAXX ( 79 * SCALE )
#define MAXY ( 24 * SCALE )

typedef struct {
    BYTE color;
    WORD x, y;
    WORD oldx, oldy;
    WORD deltax, deltay;
    thread_x *thread;
} ball_str;

ball_str balls[ MAXBALLS ];
teld_str *tptr = NULL;

void put_on_screen( int x, int y, WORD ch, WORD opt_attr )
{
    char buf[ 64 ];
    static WORD far *screen = 0xb8000000;
    WORD ofs;
    ofs = (y/SCALE) * 80 + (x/SCALE);
    screen[ ofs ] = (WORD)ch | ((WORD)opt_attr)<<8;

    sprintf( buf, "%c[%u;%uH%c", 27,
        (y/SCALE), (x/SCALE), ch );
    teld_write( tptr, buf, strlen( buf ));
    
}


void ball( DWORD num )
{
    ball_str *b;
    int tempx, tempy;

    b = &balls[ num ];
    memset( b, 0, sizeof( ball_str ));
    b->color = (num % 7) + 9;
    b->oldx = b->x = MAXX / 2;
    b->oldy = b->y = MAXY / 2;
    b->deltax = SCALE/2 - (rand() / ( RAND_MAX/SCALE/RANDOMNESS));
    b->deltay = SCALE/2 - (rand() / ( RAND_MAX/SCALE/RANDOMNESS));
    /* for network version, so we can shutdown */
    b->thread = kcurthread;

    do {
        /* get new locaton */
        tempx = b->x + b->deltax;
        if ( (tempx < SCALE) || ( tempx > MAXX )) {
            tempx = b->x;
            b->deltax = -b->deltax;
        }

        tempy = b->y + b->deltay;
        if ( (tempy < SCALE) || ( tempy > MAXY )) {
            tempy = b->y;
            b->deltay = -b->deltay;
        }

        /* erase old and accept new */
        if ( (b->oldy != b->y) || (b->oldx != b->x)) {
            put_on_screen( b->oldx, b->oldy, ' ', 0 );
            b->oldx = b->x;
            b->oldy = b->y;
        }
        b->x = tempx;
        b->y = tempy;

        /* draw the ball */
        put_on_screen( b->x, b->y, 'o', b->color );
        rt_sleep( 10 );
    } while ( 1 );
}

void telnetd_thread( DWORD max )
{
    teld_str *t;
    int temp;
    BYTE ch;

    do {

        t = teld_listen( 23  );
        tptr = t;       /* set global variable */


//        sock_mode( &t->teld_socket, TCP_MODE_NONAGLE );
        /* create balls */
        for ( temp = 0 ; temp < max; ++temp )
            rt_newthread( &ball, temp, 1024, 0, "a ball");

        do {
            ch = teld_getc( t );

            if ( ch == 255 ) break;
            if ( ch != 0 ) putch( ch );
                teld_write( t, &ch, 1 );
        } while ( 1 );

        tptr = NULL;

        /* destroy balls */
        for ( temp = 0 ; temp < max; ++temp )
            kdestroythread( balls[temp].thread );

        teld_close( t );
    } while ( 1 );
}


void help( void )
{
    cprintf("BALL num    where num is in the range 1 to %u\r\n", MAXBALLS);
    cputs("Actual limit is based on how much memory is available\r\n");
    exit( 0 );
}

int main( int argc, char **argv )
{
    DWORD max;
    kdebug = 1;
    rt_init(100);
    sock_init();            /* initialize network */
    rt_timerfreq( 100 );

    if ( argc < 2 ) help();
    max = atoi( argv[1] );
    if ( (max < 0) || (max >= MAXBALLS )) help();

    cputs("starting...waiting for a TELNET connection to display balls\r\n");
    cputs("Press the space bar to exit\r\n");

    rt_newthread( telnetd_thread, max, 4096, 0, "worker" );
    do {
        /* nothing */
        rt_yield();
    } while ( 1 );
}

