#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/ports.h>
#include <graphics/gfx.h>
#include <graphics/clip.h>
#include <graphics/view.h>
#include <graphics/rastport.h>
#include <graphics/layers.h>
#include <intuition/intuition.h>

#define COPY	NANBC|NABC|ABNC|ABC

long seed[] = {0xB807C324, 0x9E8732B5, 0x4E50957BC};

/* random number generator */

rand(i)
register short i;
{
    seed[i] = seed[i] < 0 ? seed[i] << 1 ^ 0x1D872B41 : seed[i] << 1;
    return(seed[i]);
}

#define RWidth	Get_RWidth(w)
#define RHeight Get_RHeight(w)
#define MAX_CLOSEWINDOW 1

/* #define DEBUG */
/* #define KPRINTF */

#ifdef KPRINTF
#define printf kprintf
#endif

int close_count;

extern struct Gadget *vgadget_ptr;
extern struct Gadget *hgadget_ptr;

lbnc(w)
struct RastPort *w;
{
    register long i;
    short lx,ly,lvx,lvy;
    short rx,ry,rvx,rvy;
    short clrDepth,linDepth;
    struct Layer *l;
    int counter;
    int lcounter;
    int xoffset,yoffset;
    struct Window *window;
    struct IntuiMessage *message;

    close_count = MAX_CLOSEWINDOW;
    counter = 0;
    lcounter = 0;
    l = w->Layer;
    lx = 0; ly = 0;
    rx = 30;	ry = 10;
    lvx = 2;	lvy = 3;
    rvx = 5;	rvy = 7;
    clrDepth = 320;
    linDepth = 160;
    SetDrMd(w,1);

    xoffset = Get_xoffset(w);
    yoffset = Get_yoffset(w);

#ifdef DEBUG
    printf("xoffset = %ld yoffset = %ld\n",xoffset,yoffset);
#endif
    if (l)  window = l->Window;

restart:
    while ((message = (struct IntuiMessage *)GetMsg(window->UserPort)) == 0)
    {
	if (clrDepth-- == 0)
	{
	    clrDepth = 320;
	    SetAPen(w,w->FgPen+1);
	}

	if (linDepth-- == 0)
	{
	    newvel(&lvx);
	    newvel(&lvy);
	    newvel(&rvx);
	    newvel(&rvy);
	    linDepth = 320;
	}

	Move(w,xoffset+lx,yoffset+ly);
	Draw(w,xoffset+rx,yoffset+ry);
	lx += lvx;  ly += lvy;
	rx += rvx;  ry += rvy;
	if (lx<0)   zbounce(&lx,&lvx);
	if (rx<0)   zbounce(&rx,&rvx);
	if (ly<0)   zbounce(&ly,&lvy);
	if (ry<0)   zbounce(&ry,&rvy);
	if (lx>RWidth-1)    mbounce(&lx,&lvx,RWidth-1);
	if (ly>RHeight-1)   mbounce(&ly,&lvy,RHeight-1);
	if (rx>RWidth-1)    mbounce(&rx,&rvx,RWidth-1);
	if (ry>RHeight-1)   mbounce(&ry,&rvy,RHeight-1);
endit:
	;
    }

    switch (message->Class)
    {

	case CLOSEWINDOW :
	{
	    ReplyMsg(message);
	    return;
	}

	case GADGETDOWN:
	{ 
	    struct IntuiMessage copymsg;

	    /* copy all fields */
	    copymsg = *message;

	    /* reply to original */
	    ReplyMsg(message);

	    /* smooth-scroll until gadget is released */
	    {
		ULONG old_idcmp_flags;
		ULONG new_idcmp_flags;

		/* save old idcmp_flags */

		old_idcmp_flags = copymsg.IDCMPWindow->IDCMPFlags;

		/* listen for ticks as long as gadget is down */

		new_idcmp_flags = (old_idcmp_flags | INTUITICKS);

		ModifyIDCMP(copymsg.IDCMPWindow,new_idcmp_flags);

		/* loop for intuiticks messages */

		{
		    struct IntuiMessage *loopmsg;

		    while((loopmsg =  (struct IntuiMessage *) WaitPort(copymsg.IDCMPWindow->UserPort)) && (loopmsg->Class == INTUITICKS))
		    {
			if(loopmsg = (struct IntuiMessage *)GetMsg(copymsg.IDCMPWindow->UserPort))
			{
			    ReplyMsg(loopmsg);

			    do_gadget_up(&copymsg);

			    /* draw after smooth scrolling */
			    {

				if (clrDepth-- == 0)
				{
				    clrDepth = 320;
				    SetAPen(w,w->FgPen+1);
				}

				if (linDepth-- == 0)
				{
				    newvel(&lvx);
				    newvel(&lvy); 
				    newvel(&rvx);
				    newvel(&rvy);
				    linDepth = 320;
				}

				Move(w,xoffset+lx,yoffset+ly);
				Draw(w,xoffset+rx,yoffset+ry);
				lx += lvx;  ly += lvy;
				rx += rvx;  ry += rvy;
				if (lx<0)   zbounce(&lx,&lvx);
				if (rx<0)   zbounce(&rx,&rvx);
				if (ly<0)   zbounce(&ly,&lvy);
				if (ry<0)   zbounce(&ry,&rvy);
				if (lx>RWidth-1)    mbounce(&lx,&lvx,RWidth-1);
				if (ly>RHeight-1)   mbounce(&ly,&lvy,RHeight-1);
				if (rx>RWidth-1)    mbounce(&rx,&rvx,RWidth-1);
				if (ry>RHeight-1)   mbounce(&ry,&rvy,RHeight-1);

			    }
			    /* done drawing */

			}

		    }

		    /* next message was not a tick */
		}

		/* restore old idcmp_flags */

		ModifyIDCMP(copymsg.IDCMPWindow,old_idcmp_flags);
	  }

	}
	break;

	case GADGETUP: 
	{
	    struct IntuiMessage copymsg;

	    /* copy all fields */
	    copymsg = *message;

	    /* reply to original */
	    ReplyMsg(message);

	    /* process message */
	    do_gadget_up(&copymsg);
	}
	break;

	case SIZEVERIFY:
	{
	    ReplyMsg(message);

	    /* wait for newsize */
	    WaitPort(window->UserPort);
	}
	break;

	case NEWSIZE:
	{
	    struct IntuiMessage copymsg;

	    /* copy all fields */
	    copymsg = *message;

	    /* reply to original */
	    ReplyMsg(message);

	    /* provide vertical gadget address */
	    copymsg.IAddress = vgadget_ptr;

	    /* set vertical scroll */
	    do_gadget_up(&copymsg);

	    /* bart - 04.23.86 */
	    /* re-calculate vertical pot body for new size */
	    {
		struct Window *w; 
		struct RastPort *rp;
		struct Layer *l;

		if(w = copymsg.IDCMPWindow)
		{
		    if(rp = w->RPort)
		    {
			if(l = rp->Layer)
			{
			    struct PropInfo *pi;
			    UWORD sb_height;
			    ULONG rel_body;
		 
			    pi = (struct PropInfo *)vgadget_ptr->SpecialInfo;
						
			    sb_height = l->SuperBitMap->Rows;

			    rel_body=(MAXPOT*(usable_height(w)))/(sb_height);

			    ModifyProp(vgadget_ptr,
				       window,
				       NULL,
				       pi->Flags,
				       pi->HorizPot,
				       pi->VertPot,
				       pi->HorizBody,
				       rel_body);
			}
		    }
		}
	    }

	    /* provide vertical gadget address */
	    copymsg.IAddress = hgadget_ptr;

	    /* set horizontal scroll */
	    do_gadget_up(&copymsg);

	    /* bart - 04.23.86 */
	    /* re-calculate horizontal pot body for new size */

	    {
		struct Window *w; 
		struct RastPort *rp;
		struct Layer *l;

		if(w = copymsg.IDCMPWindow)
		{
		    if(rp = w->RPort)
		    {
			if(l = rp->Layer)
			{
			    struct PropInfo *pi;
			    UWORD bb_width;
			    ULONG rel_body;
		 
			    pi = (struct PropInfo *)hgadget_ptr->SpecialInfo;
						    
			    bb_width = l->SuperBitMap->BytesPerRow << 3;

			    rel_body=(MAXPOT*(usable_width(w)))/(bb_width);

			    ModifyProp(hgadget_ptr,
				       window,
				       NULL,
				       pi->Flags,
				       pi->HorizPot,
				       pi->VertPot,
				       rel_body,
				       pi->VertBody);
			}
		    }
		}
	    }
	}
	break;

	default:
	{
	    ReplyMsg(message);
	}
	break;

    }

    goto restart;

}

newvel(v)
short *v;
{
    *v = (15 & rand(0)) - 7;
}

zbounce(p,v)
short *p,*v;
{
    *p = -*p;
    *v = -*v;
}

mbounce(p,v,c)
short *p,*v;
short c;
{
    *p = 2*c - *p;
    *v = -*v;
}


