/************************************************************************

vJet V1.0 © 1992 Jan Pfeil · fileviewer for AMIGA
Last changes:   15.04.92

vJet display routines

************************************************************************/

#include <math.h>
#include <string.h>

#include <exec/memory.h>
#include <graphics/gfxbase.h>

#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/intuition.h>

#include "extern.h"

VOID checkWinSize(struct vJet *vjet)     /*wenn window vergrößert*/
{
vjet->linesPerPage = min(vjet->maxline,(vjet->win->GZZHeight / vjet->dvF->tf_YSize));
vjet->columnsPerPage = min(vjet->maxcolumn,(vjet->win->GZZWidth / vjet->dvF->tf_XSize));
/*new size bigger then page*/
if(vjet->maxline-vjet->topline < vjet->linesPerPage)
    if(0 > (vjet->topline = vjet->maxline - vjet->linesPerPage))
        vjet->topline = 0;
if(vjet->maxcolumn-vjet->topcolumn < vjet->columnsPerPage)
    if(0 > (vjet->topcolumn = vjet->maxcolumn-vjet->columnsPerPage))
        vjet->topcolumn = 0;
}


LONG countLines(char *buffer, LONG len)
{
char *c = buffer;
char *start = buffer;
LONG line=1;                        //at least one EOF
for(c = buffer ; c < buffer+len;c++) {
    if(*c == '\n' || c >= start+MAXLINELEN) {
        line++;
        start = c+1;
        }
    }
//buffer[len] = '\n';             //convert EOL to newline
return(line);       /*ablosute number of lines*/
}


char *getCSI(char *c,LONG *CSIlen)
{
char *p = c;
if(*c == '\x1B' || *c == '\x9B') {
    *CSIlen = 1;
    while(*c != 'm' && *c != 'p') {
        c++;
        (*CSIlen)++;
        }
    }
else {
    p = NULL;
    *CSIlen = 0;
    }
return(p);
}

#define PLAIN 0
#define BOLDFACE 1
#define FAINT 2
#define ITALIC 3
#define UNDERSCORE 4
#define REVERSED 7
#define CONCEALED 8         //ignored, because hidden
#define BOLDOFF 22
#define ITALICOFF 23
#define UNDERSCOREOFF 24
#define REVERSEDOFF 27
#define CONCEALEDOFF 28     //ignored

//character color (foreground)
#define FGCOLOR0 30
#define FGCOLOR1 31
#define FGCOLOR2 32
#define FGCOLOR3 33
#define FGCOLOR4 34
#define FGCOLOR5 35
#define FGCOLOR6 36
#define FGCOLOR7 37

#define RESETFGCOLOR 39

//character cell color background
#define BGCOLOR0 40
#define BGCOLOR1 41
#define BGCOLOR2 42
#define BGCOLOR3 43
#define BGCOLOR4 44
#define BGCOLOR5 45
#define BGCOLOR6 46
#define BGCOLOR7 47

#define RESETBGCOLOR 49

VOID setCSIcode(char *CSItok,UBYTE *mode,ULONG *style,UBYTE *fgColor,UBYTE *bgColor)
{
char tok[10];
int val;

if(*++CSItok == '[') {             //CSI found
    while(*CSItok != 'm' && *CSItok != 'p') {        //till end
        CSItok++;
        if(*CSItok == ';')
            CSItok++;
        CSItok = stptok(CSItok,tok,sizeof(tok),";mp"); //now p points to ';' or 'm'
        stcd_i(tok,&val);
        switch(val) {
                    case FGCOLOR0:  *fgColor = 0;
                                    break;
                    case FGCOLOR1:  *fgColor = 1;
                                    break;
                    case FGCOLOR2:  *fgColor = 2;
                                    break;
                    case FGCOLOR3:  *fgColor = 3;
                                    break;
                    case FGCOLOR4:  *fgColor = 4;
                                    break;
                    case FGCOLOR5:  *fgColor = 5;
                                    break;
                    case FGCOLOR6:  *fgColor = 6;
                                    break;
                    case FGCOLOR7:  *fgColor = 7;
                                    break;
                    case RESETFGCOLOR: *fgColor = AUTOBACKPEN;
                                    break;
                    case BGCOLOR0:  *bgColor = 0;
                                    break;
                    case BGCOLOR1:  *bgColor = 1;
                                    break;
                    case BGCOLOR2:  *bgColor = 2;
                                    break;
                    case BGCOLOR3:  *bgColor = 3;
                                    break;
                    case BGCOLOR4:  *bgColor = 4;
                                    break;
                    case BGCOLOR5:  *bgColor = 5;
                                    break;
                    case BGCOLOR6:  *bgColor = 6;
                                    break;
                    case BGCOLOR7:  *bgColor = 7;
                                    break;
                    case RESETBGCOLOR: *bgColor = AUTOFRONTPEN;
                                    break;

                    case PLAIN:     *mode = JAM2;
                                    *style = FS_NORMAL;
                                    *fgColor = AUTOBACKPEN;
                                    *bgColor = AUTOFRONTPEN;
                                    break;
                    case BOLDFACE:  *style |= FSF_BOLD;
                                    break;
                    case FAINT:
                                    break;
                    case ITALIC:    *style |= FSF_ITALIC;
                                    break;
                    case UNDERSCORE:*style |= FSF_UNDERLINED;
                                    break;
                    case REVERSED:  *mode |= INVERSVID;
                                    break;
                    case BOLDOFF:   *style &= ~FSF_BOLD;
                                    *fgColor = AUTOBACKPEN;
                                    break;
                    case ITALICOFF: *style &= ~FSF_ITALIC;
                                    break;
                    case UNDERSCOREOFF:*style &= ~FSF_UNDERLINED;
                                    break;
                    case REVERSEDOFF: *mode &= ~INVERSVID;
                                    break;
                    default:        break;
            }
        }
    CSItok++;
    }
else {
    //printf("ESC without [ found\n");
    }
}

BOOL checkForFormats(struct vJet *vjet)
{
BOOL format = FALSE;                    //switch if at least one <CSI>
LONG line,CSIlen;
UBYTE mode = JAM2;
ULONG style = FS_NORMAL;
UBYTE fgColor = AUTOBACKPEN;
UBYTE bgColor = AUTOFRONTPEN;
char *p,*CSItok;
struct vLine *vline;

for(line=0; line<vjet->maxline; line++) {
    vline = &vjet->lineArray[line];
    p = vline->string;

    vline->mode = mode;
    vline->style = style;
    vline->fgColor = fgColor;
    vline->bgColor = bgColor;

    while(p < vline->string+vline->len) {
        while(*p == '\x1B' || *p == '\x9B') {      //CSI found
            format = vline->format = TRUE;         //at least one format
            CSItok = getCSI(p,&CSIlen);
            p += CSIlen;
            setCSIcode(CSItok,&mode,&style,&fgColor,&bgColor);
            }
        p++;
        }
    }/*for(;;)*/
return(format);
}


void setDefaultStyle(struct vJet *vjet)
{
SetAPen(vjet->win->RPort,AUTOBACKPEN);
SetBPen(vjet->win->RPort,AUTOFRONTPEN);
SetDrMd(vjet->win->RPort,JAM2);
SetSoftStyle(vjet->win->RPort,0,AskSoftStyle(vjet->win->RPort));
}

/*
LONG lineLength(register char *string)
{
register char *p = string;
while(*string != '\n') {
    string++;
    }
return(string - p);
}
*/

ULONG initLPTR(struct vJet *vjet,char *buf,LONG bufSize,struct vLine lineArray[], LONG maxline)
{
char buffer[2*MAXLINELEN],*c = buf;
ULONG line, lineLen, column, maxcolumn = 0;
ULONG count,tab=8;

for(line=0 ; line < maxline; line++) {
    for(lineLen=0; *c != '\n' && lineLen<MAXLINELEN && c < buf+bufSize; c++) {

        switch(*c) {
            case '\t':  //tabulator
                        count = ((lineLen/tab+1)*tab+1)-(lineLen+1);
                        CopyMem("        ",buffer+lineLen,count);
                        lineLen+=count;
                        break;
            case '\b':  if(lineLen>0)               //backspace at column 0 is ignored yet
                            lineLen--;              //one step backward if possible
                        break;
            case '\r':  if(*(c+1) == '\n')          // '\r' followed by newline
                            ;                       //simply ignore
                        else {
                            buffer[lineLen++] = *c; //display code (should never happen in ascii mode)
                            }
                        break;
            case '\f':  //ignore formfeed
                        break;
            default:    buffer[lineLen++] = *c;
                        break;
            }
        }

    if(*c == '\n')
        c++;

    //NOTE: all strings NULL-terminated
    lineArray[line].string = AllocMem(1+lineLen*sizeof(BYTE),MEMF_PUBLIC+MEMF_CLEAR);
    if(lineLen) {
        CopyMem(buffer,lineArray[line].string,lineLen);
        lineArray[line].len = lineLen;
        }

    lineArray[line].number = line+1;
    maxcolumn = max(maxcolumn,lineLen);
    }

return(maxcolumn);
}


VOID initLines(struct vJet *vjet,char *buf,LONG bufSize)
{
vjet->maxline = countLines(buf, bufSize);

if(vjet->lineArray = AllocMem((vjet->maxline+1)*sizeof(struct vLine),MEMF_PUBLIC+MEMF_CLEAR)) {
    vjet->maxcolumn = initLPTR(vjet,buf,bufSize,vjet->lineArray,vjet->maxline);
    vjet->topline = 0;
    vjet->topcolumn = 0;
    vjet->handleCSI = checkForFormats(vjet);
//set or unset handleCSI toggle in menu
    checkWinSize(vjet);
    }
}

//this routine needs strong enhancements, don't look too close
BOOL loadFile(struct vJet *vjet,STRPTR path)
{
struct FileInfoBlock __aligned fIB;
struct FileHandle *fh = NULL;
BPTR lock;
LONG actualLen, bufSize;
BOOL ret = TRUE;
char *fileBuf;

if(lock = Lock(path,ACCESS_READ)) {
    if(Examine(lock,&fIB)) {
        unLoadFile(vjet);
        bufSize = fIB.fib_Size;
        if(fh = (struct FileHandle *)Open(path,MODE_OLDFILE)) {
            titleWin(vjet,"Loading ...");
            if(fileBuf = AllocMem(bufSize*sizeof(BYTE),MEMF_PUBLIC+MEMF_CLEAR)) {
                actualLen = Read((BPTR)fh,fileBuf,bufSize);
                if(actualLen != bufSize) {
                    ret=FALSE;
                    titleWin(vjet,"ERROR while loading file");
                    }
                else {
                    initLines(vjet,fileBuf,bufSize);

                    }
                FreeMem(fileBuf,bufSize*sizeof(BYTE));
                }
            else {
                ret=FALSE;
                }
            Close((BPTR)fh);
            }
        else ret=FALSE;
        }
    else ret=FALSE;
    UnLock(lock);
    }
else ret=FALSE;
return(ret);
}

//reset everything concerning file
VOID unLoadFile(struct vJet *vjet)
{
register LONG line;

if(vjet->lineArray) {
    for(line=0 ; line < vjet->maxline; line++) {
        if(vjet->lineArray[line].string) {
            FreeMem(vjet->lineArray[line].string,1+vjet->lineArray[line].len*sizeof(BYTE));
            }
        }
    FreeMem(vjet->lineArray,(vjet->maxline+1)*sizeof(struct vLine));
    vjet->lineArray = NULL;
    vjet->maxline = 0;
    vjet->maxcolumn = 0;
    vjet->topline = 0;
    vjet->topcolumn = 0;
    vjet->linesPerPage = 0;
    vjet->columnsPerPage = 0;
    }

setDefaultStyle(vjet);
vjet->findpos[0] = -1;
vjet->findpos[1] = -1;
vjet->findLen = 0;

/*path stays alive*/
}


VOID openFile(struct vJet *vjet,STRPTR path)
{
BOOL retry = TRUE;
BOOL success = FALSE;

do {
    if(*path == NULL) {
        if(fileReq(vjet,vjet->win,"Load file",vjet->path[vjet->pathNum],FREQ_TEXT)) {
            retry = TRUE;
            path = vjet->path[vjet->pathNum];
            }
        else {
            retry = FALSE;
            }
        }
    else {
        if(loadFile(vjet,path)) {
            retry = FALSE;
            success = TRUE;
            }
        else {
            //IOErr !
            if(retry = arqEasyRequest(vjet->win,openFail,ARQ_ID_QUESTION,NULL,path))
                *path = NULL;   //to indicate a new fileRequest is necessary and old path is invalid
            }
        }
    }while(retry == TRUE);

if(success) {
    displayWholePage(vjet);
    setHSlider(vjet);
    setVSlider(vjet);
    titleWin(vjet,path);
    }
}


/************************************************************************************
line        - line to print
linepos     - row on display
col         - column on display
ccount      - character count to be printed
************************************************************************************/
VOID printLine(struct vJet *vjet,struct vLine line,LONG linepos,LONG col,LONG ccount)
{
LONG x,y,len = line.len-vjet->topcolumn;    /*was in Zeile noch übrig ist*/
char *c,*p,*CSItok;
LONG CSIlen,clen = 0;
UBYTE mode=0,fgColor=0,bgColor=0;
ULONG style=0;

if(vjet->handleCSI) {
    mode = line.mode;
    SetDrMd(vjet->win->RPort,mode);
    style = line.style;
    SetSoftStyle(vjet->win->RPort,style,AskSoftStyle(vjet->win->RPort));
    fgColor = line.fgColor;
    SetAPen(vjet->win->RPort,fgColor);
    bgColor = line.bgColor;
    SetBPen(vjet->win->RPort,bgColor);
    }

//now on first printable position
x = col * vjet->dvF->tf_XSize;          /*ab dieser Spalte*/
y = linepos * vjet->dvF->tf_YSize + vjet->dvF->tf_Baseline;
Move(vjet->win->RPort, x, y);

if(line.number == 0) {
//    DisplayBeep(vjet->scr);
//    titleWin(vjet,"ClearEOL");
//    Delay(50L);
    ClearEOL(vjet->win->RPort);
    }
else if(line.format && vjet->handleCSI) {       //this line contains ANSI format
    c = line.string;

    //skip text before first column

    while(c < line.string+line.len && c < line.string+vjet->topcolumn+col+clen) {
        if(*c == '\x1B' || *c == '\x9B') {      //CSI found
            CSItok = getCSI(c,&CSIlen);
            c += max(1,CSIlen);                 //increase c at least one
            clen += CSIlen;      //really printed chars
            setCSIcode(CSItok,&mode,&style,&fgColor,&bgColor);
            }
        else {
            c++;
            }
        }

    SetDrMd(vjet->win->RPort,mode);
    SetSoftStyle(vjet->win->RPort,style,AskSoftStyle(vjet->win->RPort));
    SetAPen(vjet->win->RPort,fgColor);
    SetBPen(vjet->win->RPort,bgColor);

//c now points to first printable column
    p = c;

    while(c < line.string+line.len && c <= line.string+vjet->topcolumn+col+clen+vjet->columnsPerPage) {

        if(*c == '\x1B' || *c == '\x9B') {      //CSI found
            if(c > p) {
                Text(vjet->win->RPort,p,c-p);
                }
            CSItok = getCSI(c,&CSIlen);
            c += max(1,CSIlen);
            clen += CSIlen;      //really printed chars
            setCSIcode(CSItok,&mode,&style,&fgColor,&bgColor);
            SetDrMd(vjet->win->RPort,mode);
            SetSoftStyle(vjet->win->RPort,style,AskSoftStyle(vjet->win->RPort));
            SetAPen(vjet->win->RPort,fgColor);
            SetBPen(vjet->win->RPort,bgColor);
            p = c;
            }
        else {
            c++;
            }
        }
    if(c > p) {                         //printf rest of line
        Text(vjet->win->RPort,p,c-p);
        }
    }
else if((len-col) > 0) {
    Text(vjet->win->RPort,line.string+vjet->topcolumn+col,min(len-col,ccount));

    }
}

VOID displayPage(struct vJet *vjet,LONG lpos,LONG lcount,LONG col,LONG ccount)
{
LONG line = vjet->topline+lpos;
for( ;lcount>0;lcount--) {
    printLine(vjet,vjet->lineArray[line++],lpos++,col,ccount);
    }
}

VOID displayWholePage(struct vJet *vjet)
{
SetRast(vjet->win->RPort,AUTOFRONTPEN);
displayPage(vjet,0,vjet->linesPerPage+1,0,vjet->columnsPerPage+1);
}

VOID movePageVert(struct vJet *vjet,LONG lines)   /*Seite vertikal scrollen*/
{
//vacated space is filled with background color
SetBPen(vjet->win->RPort,AUTOFRONTPEN);     //a help for ScrollRaster()

if(lines>0) {       /* vorwärts, page forward */
    if(vjet->topline+vjet->linesPerPage+lines > vjet->maxline)
        lines = vjet->maxline-vjet->linesPerPage-vjet->topline;
    vjet->topline += lines;
    if(lines < vjet->linesPerPage) {
        ScrollRaster(vjet->win->RPort,0,lines*vjet->dvF->tf_YSize,
                     0,0,vjet->win->GZZWidth,vjet->win->GZZHeight);
        displayPage(vjet,vjet->linesPerPage-lines,lines+1,0,vjet->columnsPerPage+1);
        }
    else {
        SetRast(vjet->win->RPort,AUTOFRONTPEN);
        displayWholePage(vjet);
        }
    }

else if(lines<0) {       /* rückwärts, page backward */
    if(vjet->topline+lines < 0)
        lines = -vjet->topline;
    vjet->topline += lines;
    if(-lines < vjet->linesPerPage) {
        ScrollRaster(vjet->win->RPort,0,lines*vjet->dvF->tf_YSize,
                     0,0,vjet->win->GZZWidth,vjet->win->GZZHeight);
        displayPage(vjet,0,-lines,0,vjet->columnsPerPage+1);
        }
    else {
        SetRast(vjet->win->RPort,AUTOFRONTPEN);
        displayWholePage(vjet);
        }
    }
}/*end of movePageVert()*/

VOID movePageHoriz(struct vJet *vjet,LONG columns)   /*Seite vertikal scrollen*/
{
SetBPen(vjet->win->RPort,AUTOFRONTPEN);

if(columns>0) {       /* right, page rightward */
    if(vjet->topcolumn+columns+vjet->columnsPerPage > vjet->maxcolumn)
        columns = vjet->maxcolumn-vjet->columnsPerPage-vjet->topcolumn;
    vjet->topcolumn += columns;
    ScrollRaster(vjet->win->RPort,columns*vjet->dvF->tf_XSize,0,
                 0,0,vjet->win->GZZWidth,vjet->win->GZZHeight);
    displayPage(vjet,0,vjet->linesPerPage+1,vjet->columnsPerPage-columns,columns+1);
    }

else if(columns<0) {       /* rückwärts, page backward */
    if(vjet->topcolumn+columns < 0)
        columns = -vjet->topcolumn;
    vjet->topcolumn += columns;
    ScrollRaster(vjet->win->RPort,columns*vjet->dvF->tf_XSize,0,
                 0,0,vjet->win->GZZWidth,vjet->win->GZZHeight);
    displayPage(vjet,0,vjet->linesPerPage+1,0,-columns);
    }
}/*end of movePageHoriz()*/

/*end of file*/
