/* Copyright 1989 - 2000 by Abacus Research and
 * Development, Inc.  All rights reserved.
 */

#if !defined (OMIT_RCSID_STRINGS)
char ROMlib_rcsid_listAddDel[] =
	    "$Id: listAddDel.c 74 2004-12-30 03:38:55Z ctm $";
#endif

/* Forward declarations in ListMgr.h (DO NOT DELETE THIS LINE) */

#include "rsys/common.h"
#include "ListMgr.h"
#include "MemoryMgr.h"
#include "rsys/list.h"
#include "rsys/screen.h"

P3(PUBLIC pascal trap, INTEGER, LAddColumn, INTEGER, count,	/* IMIV-271 */
					      INTEGER, coln, ListHandle, list)
{
    Rect todraw;
    Cell c;
    INTEGER ncols, nrows, noffsets, offset;
    Size nbefore, nafter;
    Ptr ip, op;
    int i;
    Point p;

    nrows = Hx(list, dataBounds.bottom) - Hx(list, dataBounds.top);
    noffsets = count * nrows;
    if (coln > Hx(list, dataBounds.right))
	coln = Hx(list, dataBounds.right);

    if (coln < Hx(list, dataBounds.left))
	coln = Hx(list, dataBounds.left);

    HxX(list, dataBounds.right) = CW(Hx(list, dataBounds.right) + count);

    if (noffsets) {
	TRAPBEGIN();
	SetHandleSize((Handle) list,
		    GetHandleSize((Handle) list) + noffsets * sizeof(INTEGER));
	ncols = Hx(list, dataBounds.right) - Hx(list, dataBounds.left);
	nbefore = (coln - Hx(list, dataBounds.left)) * sizeof(INTEGER);
	nafter  = (ncols - count) * sizeof(INTEGER) - nbefore;
	ip = (Ptr) (HxX(list, cellArray) + nrows * (ncols - count) + 1);
	op = (Ptr) (HxX(list, cellArray) + nrows * ncols + 1);
	op -= sizeof(INTEGER);
	ip -= sizeof(INTEGER);
	*(INTEGER *)op = *(INTEGER *)ip;	/* sentinel */
	/* SPEEDUP:  merge the two BlockMoves ... (unroll begining and end) */
	while (--nrows >= 0) {
	    ip -= nafter;
	    op -= nafter;
	    BlockMove(ip, op, nafter);
	    offset = CW(*(INTEGER *)op) & 0x7FFF;
	    for (i = 0; ++i <= count; )
	      {
		op -= sizeof(INTEGER);
		*(INTEGER *)op = CW(offset);
	      }
	    ip -= nbefore;
	    op -= nbefore;
	    BlockMove(ip, op, nbefore);
	}

	p.h = Hx(list, cellSize.h);
	p.v = Hx(list, cellSize.v);
	C_LCellSize(p, list);		/* recalcs visible */

	if (Hx(list, listFlags) & DODRAW) {
	    todraw = HxX(list, dataBounds);
	    todraw.left = CW(coln);
	    SectRect(&todraw, &HxX(list, visible), &todraw);
	    for (c.v = CW(todraw.top) ; c.v < CW(todraw.bottom); c.v++)
		for (c.h = CW(todraw.left) ; c.h < CW(todraw.right); c.h++)
		    C_LDraw(c, list);
	}
	TRAPEND();
    }
    return coln;
}

P3(PUBLIC pascal trap, INTEGER, LAddRow, INTEGER, count,	/* IMIV-271 */
					      INTEGER, rown, ListHandle, list)
{
    Rect todraw;
    Cell c;
    INTEGER ncols, nrows, noffsets, offset;
    Size nbefore, nafter;
    INTEGER *ip, *op;
    Point p;

    ncols = Hx(list, dataBounds.right) - Hx(list, dataBounds.left);
    noffsets = count * ncols;
    if (rown > Hx(list, dataBounds.bottom))
	rown = Hx(list, dataBounds.bottom);

    if (rown < Hx(list, dataBounds.top))
      rown = Hx(list, dataBounds.top);

    HxX(list, dataBounds.bottom) = CW(Hx(list, dataBounds.bottom) + count);

    if (noffsets) {
	TRAPBEGIN();
	SetHandleSize((Handle) list,
		    GetHandleSize((Handle) list) + noffsets * sizeof(INTEGER));
	nrows = Hx(list, dataBounds.bottom) - Hx(list, dataBounds.top);
	nbefore = (rown - Hx(list, dataBounds.top));
	nafter  = ((nrows - count) - nbefore) * ncols;
	ip = HxX(list, cellArray) + (nrows - count) * ncols + 1;
	op = HxX(list, cellArray) + nrows * ncols + 1;
	*--op = *--ip;	/* sentinel */
	ip -= nafter;
	op -= nafter;
	offset = CW(*ip) & 0x7FFF;
	BlockMove((Ptr) ip, (Ptr) op, nafter * sizeof(INTEGER));
						    /* move the after rows */
	while (--noffsets >= 0)
	    *--op = CW(offset);

	p.h = Hx(list, cellSize.h);
	p.v = Hx(list, cellSize.v);
	C_LCellSize(p, list);		/* recalcs visible */

	if (Hx(list, listFlags) & DODRAW) {
	    todraw = HxX(list, dataBounds);
	    todraw.top = CW(rown);
	    SectRect(&todraw, &HxX(list, visible), &todraw);
	    for (c.v = CW(todraw.top) ; c.v < CW(todraw.bottom); c.v++)
		for (c.h = CW(todraw.left) ; c.h < CW(todraw.right); c.h++)
		    C_LDraw(c, list);
	}
	TRAPEND();
    }
    return rown;
}

PRIVATE void
compute_visible_rect (Rect *rp, ListHandle list, INTEGER top, INTEGER left,
     INTEGER bottom, INTEGER right)
{
  INTEGER h, v;
  INTEGER new_top, new_left, new_bottom, new_right;

  h = Hx (list, cellSize.h);
  v = Hx (list, cellSize.v);

  new_top    = Hx (list, rView.top ) + (top  - Hx (list, visible.top )) * v;
  new_left   = Hx (list, rView.left) + (left - Hx (list, visible.left)) * h;
  new_bottom = new_top  + (bottom - top ) * v;
  new_right  = new_left + (right  - left) * h;

  rp->top    = CW (new_top);
  rp->left   = CW (new_left);
  rp->bottom = CW (new_bottom);
  rp->right  = CW (new_right);

  SectRect (rp, &HxX (list, rView), rp);
}

P3(PUBLIC pascal trap, void, LDelColumn, INTEGER, count,	/* IMIV-271 */
					      INTEGER, coln, ListHandle, list)
{
    Rect todraw;
    Cell c;
    INTEGER ncols, nrows, noffsets, delta;
    Size nbefore, nafter, ntomove;
    unsigned short int *ip, *op;	/* unsigned INTEGER */
    Ptr dataip, dataop;
    INTEGER off1, off2, off3, off4, off5;
    int i;
    ControlHandle control;
    Point p;

    if (!list || coln >= Hx(list, dataBounds.right))
/*-->*/	return;			/* invalid */

    if (count == 0 || (coln == Hx(list, dataBounds.left) &&
	      count >= Hx(list, dataBounds.right) - Hx(list, dataBounds.left))) {
	SetHandleSize((Handle) HxP(list, cells), (Size) 0);
	SetHandleSize((Handle) list, sizeof(ListRec));
	HxX(list, cellArray)[0] = 0;
	HxX(list, dataBounds.right) = HxX(list, dataBounds.left);
	HxX(list, visible.left)  = HxX(list, dataBounds.left);
	p.h = Hx(list, cellSize.h);
	p.v = Hx(list, cellSize.v);
	C_LCellSize(p, list);		/* recalcs visible */
	if (Hx(list, listFlags) & DODRAW)
	    EraseRect(&HxX(list, rView));
	if ((control = HxP(list, hScroll)))
	    SetCtlMax(control, Hx(control, contrlMin));
/*-->*/	return;		/* quick delete of everything */
    }

    if (coln + count > Hx(list, dataBounds.right))
	count = Hx(list, dataBounds.right) - coln;

    nrows = Hx(list, dataBounds.bottom) - Hx(list, dataBounds.top);
    noffsets = count * nrows;
    if (coln > Hx(list, dataBounds.right))
	coln = Hx(list, dataBounds.right);

    HxX(list, dataBounds.right) = CW(Hx(list, dataBounds.right) - count);

    if (noffsets) {
        INTEGER visible_right, bounds_right;

	TRAPBEGIN();
	ncols = Hx(list, dataBounds.right) - Hx(list, dataBounds.left);
	nbefore = (coln - Hx(list, dataBounds.left));
	nafter  = ncols - nbefore;
	ip = op = (unsigned short int *) HxX(list, cellArray);
	dataip = dataop = (Ptr) STARH(HxP(list, cells));
	delta = 0;
	/* SPEEDUP:  partial loop unrolling ... combine things and don't
		     bother adding delta when we know that it's zero */
	while (--nrows >= 0) {
	    off1 = CW(*ip) & 0x7FFF;
	    for (i = nbefore; --i >= 0; )	/* copy before-offsets */
		*op++ = CW(CW(*ip++) - delta);

	    off2 = CW(*ip) & 0x7FFF;
	    ntomove = off2 - off1;
	    BlockMove(dataip, dataop, ntomove);	/* copy before-data */
	    dataip += ntomove;
	    dataop += ntomove;

	    ip += count;			/* skip count offsets */

	    off3 = CW(*ip) & 0x7FFF;
	    ntomove = off3 - off2;
	    dataip += ntomove;			/* skip appropriate data */
	    delta  += ntomove;			/* note this */

	    off4 = CW(*ip) & 0x7FFF;
	    for (i = nafter; --i >= 0; )	/* copy after-offsets */
		*op++ = CW(CW(*ip++) - delta);

	    off5 = CW(*ip) & 0x7FFF;
	    ntomove = off5 - off4;
	    BlockMove(dataip, dataop, ntomove);	/* copy before-data */
	    dataip += ntomove;
	    dataop += ntomove;
	}
	*op++ = CW(CW(*ip++) - delta);	/* sentinel */
	SetHandleSize((Handle) list,
		    GetHandleSize((Handle) list) - noffsets * sizeof(INTEGER));
	SetHandleSize((Handle) HxP(list, cells),
			       GetHandleSize((Handle) HxP(list, cells)) - delta);

	p.h = Hx(list, cellSize.h);
	p.v = Hx(list, cellSize.v);


	/* save visible_right and bounds_right now, because LCellSize
	   will adjust them and we won't be able to figure out if we
	   needed to force a scroll */

	visible_right = Hx(list, visible.right);
	bounds_right = Hx(list, dataBounds.right);
	C_LCellSize(p, list);		/* recalcs visible */
	if ((control = HxP(list, hScroll))) {
	    INTEGER visible_left;

	    visible_left = Hx(list, visible.left);

	    /* Determine whether or not we need to scroll up one location
	       (because we were maximally scrolled down and we deleted
	       something that was visible) */

	    if (visible_left > 0 && visible_right > bounds_right) {
	      --visible_left;
	      HxX(list, visible.left) = CW (visible_left);
	      coln = visible_left;
	    }
	}

	if (Hx(list, listFlags) & DODRAW) {
	    Rect eraser;

	    compute_visible_rect (&eraser, list, Hx (list, visible.top),
				  Hx (list, visible.right),
				  Hx (list, visible.bottom),
				  visible_right);
	    EraseRect (&eraser);

	    todraw = HxX(list, dataBounds);
	    todraw.left = CW(coln);
	    SectRect(&todraw, &HxX(list, visible), &todraw);
	    for (c.v = CW(todraw.top) ; c.v < CW(todraw.bottom); c.v++)
		for (c.h = CW(todraw.left) ; c.h < CW(todraw.right); c.h++)
		    C_LDraw(c, list);
	}
	TRAPEND();
    }
}

P3(PUBLIC pascal trap, void, LDelRow, INTEGER, count,		/* IMIV-272 */
					      INTEGER, rown, ListHandle, list)
{
    Rect todraw;
    Cell c;
    INTEGER ncols, nrows, noffsets;
    Size nbefore, nafter;
    unsigned short int *ip, *op;
    ControlHandle control;
    INTEGER off1, off2, off3;
    Size delta, ntomove;
    Point p;

    if (!list || rown >= Hx(list, dataBounds.bottom))
/*-->*/	return;			/* invalid */

    if (count == 0 || (rown == Hx(list, dataBounds.top) &&
	      count >= Hx(list, dataBounds.bottom) - Hx(list, dataBounds.top))) {
	SetHandleSize((Handle) HxP(list, cells), (Size) 0);
	SetHandleSize((Handle) list, sizeof(ListRec));
	HxX(list, cellArray)[0] = CWC(0);
	HxX(list, dataBounds.bottom) = HxX(list, dataBounds.top);
	HxX(list, visible.top)  = HxX(list, dataBounds.top);
	p.h = Hx(list, cellSize.h);
	p.v = Hx(list, cellSize.v);
	C_LCellSize(p, list);		/* recalcs visible */
	if (Hx(list, listFlags) & DODRAW)
	    EraseRect(&HxX(list, rView));
	if ((control = HxP(list, vScroll)))
	    SetCtlMax(control, Hx(control, contrlMin));
/*-->*/	return;	/* quick delete of all */
    }

    if (rown + count > Hx(list, dataBounds.bottom))
	count = Hx(list, dataBounds.bottom) - rown;

    ncols = Hx(list, dataBounds.right) - Hx(list, dataBounds.left);
    noffsets = count * ncols;

    HxX(list, dataBounds.bottom) = CW(Hx(list, dataBounds.bottom) - count);

    if (noffsets) {
        INTEGER visible_bottom, bounds_bottom;

	TRAPBEGIN();
	nrows = Hx(list, dataBounds.bottom) - Hx(list, dataBounds.top);
	nbefore = (rown - Hx(list, dataBounds.top)) * ncols;
	nafter  = nrows * ncols  - nbefore;
	ip = op = (unsigned short int *) HxX(list, cellArray) + nbefore;
	ip += noffsets;
	off1 = CW(*op) & 0x7FFF;
	off2 = CW(*ip) & 0x7FFF;
	delta = off2 - off1;

	while (--nafter >= 0)
	    *op++ = CW(CW(*ip++) - delta);
	off3 = CW(*ip) & 0x7FFF;
	*op = CW(CW(*ip) - delta);	/* sentinel */

	ntomove = off3 - off2;
	BlockMove((Ptr) STARH(HxP(list, cells)) + off2,
			       (Ptr) STARH(HxP(list, cells)) + off1, ntomove);

	SetHandleSize((Handle) list,
		    GetHandleSize((Handle) list) - noffsets * sizeof(INTEGER));
	SetHandleSize((Handle) HxP(list, cells),
			       GetHandleSize((Handle) HxP(list, cells)) - delta);

	p.h = Hx(list, cellSize.h);
	p.v = Hx(list, cellSize.v);

	/* save visible_bottom and bounds_bottom now, because LCellSize
	   will adjust them and we won't be able to figure out if we
	   needed to force a scroll */

	visible_bottom = Hx(list, visible.bottom);
	bounds_bottom = Hx(list, dataBounds.bottom);
	C_LCellSize(p, list);		/* recalcs visible */
	if ((control = HxP(list, vScroll))) {
	    INTEGER visible_top;

	    visible_top = Hx(list, visible.top);

	    /* Determine whether or not we need to scroll up one location
	       (because we were maximally scrolled down and we deleted
	       something that was visible) */

	    if (visible_top > 0 && visible_bottom > bounds_bottom) {
	      --visible_top;
	      HxX(list, visible.top) = CW (visible_top);
	      rown = visible_top;
	    }
	}

	if (Hx(list, listFlags) & DODRAW) {
	    Rect eraser;

	    compute_visible_rect (&eraser, list, Hx (list, visible.bottom),
				  Hx (list, visible.left),  visible_bottom,
				  Hx (list, visible.right));
	    EraseRect (&eraser);

	    todraw = HxX(list, dataBounds);
	    todraw.top = CW(rown);
	    SectRect(&todraw, &HxX(list, visible), &todraw);

	    for (c.v = CW(todraw.top) ; c.v < CW(todraw.bottom); c.v++)
		for (c.h = CW(todraw.left) ; c.h < CW(todraw.right); c.h++)
		    C_LDraw(c, list);
	}
	TRAPEND();
    }
}
