/*************************
 *        Boxes.C        *
 * by Tobias Ferber 1989 *
 *************************/

#include <exec/types.h>
#include <exec/ports.h>
#include <exec/memory.h>
#include <exec/libraries.h>
#include <libraries/dos.h>
#include <graphics/gfxbase.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>

#include <stdio.h>
#include <time.h>

#ifdef USE_TIMER_DEVICE
#include "timer.h"
struct timerequest *tr= (struct timerequest *)NULL;
struct MsgPort *tp;  /* tr's reply port */
#define MICROSPEED 5L  /* call PaintRect() every ... micro seconds */
#endif

struct NewWindow nw= {
  0,0,200,100,-1,-1,
  CLOSEWINDOW

#ifndef USE_TIMER_DEVICE
  | INTUITICKS
#endif

  | NEWSIZE,
  WINDOWCLOSE|WINDOWDEPTH|WINDOWDRAG|WINDOWSIZING|RMBTRAP|NOCAREREFRESH|ACTIVATE,
  NULL,NULL,(UBYTE *)"Boxes",
  NULL,NULL,
  0,0,-1,-1,
  WBENCHSCREEN
};

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Window *w;
short xmin, xmax, ymin, ymax, pens;

void RethinkWindowDimensions(void)
{ xmin= w->BorderLeft;
  xmax= w->Width - w->BorderRight;
  ymin= w->BorderTop +1;
  ymax= w->Height - w->BorderBottom;
  pens= 1L << w->WScreen->RastPort.BitMap->Depth;
}

void CloseStuff(void)
{
  if(tr)
  { purge_timer(tr);
    close_timer(tr);
  }

  if(w)
  { CloseWindow(w);
    w= (struct Window *)NULL;
  }

  if(IntuitionBase) CloseLibrary(IntuitionBase);
  if(GfxBase) CloseLibrary(GfxBase);
}

int OpenStuff(void)
{ struct Screen s;

  GfxBase= (struct GfxBase *)OpenLibrary("graphics.library",0L);
  if(!GfxBase) return 1;
  IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0L);
  if(!IntuitionBase) return 2;
  if(GetScreenData(&s,sizeof(struct Screen),WBENCHSCREEN,NULL))
  {
    /* GetScreenData() lies about dimensions */
    s.Width= s.ViewPort.DWidth;
    s.Height= s.ViewPort.DHeight;

    if((nw.LeftEdge= s.MouseX - nw.Width/2) < 0)
      nw.LeftEdge= 0;
    else if(nw.LeftEdge + nw.Width > s.Width)
      nw.LeftEdge= s.Width - nw.Width;

    if((nw.TopEdge= s.MouseY - nw.Height/2) < 0)
      nw.TopEdge= 0;
    else if(nw.TopEdge+nw.Height > s.Height)
      nw.TopEdge= s.Height - nw.Height;
  }
  else return 3;

  w= (struct Window *)OpenWindow(&nw);

  if(!w)
    return 4;

  RethinkWindowDimensions();

#ifdef USE_TIMER_DEVICE
  tr= open_timer(NULL,0L);

  if(!tr)
    return 7;

  tp= tr->tr_node.io_Message.mn_ReplyPort;
  queue_timer(tr,0,1);
#endif /* USE_TIMER_DEVICE */

  return 0;
}

void PaintRect(void)
{
  register long x0,y0,x1,y1,p,t;

  time(&t);
  srand(t*270970*rand(42));

  x0= xmin + ( ((t*rand(t)) & 0x7FFF) % (xmax-xmin-4) );
  y0= ymin + ( ((x0*rand(x0)) & 0x7FFF ) % (ymax-ymin-4) );

  x1= x0+1 + ( ((y0*rand(y0)) & 0x7FFF ) % (xmax-x0-2) );
  y1= y0+1 + ( ((x1*rand(x1)) & 0x7FFF ) % (ymax-y0-2) );

  p= ((t+(y1*rand(y1))) & 0x7F) % pens;

  /*printf("[%d] (%d,%d) - (%d,%d)\n",p, x0,y0, x1,y1);*/

  SetAPen(w->RPort, (UBYTE)p);
  RectFill(w->RPort, (SHORT)x0,(SHORT)y0, (SHORT)x1,(SHORT)y1);
}

BOOL HandleIDCMP()
{
  BOOL done= FALSE;
  struct IntuiMessage *imsg;
  ULONG class;
  long usersigmask  = 1L << w->UserPort->mp_SigBit,
       breaksigmask = SIGBREAKF_CTRL_C,

#ifdef USE_TIMER_DEVICE
       timersigmask = 1L << tp->mp_SigBit,
       sig= Wait(usersigmask | breaksigmask | timersigmask);
#else
       sig= Wait(usersigmask | breaksigmask);
#endif

  done |= (sig & breaksigmask);

#ifdef USE_TIMER_DEVICE
  if(sig & timersigmask)
  { while( GetMsg(tp) )
      ;
    PaintRect();
    if(CheckIO((struct IORequest *)&tr->tr_node))
      queue_timer(tr,0,MICROSPEED);
  }
#endif

  if(sig & usersigmask)
  { while(imsg=(struct IntuiMessage *)GetMsg(w->UserPort))
    { class = imsg->Class;
      ReplyMsg(imsg);

      switch(class)
      {
        case CLOSEWINDOW:
          done= TRUE;
          break;
        case NEWSIZE:
          SetRast(w->RPort,0L);
          RefreshWindowFrame(w);
          RethinkWindowDimensions();
          break;

#ifndef USE_TIMER_DEVICE
        case INTUITICKS:
          PaintRect();
          break;
#endif
      }
    }
  }
  return done;
}

void main(void)
{
  int err= OpenStuff();

  if(!err)
  { while( !HandleIDCMP() )
      ;
    CloseStuff();
  }
  exit(err);
}

#ifdef _DCC
wbmain(void) { main(); }
#endif
