#include <intuition/intuisup.h>
#include <intuition/intuitionbase.h>
#include "patch.h"


extern USHORT GadgetsData[];
extern struct WindowPatch   PList;
extern struct IntuitionBase *IntuitionBase;
extern struct MsgPort       *DefaultPort;

/* Global Read-Only data */

struct   Image    GadgetsImage = { -1,0, 50,10, 2, GadgetsData, 0x3,0x0, NULL };
struct   Gadget   NewGadgets[NEWGADGETS] =
   {
      { NULL, -36,0, 15,10, GRELRIGHT, RELVERIFY, BOOLGADGET,
        NULL, NULL, NULL, NULL, NULL, ICONGADGET, NULL },
      { NULL, -19,0, 14,10, GRELRIGHT, RELVERIFY, SYSGADGET | WUPFRONT,
        NULL, NULL, NULL, NULL, NULL, 0, NULL },
      { NULL, -51,0, 14,10, GADGIMAGE | GRELRIGHT, RELVERIFY, SYSGADGET | WDOWNBACK,
        (APTR)&GadgetsImage, NULL, NULL, NULL, NULL, 0, NULL },
   };

struct WindowPatch
*AddPatch()
{
   register struct WindowPatch *patch;

   if (patch = New(struct WindowPatch, 1))
      {
      patch->NextPatch = PList.NextPatch;
      PList.NextPatch  = patch;
      return(patch);
      }
   return(NULL);
}

VOID
RemovePatch(patch)
register struct WindowPatch *patch;
{
   register struct WindowPatch *p = PList.NextPatch, *previous = NULL;

#ifdef DEBUG
printf("removing patch [%s], ", patch->Window->Title);
#endif

   while(p != patch) { previous = p; p = p->NextPatch; }

   if (previous) previous->NextPatch = patch->NextPatch;
   else PList.NextPatch = patch->NextPatch;
   CheckDelete(patch, 1);
}

struct   WindowPatch
*FindWPatch(window)
register struct   Window   *window;
{
   register struct WindowPatch *p = PList.NextPatch;

   while (p)
         {
         if (p->Window == window) return(p);
         p = p->NextPatch;
         }
   return(NULL);
}

VOID
UnPatchWindow(patch, refresh)
register struct WindowPatch *patch;
register BOOL   refresh;
{
   register struct Window  *w = patch->Window;

#ifdef DEBUG
printf("unpatching window [%s]: ", w->Title);
#endif
   RemoveGList(w, patch->Gadgets, NEWGADGETS);

   if (patch->BackGadget && patch->FrontGadget)
      {
#ifdef DEBUG
printf("restoring depth, ");
#endif
      AddGadget(w, patch->FrontGadget, 0);
      if (refresh) RefreshGList(patch->FrontGadget, w, NULL, 1);
      AddGadget(w, patch->BackGadget,  0);
      if (refresh) RefreshGList(patch->BackGadget, w, NULL, 1);
      }
   if (w->UserPort==DefaultPort) w->UserPort = NULL;
   RemovePatch(patch);
#ifdef DEBUG
printf("done\n");
#endif
}

VOID
PatchWindow(window)
register struct Window      *window;
{
   register USHORT i;
   register struct Gadget        *g;
   register struct WindowPatch   *patch = AddPatch();

#ifdef DEBUG
printf("patching window [%s]: ", window->Title);
#endif

   if (patch)
      {
      patch->Window = window;

      CopyMemQuick(NewGadgets, patch->Gadgets, NEWGADGETS*sizeof(struct Gadget));
      for(i=0; i<NEWGADGETS; i++)
         {
         patch->Gadgets[i].NextGadget = &patch->Gadgets[i+1];
         if (window->Flags & GIMMEZEROZERO) patch->Gadgets[i].GadgetType |= GZZGADGET;
         }
      patch->Gadgets[NEWGADGETS-1].NextGadget = NULL;

      for(g=window->FirstGadget; g; g=g->NextGadget)
         {
         if ((g->GadgetType & SYSGADGET) && (g->GadgetType &~GADGETTYPE)==WDOWNBACK) patch->BackGadget  = g;
         if ((g->GadgetType & SYSGADGET) && (g->GadgetType &~GADGETTYPE)==WUPFRONT)  patch->FrontGadget = g;
         }

      if (patch->BackGadget && patch->FrontGadget)
         {
#ifdef DEBUG
printf("adding depth, ");
#endif
         RemoveGadget(window, patch->BackGadget);
         RemoveGadget(window, patch->FrontGadget);

         AddGList(window, patch->Gadgets, 0, NEWGADGETS, NULL);
         RefreshGList(patch->Gadgets, window, NULL, NEWGADGETS);

         /* This window has no port: let's give it one,  */
         /* otherwise Intuition wont send msgs to it.    */
         if (!window->UserPort) window->UserPort = DefaultPort;
         /* Add GADGETUP/GADGETDOWN to the window IDCMPs */
         /* trough our patched version of ModifyIDCMP(). */
         ModifyIDCMP(window, window->IDCMPFlags);
         }
      }
#ifdef DEBUG
printf("done\n");
#endif
}

VOID
PatchCurrentWindows()
{
   register struct   Screen   *screen = IntuitionBase->FirstScreen;
   register struct   Window   *window;

   while (screen)
         {
         for(window=screen->FirstWindow; window; window=window->NextWindow) PatchWindow(window);
         screen = screen->NextScreen;
         }
}


