/* !RunImage.c
Provides a demo of TMT at work
by N. Douglas
Started: 30-11-1996
Last updated: 16-01-1998 version 0.26

Requires TMTMod to be linked in with it as this provides the Win32 thunking
layer
*/

#include "TMTMod.h"
#include "kernel.h"
#include <stdlib.h>
#include <string.h>

typedef struct ROINITIALISEBLK
{
  int rovers;			/* RO version */
  int wimpvers;			/* Wimp version */
  int tnvers;			/* Support module version */
  char *taskname;		/* RO Wimp task name */
  function handler;		/* address of 17, 18 & 19 handler */
  int taskh;			/* RO Wimp task handle */

} ROINITIALISEBLK;

static BOOL quit=FALSE;
static char indir[256];
static char templ[1024];
static char menus[256];
static int windh,infoh;
static char *sp;
static const char spname[]="Sprite";
static char *savearea;
static char sc[16];
static char pix[16*4];
static char halt=FALSE;

#define FRAMES 1/*5000*/
#define XOR_SPECIAL 0x1d872b41
static unsigned int seed=0xabcdef12;

int codeshandler(int, int);
int codeshandler2(int, int);
void CreateNewWindow(void);
void UpdateWindow(void);
unsigned int rnd(int);
void ModeChange(void);
void RedrawWindow(_kernel_swi_regs);
void ROInitialise(ROINITIALISEBLK *);
void ROClosedown(int);
int ROReportError(int, int *);
int ROReportErrora(int, int, char *);
void StdErrHandlr(_kernel_oserror *);
void ROSetPollMask(int);

int main(void)
{
  ROINITIALISEBLK blk;
  char taskname[]="Wimp2 Demo";
  char q[256];
  _kernel_swi_regs r;
  int icbarh;
  int count=rnd(FRAMES);

  blk.rovers=200;
  blk.wimpvers=200;
  blk.tnvers=010;
  blk.taskname=taskname;
  blk.handler=(function) codeshandler;

  ROInitialise(&blk);

  /* Now we're being preempted */

  /* Load some templates */
  {
    const char templatenm[]="<Wimp2Demo$Dir>.Templates";
    const char main[]="main";
    const char info[]="info";

    r.r[1]=(int) templatenm;
    StdErrHandlr(_kernel_swi(Wimp2_OpenTemplate, &r, &r));

    r.r[1]=(int) templ;
    r.r[2]=(int) indir;
    r.r[3]=(int) indir+256;
    r.r[4]=-1;
    r.r[5]=(int) info;
    r.r[6]=0;
    StdErrHandlr(_kernel_swi(0x400db/*Wimp_LoadTemplate*/, &r, &r));
    StdErrHandlr(_kernel_swi(0x400c1/*Wimp_CreateWindow*/, &r, &r));
    infoh=r.r[0];

    r.r[1]=(int) templ;
    r.r[4]=-1;
    r.r[5]=(int) main;
    r.r[6]=0;
    StdErrHandlr(_kernel_swi(0x400db/*Wimp_LoadTemplate*/, &r, &r));

    StdErrHandlr(_kernel_swi(Wimp2_CloseTemplate, &r, &r));
  }

  /* Put an icon on the icbar */
  {
    const char icname[]="!wimp2demo";

    *(int *)(q+0)=-1;
    *(int *)(q+4)=0;
    *(int *)(q+8)=0;
    *(int *)(q+12)=68;
    *(int *)(q+16)=68;
    *(int *)(q+20)=0x1700301a;
    *(int *)(q+24)=*(int *) (icname+0);
    *(int *)(q+28)=*(int *) (icname+4);
    *(int *)(q+32)=*(int *) (icname+8);
    r.r[1]=(int) q;
    StdErrHandlr(_kernel_swi(0x400c2/*Wimp_CreateIcon*/, &r, &r));
    icbarh=r.r[0];
  }

  StdErrHandlr(_kernel_swi(0x42/*OS_ReadMonotonicTime*/, &r, &r));
  seed=r.r[0];

  CreateNewWindow();
  UpdateWindow();
  ModeChange();

  r.r[1]=(int) q;
  *(int *)(q+0)=windh;
  StdErrHandlr(_kernel_swi(0x400cb/*Wimp_GetWindowState*/, &r, &r));
  {
    int dx=(*(int *)(q+12))-(*(int *)(q+4)),dy=(*(int *)(q+16))-(*(int *)(q+8));
    *(int *)(q+4)=rnd(640);
    *(int *)(q+8)=rnd(512);
    *(int *)(q+12)=(*(int *)(q+4))+dx;
    *(int *)(q+16)=(*(int *)(q+8))+dy;
  }
  StdErrHandlr(_kernel_swi(0x400c5/*Wimp_OpenWindow*/, &r, &r));

  /* Enter main message loop */
  do
  {
    /* Suspend preemption if no background processing */
    r.r[0]=(halt) ? 1 : 0;
    r.r[1]=(int) q;
    StdErrHandlr(_kernel_swi(Tornado_Poll, &r, &r));
    switch(r.r[0])
    {
      case 0:
      if(!halt)
      {
        if(count<=0)
        {
        UpdateWindow();
        r.r[1]=(int) q;
        *(int *)(q+0)=windh;
        StdErrHandlr(_kernel_swi(0x400cb/*Wimp_GetWindowState*/, &r, &r));
        *(int *)(q+20)=(*(int *)(q+4))-(*(int *)(q+20));
        *(int *)(q+24)=(*(int *)(q+16))-(*(int *)(q+24));
        *(int *)(q+4)=0;
        *(int *)(q+8)=-512;
        *(int *)(q+12)=640;
        *(int *)(q+16)=0;
        RedrawWindow(r);
        count=FRAMES+1;
        }
        count-=1;
      }
      break;
      case 1:
      RedrawWindow(r);
      break;
      case 2:
      StdErrHandlr(_kernel_swi(0x400c5/*Wimp_OpenWindow*/, &r, &r));
      break;
      case 3:
      StdErrHandlr(_kernel_swi(0x400c6/*Wimp_CloseWindow*/, &r, &r));
      break;
      case 6:
      if((*(int *)(q+12))==-2)/*ie; the icon bar*/
      {
        if((*(int *)(q+8) & 2)==2)
        {
          const char info[]="Info";
          const char quit[]="Quit";
          char *menuptr;

          /*Open a quit menu */
          *(int *)(menus+0)=*(int *)(taskname+0);
          *(int *)(menus+4)=*(int *)(taskname+4);
          *(int *)(menus+8)=*(int *)(taskname+8);
          *(char *)(menus+12)=7;
          *(char *)(menus+13)=2;
          *(char *)(menus+14)=7;
          *(char *)(menus+15)=0;
          *(int *)(menus+16)=4*16;	/* I see this is ignored on RO3 */
          *(int *)(menus+20)=44;
          *(int *)(menus+24)=0;
          menuptr=menus+28;

          *(int *)(menuptr+0)=0x0;
          *(int *)(menuptr+4)=infoh;
          *(int *)(menuptr+8)=0x7005031;
          *(int *)(menuptr+12)=*(int *)(info+0);
          *(int *)(menuptr+16)=*(int *)(info+4);
          *(int *)(menuptr+20)=*(int *)(info+8);
          menuptr+=24;
          *(int *)(menuptr+0)=0x80;
          *(int *)(menuptr+4)=-1;
          *(int *)(menuptr+8)=0x7005031;
          *(int *)(menuptr+12)=*(int *)(quit+0);
          *(int *)(menuptr+16)=*(int *)(quit+4);
          *(int *)(menuptr+20)=*(int *)(quit+8);
          r.r[1]=(int) menus;
          r.r[2]=(*(int *)(q+0))-64;
          r.r[3]=96+2*48;
          StdErrHandlr(_kernel_swi(0x400d4/*Wimp_CreateMenu*/, &r, &r));
        }
        else if((*(int *)(q+8) & 4)==4)
        {
          /* Open the window */
          *(int *)(q+0)=windh;
          r.r[1]=(int) q;
          StdErrHandlr(_kernel_swi(0x400cb/*Wimp_GetWindowState*/, &r, &r));
          *(int *)(q+28)=-1;
          StdErrHandlr(_kernel_swi(0x400c5/*Wimp_OpenWindow*/, &r, &r));
        }
        else
        {
          StdErrHandlr(_kernel_swi(0x107, &r, &r));
        }
        break;
      }
      else if((*(int *)(q+12))==windh) /* ie; it's the window */
      {
        if((*(int *)(q+8) & 4)==4)
        {
          /* Stop the drawing */
          halt=TRUE;
        }
        else if((*(int *)(q+8) & 1)==1)
        {
          /* Restart the drawing */
          halt=FALSE;
        }
        else
        {
          StdErrHandlr(_kernel_swi(0x107, &r, &r));
        }
        break;
      }
      break;
      case 9:
      if((*(int *)(q+0))==1)
        quit=TRUE;
      break;
      case 17:
      case 18:
      switch(*(int *) (r.r[1]+16))
      {
        case 0x400c1:
        ModeChange();
        break;
        default:
        {
          /* codeshandler2(r.r[0], r.r[1]); */
          break;
        }
      }
      break;
      default:
      break;
    }
  }
  while(!quit);

  /* Shut her down */
  ROClosedown(blk.taskh);

  return 0;
}

int codeshandler(int msgno, int msgblk)
{
  /*return 2;*/
  return codeshandler2(msgno, msgblk);
}

int codeshandler2(int msgno, int msgblk)
{
  switch(*(int *) (msgblk+16))
  {
    case 0:
    quit=TRUE;
    return MSG_HANDLED;
    break;
    case 0x502:/*Message_HelpRequest*/
    if(*(int *)(msgblk+32)==-2)
    {
      char msg[]="This is the icon of a demonstration of the tornado II support module's preemption facilities|MClick SELECT to open the demo's main window|MClick MENU to open the demo's icon bar menu";
      _kernel_swi_regs r;

      strcpy((char *) msgblk+20,msg);
      *(int *)(msgblk+0)=256;
      *(int *)(msgblk+16)=0x503;/*Message_HelpGive*/
      *(int *)(msgblk+12)=*(int *)(msgblk+8);
      r.r[0]=17;
      r.r[1]=msgblk;
      r.r[2]=*(int *)(msgblk+4);
      _kernel_swi(0x400e7/*Wimp_SendMessage*/, &r, &r);
      return MSG_HANDLED;
    }
    else if(*(int *)(msgblk+32)==windh)
    {
      char msg[]="The lines in this window are being drawn into it preemptively|MClick SELECT to stop the lines being drawn|MClick ADJUST to restart the lines being drawn";
      _kernel_swi_regs r;

      strcpy((char *) msgblk+20,msg);
      *(int *)(msgblk+0)=256;
      *(int *)(msgblk+16)=0x503;/*Message_HelpGive*/
      *(int *)(msgblk+12)=*(int *)(msgblk+8);
      r.r[0]=17;
      r.r[1]=msgblk;
      r.r[2]=*(int *)(msgblk+4);
      _kernel_swi(0x400e7/*Wimp_SendMessage*/, &r, &r);
      return MSG_HANDLED;
    }
    return MSG_PASSON;
    break;
    default:
    return MSG_PASSON;
    break;
  }
}

void CreateNewWindow(void)
{
  _kernel_swi_regs r;
  int spaddr;

  sp=malloc(320*256+1024);
  if(sp==0)
    ROReportErrora(0x102, 0, "Not enough memory to allocate for sprite");
  /* I'm probably missing something here but somehow the sprite area
     needs zeroing or the sprite create fails!!! */
  {
    int n;

    for(n=0;n<320*256+1024;n+=4)
      *(int *)(sp+n)=0;
  }
  *(int *)(sp+0)=320*256+1024;
  *(int *)(sp+8)=16;
  r.r[0]=256+9;
  r.r[1]=(int) sp;
  StdErrHandlr(_kernel_swi(0x2e/*OS_SpriteOp*/, &r, &r));
  r.r[0]=256+15;
  r.r[1]=(int) sp;
  r.r[2]=(int) spname;
  r.r[3]=1;
  r.r[4]=320;
  r.r[5]=256;
  r.r[6]=20;
  StdErrHandlr(_kernel_swi(0x2e, &r, &r));
  r.r[0]=256+24;
  r.r[1]=(int) sp;
  r.r[2]=(int) spname;
  StdErrHandlr(_kernel_swi(0x2e, &r, &r));
  spaddr=r.r[2];
  *(int *)(spaddr+44+0)=0x00000000;
  *(int *)(spaddr+44+8)=0x0000ff00;
  *(int *)(spaddr+44+16)=0x00ff0000;
  *(int *)(spaddr+44+24)=0x00ffff00;
  *(int *)(spaddr+44+32)=0xff000000;
  *(int *)(spaddr+44+40)=0xff00ff00;
  *(int *)(spaddr+44+48)=0xffff0000;
  *(int *)(spaddr+44+56)=0xffffff00;

  r.r[0]=256+62;
  r.r[1]=(int) sp;
  r.r[2]=(int) spname;
  StdErrHandlr(_kernel_swi(0x2e, &r, &r));
  savearea=malloc(r.r[3]);
  *(int *)(savearea)=0;

  r.r[1]=(int) templ;
  StdErrHandlr(_kernel_swi(0x400c1/*Wimp_CreateWindow*/, &r, &r));
  windh=r.r[0];
}

void UpdateWindow(void)
{
  _kernel_swi_regs r,r2;

  r2.r[0]=256+60;
  r2.r[1]=(int) sp;
  r2.r[2]=(int) spname;
  r2.r[3]=(int) savearea;
  StdErrHandlr(_kernel_swi(0x2e, &r2, &r2));

  StdErrHandlr(_kernel_swi(0x100+18, &r, &r));
  StdErrHandlr(_kernel_swi(0x100+0, &r, &r));
  StdErrHandlr(_kernel_swi(0x100+rnd(8), &r, &r));
  /*r.r[0]=4;
  r.r[1]=0;
  r.r[2]=0;
  StdErrHandlr(_kernel_swi(0x45*//*OS_Plot*//*, &r, &r));*/
  r.r[0]=5;
  r.r[1]=rnd(640);
  r.r[2]=rnd(512);
  StdErrHandlr(_kernel_swi(0x45/*OS_Plot*/, &r, &r));

  StdErrHandlr(_kernel_swi(0x2e, &r2, &r2));
}

unsigned int rnd(int val)
{
  int n;

  for(n=0;n<32;n++)
  {
    seed=seed<<1;
    if(seed & (1<<30))
    {
      seed=seed^XOR_SPECIAL;
    }
  }
  n=seed % val;
  if(n>=0)
    return n;
  else
    return -n;
}

void ModeChange(void)
{
  _kernel_swi_regs r;
  int spaddr,n;
  char pal2[16*4];

  r.r[0]=256+24;
  r.r[1]=(int) sp;
  r.r[2]=(int) spname;
  StdErrHandlr(_kernel_swi(0x2e, &r, &r));
  spaddr=r.r[2];

  for(n=0;n<16*8;n+=8)
    *(int *)(pal2+(n/2))=*(int *)(spaddr+44+n);

  r.r[0]=*(int *)(spaddr+40);
  r.r[1]=(int) pal2;
  r.r[2]=-1;
  r.r[3]=-1;
  r.r[4]=(int) pix;
  StdErrHandlr(_kernel_swi(0x40740/*ColourTrans_SelectTable*/, &r, &r));

  r.r[0]=256;
  r.r[1]=(int) sp;
  r.r[2]=(int) spname;
  r.r[6]=(int) sc;
  r.r[7]=-1;
  StdErrHandlr(_kernel_swi(0x400ed/*Wimp_ReadPixTrans*/, &r, &r));
}

void RedrawWindow(_kernel_swi_regs r2)
{
  _kernel_swi_regs r=r2,t;
  int dx=*(int *)(r.r[1]+20), dy=*(int *)(r.r[1]+24);

  StdErrHandlr(_kernel_swi(Tornado_RedrawWindow, &r, &r));
  while(r.r[0]!=0)
  {
    t.r[0]=256+52;
    t.r[1]=(int) sp;
    t.r[2]=(int) spname;
    t.r[3]=dx;
    t.r[4]=dy-512;
    t.r[5]=0;
    t.r[6]=(int) sc;
    t.r[7]=(int) pix;
    StdErrHandlr(_kernel_swi(0x2e, &t, &t));

    StdErrHandlr(_kernel_swi(Tornado_GetRectangle, &r, &r));
  }
}

void ROInitialise(ROINITIALISEBLK *blk)
{
  char task[]="TASK";
  _kernel_swi_regs r;

  r.r[0]=025;
  r.r[1]=(int) blk->taskname;
  r.r[2]=(int) blk->handler;
  StdErrHandlr(_kernel_swi(Tornado_Initialise, &r, &r));

  blk->tnvers=r.r[0];
  blk->rovers=r.r[1];
  blk->wimpvers=r.r[1];
  blk->taskh=r.r[3];
}

void ROClosedown(int taskh)
{
  _kernel_swi_regs r;

  r.r[0]=taskh;
  StdErrHandlr(_kernel_swi(Tornado_Closedown, &r, &r));
}

int ROReportError(int flags, int *blk)
{
  _kernel_swi_regs r;
  char tmesg[]="Wimp2 Demo";

  r.r[0]=(int) blk;
  r.r[1]=flags;
  r.r[2]=(int) tmesg;
  _kernel_swi(0x400df/*Wimp_ReportError*/, &r, &r);

  if(flags & 0x100)
    exit(EXIT_FAILURE);
  return r.r[1];
}

int ROReportErrora(int flags, int errno, char *errstr)
{
  char q[260];

  *(int *)(q+0)=errno;
  strcpy((q+4), errstr);
  return ROReportError(flags, (int *) q);
}

void StdErrHandlr(_kernel_oserror *blk)
{
  if(blk)
    ROReportError(0x102, (int *) blk);
}



/* Just for debugging purposes */
void end(void)
{
}
