/*
 * misc.c V1.1
 *
 * miscellaneous support routines
 *
 * (c) 1992-1993 Holger Brunst
 */

#include <CClock.h> 

/* Wait pointer image data */
static __chip const UWORD WaitPointer[] = {
                                           0x0000, 0x0000,

                                           0x0400, 0x07c0,
                                           0x0000, 0x07c0,
                                           0x0100, 0x0380,
                                           0x0000, 0x07e0,
                                           0x07c0, 0x1ff8,
                                           0x1ff0, 0x3fec,
                                           0x3ff8, 0x7fde,
                                           0x3ff8, 0x7fbe,
                                           0x7ffc, 0xff7f,
                                           0x7efc, 0xffff,
                                           0x7ffc, 0xffff,
                                           0x3ff8, 0x7ffe,
                                           0x3ff8, 0x7ffe,
                                           0x1ff0, 0x3ffc,
                                           0x07c0, 0x1ff8,
                                           0x0000, 0x07e0,

                                           0x0000, 0x0000
                                          };

/* Disable a window */
void DisableWindow(struct Window *w)
{
 /* Disable right mouse button */
 w->Flags |= WFLG_RMBTRAP;

 /* Disable IDCMP */
 ModifyIDCMP(w, IDCMP_REFRESHWINDOW);

 /* Set wait pointer */
 SetPointer(w, WaitPointer, 16, 16, -6, 0);
}

/* Enable a window */
void EnableWindow(struct Window *w, ULONG idcmp)
{
 /* Clear wait pointer */
 ClearPointer(w);

 /* Enable IDCMP */
 ModifyIDCMP(w, idcmp);

 /* Enable right mouse button */
 w->Flags &= ~WFLG_RMBTRAP;
}

/* Remove all remaining messages from message port */
static void StripIntuiMessages(struct MsgPort *mp, struct Window *win)
{
 struct IntuiMessage    *msg;
 struct Node            *succ;

 msg = (struct IntuiMessage *) mp->mp_MsgList.lh_Head;

 while (succ = msg->ExecMessage.mn_Node.ln_Succ) {

  if (msg->IDCMPWindow ==  win) {

   /* Intuition is about to free this message.
    * Make sure that we have politely sent it back.
    */
   Remove((struct Node *) msg);
   ReplyMsg((struct Message *) msg);
  }
  msg = (struct IntuiMessage *) succ;
 }
}

/* Close a window safely */
void CloseWindowSafely(struct Window *win)
{
 /* we forbid here to keep out of race conditions with Intuition */
 Forbid();

 /* send back any messages for this window 
  * that have not yet been processed
  */
 StripIntuiMessages(win->UserPort, win);

 /* clear UserPort so Intuition will not free it */
 win->UserPort = NULL;

 /* tell Intuition to stop sending more messages */
 ModifyIDCMP(win, 0L);

 /* turn multitasking back on */
 Permit();

 /* and really close the window */
 CloseWindow(win);
}

/* Create a list of GT gadgets */
struct Gadget *CreateGadgetList(struct GadgetData *gData, ULONG gadNum, ULONG idOffset)
{
 struct Gadget      *ClockGads, *gad;
 struct NewGadget   NewGad;
 ULONG              i;

 /* Create GadTools gadget context */
 ClockGads = NULL;
 if (gad = CreateContext(&ClockGads)) {
  NewGad.ng_TextAttr = &GrntAttr;
  NewGad.ng_VisualInfo = ScreenVI;
  for (i = 0; i < gadNum; i++, gData++) {
   NewGad.ng_LeftEdge=gData->left;
   NewGad.ng_TopEdge=gData->top;
   NewGad.ng_Width=gData->width;
   NewGad.ng_Height=gData->height;
   NewGad.ng_GadgetText=gData->name;
   NewGad.ng_GadgetID=i+idOffset;
   NewGad.ng_Flags=gData->flags;

   /* Create Gadget */  
   if (!(gad =
   CreateGadgetA(gData->type, gad, &NewGad, gData->tags))) break;

   /* Store gadget pointer in GadgetData structure */ 
   gData->gadget=gad;
  }
  /* Gadgets created? */
  if (gad) return (ClockGads); 

  /* Couldn't create gadgets */
  FreeGadgets(ClockGads);
 } 
 /* Return failure */
 return (NULL);
}

/* I was to lousy to write any special kind of routine in order to switch
   between the two sides. So I decided to simply zoom it */ 
static USHORT  buf[32];  
void Zoom(struct Screen *s, USHORT *p, short num)
{
 long i, steps;
 struct ColorMap *cm = s->ViewPort.ColorMap;

 /* Read current screen colors */
 for (i = 0; i < num; i++)
  buf[i] = GetRGB4(cm, i);

 /* Change screen colors in 16 steps */
 for (steps = 0; steps < 16; steps++) {
  /* Wait for vertical blank to syncronize zoom function */ 
  WaitTOF();

  /* Change 'num' color registers */
  for (i = 0; i < num; i++) {
   /* increase/decrease RGB values */ 
   if (p[i] != ~0) {
    if ((buf[i] & 0xf00) > (p[i] & 0xf00))		
     buf[i] -= 0x100;
    else if ((buf[i] & 0xf00) < (p[i] & 0xf00))
     buf[i] += 0x100;

    if ((buf[i] & 0xf0) > (p[i] & 0xf0))		
     buf[i] -= 0x10;
    else if ((buf[i] & 0xf0) < (p[i] & 0xf0))
     buf[i] += 0x10;

    if ((buf[i] & 0xf) > (p[i] & 0xf))		
     buf[i] -= 0x1;
    else if ((buf[i] & 0xf) < (p[i] & 0xf))
     buf[i] += 0x1;
   }
  }
  /* Display new pallete */
  LoadRGB4(&s->ViewPort, buf, num); 
 }
}

/* Load Iff-image
   This routine is very stupid but it works with my picture */
struct BitMap *OpenILBM(UBYTE *Name)
{
 UBYTE  *planes;
 USHORT *palette, color;
 long   *iffData;

 short  planeX, numRows;
 long   planeSize, buffer[2];

 REGISTER BYTE		*dest, repByte;
 REGISTER short		byteSum, numBytes;
 REGISTER union {
  BYTE	*B;
  WORD	*W;
  long	*L;
 } uniPtr;

 struct BitMap		*map;
 struct FileHandle	*iffHandle;

 /* Open iff image data */
 if (iffHandle = (struct FileHandle *) Open(Name, MODE_OLDFILE)) {
  /* Read image file */
  if (Read((BPTR) iffHandle, &buffer[0], 8) == 8) {
   /* Iff ? */
   if (buffer[0] == 'FORM') {
    /* Get memory for image */
	if (iffData = AllocMem(buffer[1], MEMF_PUBLIC)) {
     /* Memory for BitMap structure */
	 if (map = (struct BitMap *)
           AllocMem(sizeof (struct BitMap) + 64, MEMF_PUBLIC | MEMF_CLEAR)) {
      /* Read first chunk */
      if (Read((BPTR)iffHandle, iffData, buffer[1]) == buffer[1]) {
       /* Analyse iff */
       uniPtr.L = iffData;
       if (*uniPtr.L++ == 'ILBM') {
        if (*uniPtr.L++ == 'BMHD') {
         InitBitMap(map, uniPtr.B[12], uniPtr.W[2], uniPtr.W[3]);
         uniPtr.B += *uniPtr.L + 4; 
         /* Read color map */
         if (*uniPtr.L == 'CMAP') {
          planes = (UBYTE *) uniPtr.B + 8;		
          palette = (USHORT *) &map->Planes[6];

          for (planeX = 1 << map->Depth; planeX > 0; --planeX) {
           color = *planes++ << 4;
           color |= *planes++;		
           *palette++ = color | *planes++ >> 4;
          }
          /* Find body */
          while (*uniPtr.L != 'BODY') {
           ++uniPtr.L;
           uniPtr.B += *uniPtr.L + 4;
           if (uniPtr.B >= (BYTE *) iffData + buffer[1])
            break;
          }
          /* Read Body */
          if (*uniPtr.L == 'BODY') {
           planeSize = map->BytesPerRow * map->Rows;
           if (planes = (UBYTE *)
                AllocMem(planeSize * map->Depth, MEMF_CHIP)) {
			for (planeX = 0; planeX < map->Depth; ++planeX) 
             map->Planes[planeX] = (PLANEPTR) planes + planeSize * planeX;
             /* Decrunch image */
            uniPtr.L += 2;
            for (numRows = map->Rows; numRows > 0; --numRows) {
	         for (planeX = 0; planeX < map->Depth; ++planeX) {
		      byteSum = map->BytesPerRow;
		      dest = (BYTE *) map->Planes[planeX];
		      do {
			   if ((numBytes = *uniPtr.B++) < 0) {
               numBytes = -numBytes;
               repByte = *uniPtr.B++;

               byteSum -= numBytes+1;
               for (; numBytes > -1; --numBytes)
                *dest++ = repByte;
               }
               else {
				byteSum -= numBytes+1;
				for (; numBytes > -1; --numBytes)
                 *dest++ = *uniPtr.B++;
               }
              } while (byteSum > 0);
              map->Planes[planeX] += map->BytesPerRow;
             }
            }
            for (planeX = 0; planeX < map->Depth; ++planeX) 
             map->Planes[planeX] = map->Planes[planeX] - planeSize;

            Close((BPTR)iffHandle);
			FreeMem(iffData, buffer[1]);

			return (map);
           }		
	      }
         }
        }
       }
	  } FreeMem(map, sizeof (struct BitMap) + 64);
     } FreeMem(iffData, buffer[1]);
    }
   }
  } Close((BPTR)iffHandle);
 } return (FALSE);
}
/* Get rid of the image */
void CloseILBM(map)
struct BitMap *map;
{
 FreeMem(map->Planes[0], map->BytesPerRow * map->Rows * map->Depth);
 FreeMem(map, sizeof (struct BitMap) + 64);
}