/*
        This is the I/O stuff for Flist... Inspired by the Mg2a
        project. 
        
        Written by Stephen W. Berry. 8/19/88
*/
 
#include <libraries/arpbase.h>
#include "flist.h"

/*
 * External Amiga functions.
 */

extern     LONG       AbortIO();
extern     LONG       CloseDevice();
extern     struct     IOStdReq     *CreateStdIO();
extern     int        OpenConsole();
extern     struct     Window          *OpenWindow();
extern     LONG       RawKeyConvert();
extern     top;

/* extern Flist variables */

extern struct NewWindow *winptr;
extern struct Window mywin;
extern struct NewScreen *scrptr;
extern struct Screen scr;
extern struct Menu fmenu;
extern struct Gadget pg;
extern struct RastPort *rp;
extern struct Image cursor_image;
extern struct Image cursor_blank;
extern Enable_Abort;
extern struct FileLock *lock, *olddir;
extern char (*fname[MAXDIR])[FCHARS];
extern long (*finfo[MAXDIR])[4];
extern short remember;

/* Some external functions */

extern void swapdir(), parent();
extern long DoDOS(), spawnproc(), kill(), changedir();

/* Global variables */

struct Device *ConsoleDevice;
struct IOStdReq ConsoleReq;
struct InputEvent RawKeyEvent = {NULL,IECLASS_RAWKEY,0,0,0};

#define BUFSIZ 10

UBYTE KeyBuffer[BUFSIZ];

struct IntuiText input = {
        TEXTCOLOR,0,  /* Front & Back pen */
        JAM2,   /* Drawmode */
        0,0,    /* Left, Top */
        NULL,   /* Font */
        KeyBuffer,
        NULL    /* Next text */
        };

char conline[256];
char titlestr[80];
long row = 0,collum = 0,line = 0,first = 0;

void ttclose(),tthide(),ttshow();

/*
 * Iconify Flist's window using tthide(), iconify(), and ttshow().
 */


VOID
tthide(resize)
int resize;
{
     if (resize == TRUE) {               /* if we're resizing,     */
          mywin.LeftEdge = winptr->LeftEdge; /* use current window size */
          mywin.TopEdge = winptr->TopEdge;
          mywin.Width = winptr->Width;
          mywin.Height = winptr->Height;
     }
     ttclose();                    /* reset to zero     */
}

VOID
ttshow(resize)
int resize;
{
     openstuff();
     SetMenuStrip(winptr, &fmenu);
     Enable_Abort = 1;          
}

VOID
ttclose()
{
     ClearMenuStrip(winptr);
     CloseWindowSafely(winptr,NULL);
     CloseScreen(scrptr);
     winptr = NULL; scrptr = NULL;
     Enable_Abort = 0;
}

extern long numfiles, lastsort;

refresh()
{
    char buf[100], buf1[200];
    remember = -10;

    collum = 0;
    if (row+1 > numfiles && row+2 == numfiles) {
        row--;
        line--;
    } else 
        if (row > numfiles) {
            top = 0;
            row = 0;    
            line = 0;
        }

    sort(lastsort);
    first = 0;
    scrprt(NUMLINES,top);

    PathName(lock, buf1);
    sprintf(buf,"%s   Files = %ld", buf1, numfiles);
    strncpy(titlestr,buf,80L);
    SetWindowTitles(winptr, -1L,titlestr);
}

OpenConsole()
{
        if (OpenDevice("console.device",-1L,&ConsoleReq,0L)){
                DisplayBeep();
                Cleanup();
        }
        ConsoleDevice = ConsoleReq.io_Device; /* Lib base address */
}

/* this little guy takes input from the IDCMP and stuffs it out to the
        routines involved... */

getkey(message) 
struct IntuiMessage *message; 
                /* this routine has the potential to grow to enormous */
{               /* size... I'll try to restrain myself */
        long keycodes,i,rc;
        char buf[1000];

        RawKeyEvent.ie_Code = message->Code;
        RawKeyEvent.ie_Qualifier = message->Qualifier;
        RawKeyEvent.ie_position.ie_addr = *((APTR *)message->IAddress);
        keycodes = RawKeyConvert(&RawKeyEvent,KeyBuffer,BUFSIZ,NULL);

        ReplyMsg(message);

        if (keycodes > 0){      /* we have something */ 

        blankcur();
  
        switch (KeyBuffer[0]) {
            case 0x7f:              /* here we got a delete */
                    KeyBuffer[0] = 0;
                    if (collum == 0)
                        conline[0] = 0;
                    for(i=collum;i<254;i++)
                        conline[i] = conline[i+1];
                    drawline(collum,TRUE);
                    break;
            case 0x08:              /* back space */
                    KeyBuffer[0] = 0;
                    if (collum == 0)
                            conline[0] = 0;
                    if (collum > 0) {
                            collum--;
                            for(i=collum;i<254;i++)
                                    conline[i] = conline[i+1];
                    }
                    drawline(collum, TRUE);
                    break;
            case 0x0d:
                    KeyBuffer[0] = 0;
                    DoDOS(conline);     /* This is the Biggie! */
                    if ( row == NLMO ) {
                            if ( top + NUMLINES < numfiles ) {
                                    line++;
                                    scrprt(NUMLINES,++top);
                            }
                            else
                                    DisplayBeep(0L);
                    }
                    first = 0;
                    collum = 0;
                    for(i=0;i<255;i++)
                            conline[i] = 0;
                    break;
            case 0x9b:
                    KeyBuffer[0] = 0;
                    switch (KeyBuffer[1]) {
                        case 0x3f:	    /* looking for the Help key */
                            if (KeyBuffer[2] == 0x7e)
                                Help();
                            break;
                        case 0x41:      /* up arrow */
                            if (collum == 0) {
                                for(i=0;i<255;i++)
                                    conline[i] = 0;
                            }
                            else {
                                strcpy(buf,conline);
                                conline[first] = 0;
                                drawline(collum,TRUE);
                                strcpy(conline,buf);
                            }
                            if (row > 0) {
                                line--;
                                row--;
                            }
                            else if (row == 0 && top > 0) {
                                line--;
                                scrprt(NUMLINES,--top);
                            }
                            drawline(collum,TRUE);
                            break;
                        case 0x42:      /* Down Arrow */
                            if (collum == 0) {
                                for(i=0;i<255;i++)
                                    conline[i] = 0;
                            }
                            else {
                                strcpy(buf,conline);
                                conline[first] = 0;
                                drawline(collum,TRUE);
                                strcpy(conline,buf);
                            }
                            if (row < NLMO) {
                                if (line < numfiles - 1){
                                    line++;
                                    row++;
                                }        
                            }
                            else if (row == NLMO && line < numfiles - 1) {
                                line++;
                                scrprt(NUMLINES,++top);
                            }
                            drawline(collum,TRUE);
                            break;
                        case 0x44:      /* Left Arrow */
                            if (collum > 0)
                                collum--;
                                drawline(collum,TRUE);
                            break;
                        case 0x43:      /* Right Arrow */
                            if (collum < 90)
                                collum++;
                            else 
                                DisplayBeep(NULL);
                            drawline(collum,FALSE);
                            break;
                        default:
                            check_for_shift();
                            break;
                    }
                    KeyBuffer[1] = 0;
                    break;
            case 0x1b:      /* The File name insertion thing... */
                    insert_name();
                    break;
            default:
                    if (KeyBuffer[0] < 0x20)
                        control_keys(KeyBuffer[0]);
                    else
                        enter_char(KeyBuffer[0]);
                    break;
            }
    drawcur();
    }
}

/* I split up the switch for two reasons... One, I though that the first
   was getting a bit big, Two, I think MANX chokes on large switches.
*/

/* Looking for the shift-arrow keys */

check_for_shift()
{
    char buf[256];

    switch (KeyBuffer[1]) {

        case 'T':
            if (top > 0) {

                if (line < 10)
                    line = 0;
                else
                    if (top < 10)
                        line -= top;
                    else 
                        line -= 10;

                if (top < 10)
                    top = 0;
                else 
                    top -= 10;

            }
            scrprt(NUMLINES,top);
            strcpy(buf,conline);
            conline[first] = 0;
            drawline(collum,TRUE);
            strcpy(conline,buf);
            drawline(collum,TRUE);
            break;

        case 'S':

            if (numfiles - 11 > line) {

                if (numfiles - 11 < line)
                    line = numfiles - 1;
                else
                    line += 10;

                if (top+10 > numfiles - 1)
                    top = numfiles - 1;
                else 
                    top += 10;
            }
            scrprt(NUMLINES,top);
            strcpy(buf,conline);
            conline[first] = 0;
            drawline(collum,TRUE);
            strcpy(conline,buf);
            drawline(collum,TRUE);
            break;
        case ' ':
            switch(KeyBuffer[2]) {
                case 'A':           /* left arrow */
                    collum = 0;
                    first = 0;
                    drawline(collum,TRUE);
                    break;
                case '@':           /* right arrow */
                    collum = strlen(conline);
                    first = collum > 29 ? collum - 29: 0;
                    drawline(collum,TRUE);
                    break;
            }
        }
}

control_keys(key)
char key;
{
    char buf[256];
    int i;

    switch(key) {

        case 0x01:              /* ^A - get the Arp file-requestor */
            if (Wbargs() == 0){
                UnLock(olddir);
                refresh();
            }
            break;

        case 0x03:              /* user typed ^C */
            _abort();
            break;

        case 0x04:              /* ^D - change directory to fname */

/* ***** Hidden SECRET of AmigaDOS !! *****
   only found in the RKM includes... You can tell if a file is
   really a file or if it is a directory by the value of DirEntryType.
   If it is < 0 then it is a file, if > 0 then it is a directory */

            if (*finfo[line][0] < 0){
                sprintf(buf,"%s Not a directory",fname[line]);
                auto_req(buf);
            }else {
                changedir(fname[line]);
                refresh();
            }
            break;

        case 0x07:              /* ^G - Re-get the current dir */
            getdir();
            refresh();
            break;

        case 0x0b:              /* ^K - Delete file */
            kill(fname[line]);
            refresh();
            break;

        case 0x0c:              /* ^L - refresh the screen */
            collum = 0;
            row = 0;
            line = 0;
            first = 0;
            top = 0;
            refresh();          /* also resets the cursor to zero pos */
            break;

        case 0x0e:              /* ^N - Make directory */
            make_dir();
            refresh();
            break;

        case 0x0f:              /* ^O - sort by pattern */
            sort(3);
            refresh();
            break;

        case 0x10:              /* ^P - change directory to Parent */
            parent();
            refresh();
            break;

        case 0x12:              /* ^R - rename file */
            rename_file(fname[line]);
            refresh();
            break;

        case 0x13:              /* ^S - sort by names */
            sort(0);
            refresh();
            break;

        case 0x14:              /* ^T - sort by Time */
            sort(2);
            refresh();
            break;

        case 0x15:              /* ^U - erase line to start */
            for (i=0;i<254;i++)
                conline[i] = '\0';
            first = 0;
            collum = 0;
            drawline(collum,TRUE);
            break;

        case 0x18:              /* ^X - Start REXX macro */
            dorexx();
            break;

        case 0x19:              /* ^Y - sort by day */
            sort(4);
            refresh();
            break;

        case 0x1a:              /* ^Z - sort by size */
            sort(1);
            refresh();
            break;
    }
}


/* Enter a char into the array and screen */

enter_char(c)
register char c;
{
    int i;
    
    for(i=254;i>collum;i--)     /* This is for insert mode */
        conline[i] = conline[i-1];

    KeyBuffer[0] = c;
    if (collum < 90) {
            conline[collum] = c;
            collum++;
            drawline(collum,FALSE);
    } else 
            DisplayBeep(NULL);
    KeyBuffer[0] = 0;
}

/* Draw the current line from the cursor position, for scrolling */

drawline (curpos,flag)
long curpos,flag;
{
        long i,temp1,temp2;
        char tbuf[31];
#ifdef DEBUG
        char buf[90];

        sprintf(buf," Row %ld Collumn %ld Top %ld First %ld line %ld \
            numfiles %ld",row,collum,top,first,line,numfiles);
        SetWindowTitles(winptr,-1L,buf);
#endif

        temp2 = LINEH * row + TOP + 2;

        if ((collum >= first+30) || (collum == first)) {

                if (flag){
                        if (first>0)
                                first--;
                }
                else {
                        if (first<89)
                                first++;
                }
        }
    
    strncpy(tbuf,&conline[first],30);

    temp1 = strlen(tbuf);
    for(i=temp1;i<29;i++)
        tbuf[i] = ' ';

    tbuf[29] = '\0';

    input.IText = tbuf;
    PrintIText(rp,&input,(LONG)LEFT,temp2);
    input.IText = KeyBuffer;
}

long getcol()
{
        register long temp1;

        if (collum == first + 29)
                temp1 = CHARW * 29 + LEFT;
        else if (first == collum)
                temp1 = LEFT;
        else {
                temp1 = CHARW * (collum - first) + LEFT;
        }
        return temp1;
}

/* Draw the cursor at the current row & collum */

drawcur()
{
        register long temp1,temp2;

        temp1 = getcol();
        temp2 = LINEH * row + TOP + 2;

        SetDrMd(rp,COMPLEMENT|JAM1);
        SetAPen(rp,4);
        RectFill(rp,temp1,temp2,temp1+7,temp2+7);
        SetAPen(rp,2);
        SetDrMd(rp,JAM1);
}

/* Blank the cursur, where-ever it is. */

blankcur()
{
        register long temp1,temp2;
                
        temp1 = getcol();
        temp2 = LINEH * row + TOP + 2;

        SetDrMd(rp,COMPLEMENT|JAM2);
        SetAPen(rp,0);
        RectFill(rp,temp1,temp2,temp1+7,temp2+7);
        SetAPen(rp,2);
        SetDrMd(rp,JAM1); 
}

/* This is where the File insertion code is (in case you were wondering) */

insert_name()
{
        register int i, j;
        register char *temp;        
        j=0;
        
        if(line > numfiles)
                return;
                
        for (i=collum;i<89;i++){
                temp = fname[line];
                if (temp[j] == 0)
                        break;
                enter_char(temp[j++]);
        }
}
