
#include "rexx.h"

#undef TRUE
#undef FALSE

#include <termios.h>
#include <curses.h>
#include <stdio.h>
#include <assert.h>

#include <sys/ioctl.h>


extern void *module_handle ;


typedef struct cur_window *winptr ;
typedef struct cur_window 
{
   streng *name ;
   WINDOW *win ;
   struct cur_window *prev, *next ;
} cur_window_type ;

winptr first=NULL, last=NULL ;


static WINDOW *getwindow( streng *name ) 
{
   winptr ptr ;
   
   for (ptr=first; ptr; ptr=ptr->next )
      if (!Str_cmp(ptr->name, name))
         break ;

   if (!ptr)
   {
/*      fprintf( stderr, "Curses: Unknown window name: %s\n", name->value) ; */
      return NULL ;
   }
   return ptr->win ;
}


static void dropwindows()
{
   winptr ptr, nptr ;
 
   for (ptr=first; ptr; ptr=nptr)
   {
      nptr = ptr->next ;
      Free( ptr->name ) ;
      Free( ptr ) ;
   }
}

static void addwindow( WINDOW *win, streng *name ) 
{
   winptr ptr ;

   ptr = Malloc( sizeof(struct cur_window) ) ;
   ptr->name = name ;
   ptr->win = win ;
   ptr->next = NULL ;
   ptr->prev = last ;

   if (last)
      last->prev->next = last = ptr ;

   if (!first)
      first = ptr ;
}


/* here */
/*====== Here come the real interface functions to curses ======*/

/*====== Initiate and terminate ================================*/

streng *cur_initscr( paramboxptr parms )
{ 
   checkparam( parms, 0, 0 ) ;
   initscr() ;

   addwindow( stdscr, Str_cre("strscr")) ;
   addwindow( curscr, Str_cre("curscr")) ;
   return nullstringptr() ;
}

streng *cur_endwin( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   dropwindows() ;
   endwin() ;
   return nullstringptr() ;
}


/*====== Cursor movements ======================================*/
   
streng *cur_move( paramboxptr parms )
{
   int x, y ;

   checkparam( parms, 2, 2 ) ;
   y = atozpos( parms->value ) ;
   x = atozpos( parms->next->value ) ;

   move( y, x ) ;
   return nullstringptr() ;
}


streng *cur_getyx( paramboxptr parms ) 
{
   WINDOW *wptr ;
   int x, y ;
   streng *result ;

   checkparam( parms, 3, 3 )  ;
   wptr = getwindow( parms->value ) ;

   getyx( wptr, y, x ) ;
   result = Str_make( 2*5 + 1 ) ;
   sprintf( result->value, "%d %d", y, x ) ;
   result->len = strlen( result->value ) ;
   
   return result ;
}


streng *cur_inch( paramboxptr parms ) 
{
   streng *ch ;

   checkparam( parms, 0, 0 ) ;
   ch = Str_make( 1 ) ;
   ch->value[0] = inch() ;
   ch->len = 1 ;

   return ch ;
}


streng *cur_leaveok( paramboxptr parms ) 
{
   WINDOW *pwin ;
   int flag ;

   checkparam( parms, 2, 2 ) ;

   pwin = getwindow( parms->value ) ;
   flag = atozpos( parms->next->value ) ;
   if (flag>1)
      exiterror( ERR_INCORRECT_CALL ) ;

   leaveok( pwin, flag ) ;
   return nullstringptr() ;
}   
   


streng *cur_addch( paramboxptr parms )
{
   checkparam( parms, 1, 1 ) ;
   addch( getonechar( parms->value )) ;
   return nullstringptr() ;
}
 

streng *cur_addstr( paramboxptr parms )
{
   int i, stop ;
   char *ptr ;

   checkparam( parms, 1, 1 ) ;  
   stop = Str_len(parms->value) ;
   ptr = parms->value->value ;

   for (i=0; i<stop; i++) 
      addch( parms->value->value[i] ) ;
   return nullstringptr() ;
}


streng *cur_printw( paramboxptr parms ) 
{
   return nullstringptr() ;
}


streng *cur_insch( paramboxptr parms )
{
   checkparam( parms, 1, 1 ) ;
   insch( getonechar( parms->value )) ;
   return nullstringptr() ;
}


streng *cur_insertln( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   insertln() ;
   return nullstringptr() ;
}


streng *cur_box( paramboxptr parms )
{
   WINDOW *win ;
   char hor, vert ;

   checkparam( parms, 3, 3 ) ;
   win = getwindow( parms->value ) ;
   vert = getonechar( parms->next->value ) ;
   hor = getonechar( parms->next->next->value ) ;

   box( win, vert, hor ) ;
   return nullstringptr() ;
}


streng *cur_refresh( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   refresh() ;
   return nullstringptr() ;
}


streng *cur_standout( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   standout() ;
   return nullstringptr() ;
}


streng *cur_standend( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   standend() ;
   return nullstringptr() ;
}


streng *cur_getch( paramboxptr parms ) 
{
   streng *str ;

   checkparam( parms, 0, 0 ) ;
   str = Str_make( 1 ) ;
   str->value[0] = getch() ;
   str->len = 1 ;

   return str ;
}


streng *cur_getstr( paramboxptr parms ) 
{
   streng *str, *nstr ;
   int ch=1, i ;

   checkparam( parms, 0, 0 ) ;
   str = Str_make( SMALLSTR ) ;
   for (i=0; (ch) && (ch!=EOF); i++)
   {
      if (i>Str_max(str))
      {
         str->len = i ;
         nstr = Str_cat( Str_make(2*Str_max(str)), str ) ;
         Free( str ) ;
         str = nstr ;
      }

      str->value[i] = ch = getch() ;
   }

   str->len = i ;
   return str ;
}


streng *cur_scanw( paramboxptr parms )
{
   return nullstringptr() ;
}


streng *cur_crmode( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   crmode() ;
   return nullstringptr() ;
}

streng *cur_nocrmode( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   nocrmode() ;
   return nullstringptr() ;
}

streng *cur_raw( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   raw() ;
   return nullstringptr() ;
}

streng *cur_noraw( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   noraw() ;
   return nullstringptr() ;
}

streng *cur_echo( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   echo() ;
   return nullstringptr() ;
}

streng *cur_noecho( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   noecho() ;
   return nullstringptr() ;
}

streng *cur_nl( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   nl() ;
   return nullstringptr() ;
}

streng *cur_nonl( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   nl() ;
   return nullstringptr() ;
}



streng *cur_delch( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   delch() ;
   return nullstringptr() ;
}

streng *cur_deleteln( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   deleteln() ;
   return nullstringptr() ;
}

streng *cur_clrtoeol( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   clrtoeol() ;
   return nullstringptr() ;
}

streng *cur_clrtobot( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   clrtobot() ;
   return nullstringptr() ;
}

streng *cur_erase( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   erase() ;
   return nullstringptr() ;
}

streng *cur_clearok( paramboxptr parms )
{
   WINDOW *pwin ;
   int flag ;
 
   checkparam( parms, 2, 2 ) ;

   pwin = getwindow( parms->value ) ;
   flag = atozpos( parms->next->value ) ;
   if (flag>1)
      exiterror( ERR_INCORRECT_CALL ) ;

   clearok( pwin, flag ) ;
   return nullstringptr() ;
}

streng *cur_clear( paramboxptr parms )
{
   checkparam( parms, 0, 0 ) ;
   clear() ;
   return nullstringptr() ;
}


/*====== Routines for handline new windows ======*/


streng *curses( paramboxptr parms ) ;

static struct entrypt func_names[] = {
   { "addch",    cur_addch    },
   { "addstr",   cur_addstr   }, 
   { "box",      cur_box      },
   { "clear",    cur_clear    },
   { "clearok",  cur_clearok  },
   { "clrtobot", cur_clrtobot },
   { "clrtoeol", cur_clrtoeol },
   { "crmode",   cur_crmode   },
   { "delch",    cur_delch    },
   { "deleteln", cur_deleteln },
   { "echo",     cur_echo     },
   { "endwin",   cur_endwin   },
   { "erase",    cur_erase    },
   { "getch",    cur_getch    },
   { "getstr",   cur_getstr   },
   { "getyx",    cur_getyx    },
   { "inch",     cur_inch     },
   { "initscr",  cur_initscr  },
   { "insch",    cur_insch    },
   { "insertln", cur_insertln },
   /*"leave",*/ 
   { "move",     cur_move     },
   { "nl",       cur_nl       },
   { "nocrmode", cur_nocrmode },
   { "noecho",   cur_noecho   },
   { "noraw",    cur_noraw    },
   { "printw",   cur_printw   },
   { "raw",      cur_raw      },
   { "refresh",  cur_refresh  },
   { "scanw",    cur_scanw    },
   { "standend", cur_standend },
   { "standout", cur_standout },
   { "curses",   curses       },
   { NULL, NULL }} ;

struct entrypt *initial()
{
   return func_names ;
}


streng* curses( paramboxptr parms ) 
{
   char **cptr, *ccptr, *tptr, *ttptr ;
   streng *tstr, *tchr ;
   struct entrypt *eptr ;

   checkparam( parms, 1, 1 ) ;
   tstr = Str_make( ((parms->value)?parms->value->len:0) + 32 ) ;
   memcpy( tstr->value, parms->value->value, parms->value->len ) ;
   tptr = tstr->value + parms->value->len ;

   tchr = Str_make( 32 )  ;

   for (eptr=func_names; eptr->name; eptr++ )
   {
      ttptr = tptr ; 
      ccptr = eptr->name; 

      for (; *ccptr; *(ttptr++) = toupper(*ccptr++)) ;
      *(ttptr) = 0x00 ;
      tstr->len = strlen( tstr->value ) ;
      assert( tstr->len <= tstr->max ) ;

      strcpy( tchr->value, eptr->name ) ;
      tchr->len = strlen( eptr->name ) ;
      assert( tchr->len <= tchr->max ) ;

      loadrxfunc( NULL, tstr, tchr ) ;
   }

   return nullstringptr() ;
}


