/*
 * STEVIE - Simply Try this Editor for VI Enthusiasts
 *
 * Code Contributions By : Tim Thompson           twitch!tjt
 *                         Tony Andrews           onecom!wldrdg!tony 
 *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
 */

#include "stevie.h"

/*
 * updateNextscreen() 
 *
 * Based on the current value of Topchar, transfer a screenfull of stuff from
 * Filemem to Nextscreen, and update Botchar. 
 */

void
updateNextscreen(type)
    int             type;
{
    register char  *ptr;
    register char   c;
    register int    row;
    register int    col;
    register char  *screenp;
    register char  *endscreen;
    register char  *nextrow;
    LPtr            start;
    LINE           *memp;
    LINE           *save;	/* save pos. in case line won't fit */
    char            extra[16];
    char           *p_extra;
    int             n_extra;
    bool_t          done;	/* if TRUE, we hit the end of the file */
    bool_t          didline;	/* if TRUE, we finished the last line */
    int             srow;	/* starting row of the current line */
    int             lno;	/* number of the line we're doing */
    int             coff;	/* column offset */
    int             idx;
    int             i;
    int             j;
    char            lines;

    if (NumLineSizes == 0)
	type = NOT_VALID;

    MustRedrawLine = FALSE;
    MustRedrawScreen = TRUE;

    idx = 0;
    row = 0;
    start.linep = Topchar->linep;
    screenp = Nextscreen;

    /* The number of rows shown is Rows-1. */
    /* The last line is the status/command line. */
    endscreen = Nextscreen + (Rows - 1) * Columns;

    if ((type == VALID) || (type == VALID_TO_CURSCHAR)) {
	j = -1;
	for (i = 0; i < NumLineSizes; i++) {
	    if (LinePointers[i] == Topchar->linep) {
		j = i;
		break;
	    }
	    row += LineSizes[i];
	}
	if (j == -1) {
	    /* Are we off the top of the screen by one line ? */
	    if (Topchar->linep->next == LinePointers[0]) {
		i = plines(Topchar);
		if (i < (Rows - 1)) {
		    screenp = endscreen - (i * Columns);
		
		    while (screenp > Nextscreen)
		        *(--endscreen) = *(--screenp);

		    endscreen = Nextscreen + (i * Columns);

		    for(idx = NumLineSizes;  idx > 0;  idx--) {
			LinePointers[idx] = LinePointers[idx - 1];
			LineSizes[idx] = LineSizes[idx - 1];
		    }
		    LineSizes[idx] = i;
		}
	    }
	    row = 0;
	} else if (j == 0 && type == VALID) {
	    return;
	} else {
	    nextrow = Nextscreen + row * Columns;
	    row = 0;
	    for (;;) {
		LineSizes[idx] = LineSizes[j];
		LinePointers[idx] = LinePointers[j];

		if (type == VALID_TO_CURSCHAR) {
		    if (LinePointers[idx]->next == Curschar->linep) {
			break;
		    }
		}
		j++;
		if (j >= NumLineSizes)
		    break;

		row += LineSizes[idx];
		idx++;
	    }
	    start.linep = LinePointers[idx];

	    endscreen = nextrow + row * Columns;
	    while (nextrow < endscreen)
		*screenp++ = *nextrow++;
    	    endscreen = Nextscreen + (Rows - 1) * Columns;
	}
    }

    srow = row;
    save = memp = start.linep;

    coff = P(P_NU) ? 8 : 0;

    if (P(P_NU))
	lno = cntllines(Filemem, &start);

    done = didline = FALSE;
    col = 0;
    lines = 1;

    LinePointers[idx] = memp;

    p_extra = NULL;
    n_extra = 0;
    if (P(P_NU)) {
	strcpy(extra, mkline(lno++));
	p_extra = extra;
	n_extra = 8;
    }
    ptr = memp->s;

    /*
     * We go one past the end of the screen so we can find out if the last
     * line fit on the screen or not. 
     */
    while (screenp <= endscreen) {

	/* Get the next character to put on the screen. */

	/*
	 * The 'extra' array contains the extra stuff that is inserted to
	 * represent special characters (tabs, and other non-printable stuff. 
	 */

	if (n_extra > 0) {
	    c = *p_extra++;
	    n_extra--;
	} else {
	    c = *ptr++;
	    if (c < 32 || c > 127) {
	        if (c == NUL) {
		    srow = ++row;
		    /*
		     * Save this position in case the next line won't fit on the
		     * screen completely. 
		     */
		    save = memp;
		    if (memp->next != Fileend->linep) {
		        memp = memp->next;
		        ptr = memp->s;
		    } else {
		        done = TRUE;
		    }
		    if (P(P_LS)) {
		        *screenp++ = '$';
		        if (screenp > endscreen)
			    break;
		        col++;
		        if (col >= Columns) {
			    row++;
			    lines++;
		        }
		    }

		    LineSizes[idx++] = lines;
		    lines = 1;
		    LinePointers[idx] = memp;
		    if (P(P_NU)) {
		        strcpy(extra, mkline(lno++));
		        p_extra = extra;
		        n_extra = 8;
		    }
		    /* blank out the rest of this row */
		    nextrow = Nextscreen + (row * Columns);
		    while (screenp < nextrow)
		        *screenp++ = ' ';

		    if (done)
		        break;

		    if (screenp == endscreen) {
			didline = TRUE;
			break;
		    } else if (screenp > endscreen) {
			idx--;
			break;
		    }

		    col = 0;
		    continue;
	        } else if (c == TAB) {
	            if (!P(P_LS)) {
		        strcpy(extra, "               ");
		        p_extra = extra;
		        /* tab amount depends on current column */
		        n_extra = ((P(P_TS) - 1) - (col - coff) % P(P_TS));
		        c = ' ';
		    }
		} else if ((n_extra = chars[c].ch_size - 1) > 0) {
		    p_extra = chars[c].ch_str;
		    c = *p_extra++;
	        }
	    }
	}

	if (col >= Columns) {
	    lines++;
	    row++;
	    col = 0;
	}
	/* store the character in Nextscreen */
	*screenp++ = c;
	col++;
    }

    /* Do we have to do off the top of the screen processing ? */
    if (endscreen != (Nextscreen + (Rows - 1) * Columns)) {
        endscreen = Nextscreen + (Rows - 1) * Columns;

	row = 0;
	for(idx = 0; idx <= NumLineSizes && row < (Rows - 1);  idx++)
	    row += LineSizes[idx];

	if (row < (Rows - 1)) {
	    screenp = Nextscreen + (row * Columns);
	    done = TRUE;
	} else if (row > (Rows - 1)) {	/* Need to blank out the last line */
	    idx--;
	    save = LinePointers[idx];
	    srow = row - LineSizes[idx];
	    didline = FALSE;
	} else {
	    memp = LinePointers[idx];
	    screenp = Nextscreen + (row * Columns);
	    didline = TRUE;
	}
    }

    /*
     * If we didn't hit the end of the file, and we didn't finish the last
     * line we were working on, then the line didn't fit. 
     */
    if (!done && !didline) {
	/*
	 * Clear the rest of the screen and mark the unused lines. 
	 */
	screenp = Nextscreen + (srow * Columns);
	while (screenp < endscreen)
	    *screenp++ = ' ';

	for (; srow < (Rows - 1); srow++)
	    Nextscreen[srow * Columns] = '@';

	Botchar->linep = save;
    } else {
	/* make sure the rest of the screen is blank */
	while (screenp < endscreen)
	    *screenp++ = ' ';

	/* put '~'s on rows that aren't part of the file. */
	if (col != 0)
	    row++;
	while (row < Rows) {
	    Nextscreen[row * Columns] = '~';
	    row++;
	}

	if (done)		/* we hit the end of the file */
	    *Botchar = *Fileend;
	else
	    Botchar->linep = memp;	/* FIX - prev? */
    }

    NumLineSizes = idx;
}
