/* at_input.c */
/*************************************************************************
 ***                        AskTask Input Module                       ***
 *** Date begun: 1/4/89.                                               ***
 *** Last modified: 1/4/89.                                            ***
 *************************************************************************/
/*** Final version now usable with other programs (with trans.c).      ***
 *************************************************************************/

#include <exec/types.h>
#include <intuition/intuition.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <string.h>

extern char trans(int);

static struct RastPort  *rport;
static char inbuf[81],*vset;
static int  cursor,length,start,slen,top;
static struct IntuiText inputline = {1,2,JAM2,0,0,NULL,&inbuf[0],NULL};
/* Note: track strlen(inbuf) with dead reckoning - slen */

static void clear(int);
static void drawcursor();
static void forward();
static void backward();
static void delprev();
static void delnext();
static void insert(char);
static void reset();
static void delEOL();
static void delBOL();
void    input(struct Window *,char *,char *,char *,int,int,int,int,int);

static void reset() /*===================================================*/
{                   /* Clear input line.                                 */
    slen = 0;   cursor = 0;
    inbuf[0] = 0;
}

static void delEOL() /*==================================================*/
{                    /* Delete to end of line.                           */
    inbuf[cursor] = 0;
    slen = strlen(inbuf);   /* Recalibrate */
}

static void delBOL() /*==================================================*/
{                    /* Delete to beginning of line.                     */
int     i,j;
    i = 0;
    for (j = cursor; j <= slen; j++) inbuf[i++] = inbuf[j];
    cursor = 0;
    slen = strlen(inbuf);   /* Recalibrate */
}

static void clear(b) /*==================================================*/
int     b;           /* Blank from EOL to end of input rect + 8 pixels.  */
{
int     x,mx;
    mx = start + 7 + (length * 8);
    x = start + (slen * 8);
    SetAPen(rport,b);
    RectFill(rport,x,top,mx,top+7);
}

static void drawcursor() /*==============================================*/
{                        /* XOR the cursor rectangle.                    */
int     x;
    x = start + cursor * 8;
    SetDrMd(rport,COMPLEMENT);
    RectFill(rport,x,top,x+7,top+7);
    SetDrMd(rport,JAM1);
}

static void forward() /*=================================================*/
{                     /* Advance a character.                            */
    if (cursor < slen) cursor++;
}

static void backward() /*================================================*/
{                      /* Reverse a character.                           */
    if (cursor > 0) cursor--;
}

static void delprev() /*=================================================*/
{                     /* Delete previous character.                      */
int     e,j;
    if (cursor == 0) return;
    e = slen;
    for (j = cursor; j <= e; j++) inbuf[j-1] = inbuf[j];
    cursor--;
    slen--;
}

static void delnext() /*=================================================*/
{                     /* Delete next character (at cursor pos).          */
int     e,j;
    if (!inbuf[cursor]) return;
    e = slen;
    for (j = cursor; j < e; j++) inbuf[j] = inbuf[j+1];
    slen--;
}

static int  valid(ch) /*=================================================*/
char    ch;           /* Check if ch is an elt of vset.                  */
{
char    *cp;
    if (!vset) return(1);            /* A valid set of NULL is all valid */
    cp = vset;
    while (*cp) if (ch == *cp++) return(1);
    return(0);
}

static void insert(ch) /*================================================*/
char    ch;            /* Insert ch into the input line.                 */
{
int     e,j;
    if (!valid(ch)) return;
    e = slen;
    if (length <= e) return;
    for (j = e; j >= cursor; j--) inbuf[j+1] = inbuf[j];
    inbuf[cursor] = ch;
    cursor++; slen++;
}

/************** INPUT() **************************************************
 * Funtion: input(char *,char *,char *,int,int,int,int)                  *
 * Purpose: this function takes input from the window, and puts it into  *
 *      a buffer area passed by the caller. The caller specifies the     *
 *      input length, initial data, colors, startx position, and a valid *
 *      character set.                                                   *
 * Parameters: w    - window to read from.                               *
 *             init - initialization string.                             *
 *             data - final storage buffer (ie: input goes here).        *
 *             cset - valid char set string (NULL = no restrictions).    *
 *             x    - start x position.                                  *
 *             y    - y position (top of character).                     *
 *             l    - maximum length (in characters) of input.           *
 *             f,b  - foreground,background colors.                      *
 *************************************************************************/
void    input(w,init,data,cset,x,y,l,f,b) /*=============================*/
struct Window   *w;
char    *init,*data,*cset;
int     x,y,l,f,b;
{
struct IntuiMessage *msg;
int     j,loop;
char    ch;

    cursor = 0; start = x; length = l; vset = cset; slen = strlen(init);
    top = y;    rport = w->RPort;
    for (j = 0; j < l; j++) inbuf[j] = 0;
    inputline.FrontPen = f;     inputline.BackPen = b;
    strcpy(inbuf,init);
    loop = 1;
    while (loop) {
        PrintIText(rport,&inputline,x,y);
        clear(b);
        drawcursor();
        Wait(1<<w->UserPort->mp_SigBit);
        while (msg = (struct IntuiMessage *)GetMsg(w->UserPort)) {
            if (msg->Class != RAWKEY) {
                ReplyMsg((struct Message *)msg);
                continue;
            }
            if (msg->Qualifier & 0x08) {
                switch (msg->Code) {
                    case (0x32): reset();   break;      /* CTRL X */
                    case (0x27):                        /* CTRL K */
                    case (0x15): delEOL();  break;      /* CTRL Y */
                    case (0x16): delBOL();  break;      /* CTRL U */
                }
            }
            else {
                switch (msg->Code) {
                    case (0x4e): forward();     break;      /* CSR R */
                    case (0x4f): backward();    break;      /* CSR L */
                    case (0x41): delprev();     break;      /*  <--  */
                    case (0x46): delnext();     break;      /* DEL   */
                    case (0x43):                            /* ENTER */
                    case (0x44): loop = 0;      break;      /* RETURN */
                    default: if (ch = trans(msg->Code)) insert(ch);
                }
            }
            ReplyMsg((struct Message *)msg);
        }
    }
    strcpy(data,inbuf);
}
