#define __USE_SYSBASE 1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <dos.h>
#include <dos/dos.h>
#include <exec/memory.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h>
#include <intuition/intuition.h>
#include <devices/timer.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <clib/alib_protos.h>
#include <pragmas/blitzblank_pragmas.h>

#include <BlitzBlank.h>

struct Library *BlitzBlankBase;
static const char version[]="$VER: BB.Lines 2.60 (22.04.95)";

char *text[]={"\33c\33uLines\33n\n\nModule for BlitzBlank\n\nCopyright 1995\nby\nThomas Börkel",
              "_Lines:",
              "_Delay:"};

struct BB_Object object[]={ {&object[1],BB_VGroup,0,0,0,NULL,NULL},
                            {&object[2],BB_Slider,5,200,50,NULL,NULL},
                            {&object[3],BB_Slider,0,500,0,NULL,NULL},
                            {NULL      ,BB_VGroup_End,0,0,0,NULL,NULL} };

struct line
{
  int x1;
  int y1;
  int x2;
  int y2;
  int c;
};


struct BB_Message message;
struct BB_Screeninfo *screeninfo;
struct RastPort *rp;
struct line *li;
int dx1,dy1,dx2,dy2;


struct timerequest* inittimer (struct MsgPort *timerport)
{
  struct timerequest *timerio;
  if ((timerio=CreateIORequest (timerport,sizeof (struct timerequest))))
    if (!(OpenDevice ("timer.device",UNIT_MICROHZ,(struct IORequest *) timerio,0)))
      timerio->tr_node.io_Command=TR_ADDREQUEST;
  return (timerio);
}


void waittimer (struct timerequest *timerio,int sec,int mic)
{
  if (timerio)
  {
    timerio->tr_time.tv_secs=sec;
    timerio->tr_time.tv_micro=mic;
    DoIO ((struct IORequest *) timerio);
  }
  return;
}


/* may only be called, if starttimer() was called before */
void stoptimer (struct timerequest *timerio)
{
  if (timerio)
  {
    AbortIO ((struct IORequest *) timerio);
    WaitIO ((struct IORequest * ) timerio);
  }
  return;
}


/* may only be called, if no timerequest is pending */
void deletetimer (struct timerequest *timerio)
{
  if (timerio)
  {
    CloseDevice ((struct IORequest *) timerio);
    DeleteIORequest ((struct IORequest *) timerio);
  }
  return;
}


int sgn (long a)
{
  if (a<0)
    return (-1);
  if (a>0)
    return (1);
  return (0);
}


void check (int i)
{
  if (li[i].x1>screeninfo->width-1 || li[i].x1<0)
  {
    dx1=-dx1;
    li[i].x1+=2*dx1;
  }
  if (li[i].y1>screeninfo->height-1 || li[i].y1<0)
  {
    dy1=-dy1;
    li[i].y1+=2*dy1;
  }
  if (li[i].x2>screeninfo->width-1 || li[i].x2<0)
  {
    dx2=-dx2;
    li[i].x2+=2*dx2;
  }
  if (li[i].y2>screeninfo->height-1 || li[i].y2<0)
  {
    dy2=-dy2;
    li[i].y2+=2*dy2;
  }
  return;
}


void blank (void)
{
  int i,colors,al,w=3,s=1,co=1,ch,stop=FALSE,v;
//  struct ViewPort *vp;
  struct DateStamp ds;
  struct MsgPort *timerport;
  struct timerequest *timerio;

  al=object[1].set;

  if (!(li=calloc (al+1,sizeof (struct line)))) return;

  if ((timerport=CreateMsgPort ()))
  {
    if ((timerio=inittimer (timerport)))
    {


      colors=1<<screeninfo->depth;
      rp=&screeninfo->bbscreen->RastPort;
    //  vp=&screeninfo->bbscreen->ViewPort;

      DateStamp (&ds);
      srand48 (ds.ds_Minute*60+ds.ds_Tick);
    /*
      SetRGB4 (vp,0,0,0,0);
      SetRGB4 (vp,1,15,0,0);
      if (colors>2)
      {
        SetRGB4 (vp,2,0,0,15);
        SetRGB4 (vp,3,0,15,0);
        if (colors>4)
        {
          SetRGB4 (vp,4,0,5,0);
          SetRGB4 (vp,5,15,3,8);
          SetRGB4 (vp,6,15,5,15);
          SetRGB4 (vp,7,5,15,8);
          if (colors>8)
          {
            SetRGB4 (vp,8,10,5,0);
            SetRGB4 (vp,9,0,15,5);
            SetRGB4 (vp,10,15,7,15);
            SetRGB4 (vp,11,0,7,15);
            SetRGB4 (vp,12,8,15,3);
            SetRGB4 (vp,13,15,10,5);
            SetRGB4 (vp,14,7,0,15);
            SetRGB4 (vp,15,3,8,15);
            if (colors>16)
              for (i=16;i<colors;i++)
                SetRGB4 (vp,i,(long) (drand48 ()*13+3),(long) (drand48 ()*13+3),(long) (drand48 ()*13+3));
          }
        }
      }
    */

      BBL_RainbowPalette (screeninfo->bbscreen,1,colors-1);

      ch=al/colors;
      if (ch==0)
        ch=1;

      dx1=drand48 ()*w+s;
      dy1=drand48 ()*w+s;
      dx2=drand48 ()*w+s;
      dy2=drand48 ()*w+s;

      li[0].x1=drand48 ()*screeninfo->width;
      li[0].y1=drand48 ()*screeninfo->height;
      li[0].x2=drand48 ()*screeninfo->width;
      li[0].y2=drand48 ()*screeninfo->height;

      ScreenToFront (screeninfo->bbscreen);

    /*
      for (i=0;i<colors;i++)
      {
        SetAPen (rp,i);
        Move (rp,i,0);
        Draw (rp,i,100);
      }

      Delay (200);
    */

      if (!CheckSignal (SIGBREAKF_CTRL_C))
      {
        BBL_ModuleRunning ();

        for (i=1;i<al;i++)
        {
    //      if (object[2].set)
    //        TimeDelay (UNIT_MICROHZ,0,object[2].set*100);
          if (object[2].set)
            waittimer (timerio,0,object[2].set*100);
          li[i].x1=li[i-1].x1+dx1;
          li[i].y1=li[i-1].y1+dy1;
          li[i].x2=li[i-1].x2+dx2;
          li[i].y2=li[i-1].y2+dy2;
          check (i);
          if (i%ch==0)
          {
            co++;
            if (co>colors-1)
              co=1;
          }
          SetAPen (rp,co);
          Move (rp,li[i].x1,li[i].y1);
          Draw (rp,li[i].x2,li[i].y2);
          if (CheckSignal (SIGBREAKF_CTRL_C))
          {
            i=al-1;
            stop=TRUE;
          }
        }

        if (!stop && !CheckSignal (SIGBREAKF_CTRL_C))
        {
          i=0;
          v=al-1;
          do
          {
    //        if (object[2].set)
    //          TimeDelay (UNIT_MICROHZ,0,object[2].set*100);
            if (object[2].set)
              waittimer (timerio,0,object[2].set*100);
            SetAPen (rp,0);
            Move (rp,li[i].x1,li[i].y1);
            Draw (rp,li[i].x2,li[i].y2);
            li[i].x1=li[v].x1+dx1;
            li[i].y1=li[v].y1+dy1;
            li[i].x2=li[v].x2+dx2;
            li[i].y2=li[v].y2+dy2;
            check (i);
            if (i%ch==0)
            {
              co++;
              if (co>colors-1)
                co=1;
            }
            SetAPen (rp,co);
            Move (rp,li[i].x1,li[i].y1);
            Draw (rp,li[i].x2,li[i].y2);
            i++;
            if (i>al-1)
            {
              i=0;
              dx1=sgn(dx1)*(drand48 ()*w+s);
              dy1=sgn(dy1)*(drand48 ()*w+s);
              dx2=sgn(dx2)*(drand48 ()*w+s);
              dy2=sgn(dy2)*(drand48 ()*w+s);
            }
            v++;
            if (v>al-1)
              v=0;
          } while (!CheckSignal (SIGBREAKF_CTRL_C));
        }
      }
      deletetimer (timerio);
    }
    DeleteMsgPort (timerport);
  }
  return;
}


void main(int argc,char **argv)
{

  if (!(BlitzBlankBase=OpenLibrary ("blitzblank.library",BLITZBLANKLIB_VER)))
    exit (0);

  message.flags=BBF_Screenmode|BBF_Colors;
  message.first=&object[0];
  StrToLong (argv[3],(long *) &screeninfo);
  screeninfo->maxdepth=8;

  if (strcmp (argv[1],"BLANK")==0)
  {
    BBL_SendMessage (&message,argv[2]);
    if (screeninfo->bbscreen)
      blank ();
    BBL_BlankDone ();
  }
  else
  {
    message.infotext=BBL_GetString (270,text[0]);
    object[1].label=BBL_GetString (271,text[1]);
    object[2].label=BBL_GetString (272,text[2]);
    if (strcmp (argv[1],"CONFIG")==0)
    {
      BBL_SendMessage (&message,argv[2]);
    }
    else
    {
      message.first=NULL;
      BBL_SendMessage (&message,argv[2]);
    }
  }
  CloseLibrary (BlitzBlankBase);
  exit (0);
}

