#include <exec/types.h>
#include <intuition/intuisup.h>
#include <libraries/dos.h>
#include "patch.h"

#ifndef DEBUG
#include <proto/all.h>
#endif

#define PROGRAM_NAME "SmartIcon 2.0"
#define RCFILE       "s:.sirc"

struct   Window  *theEventWindow;

BOOL   Sleeping = FALSE;
USHORT WindowX = 40, WindowY = 20;
ULONG  PatchSignal = -1;
struct WindowPatch   PList;
struct HiddenWindow  HList;
struct ListSupport   *DList;
struct Library       *GfxBase, *IntuitionBase, *LayersBase;
struct MsgPort       *DefaultPort, *WakeupPort, *IDCMPReplyPort;
struct Task          *PatchTask;


VOID
ReadRCFile()
{
   USHORT x, y;
   register struct FileHandle *file = (struct FileHandle *)Open(RCFILE, MODE_OLDFILE);

   if (file)
      {
      if (Read(file, &x, 2)==2 && Read(file, &y, 2)==2)
         {
         WindowX = x;
         WindowY = y;
         }
      else DisplayBeep(NULL);
      Close(file);
      }
}

VOID
WriteRCFile()
{
   register struct FileHandle *file = (struct FileHandle *)Open(RCFILE, MODE_NEWFILE);

   if (file)
      {
      Write(file, &DList->LRWindow->LeftEdge, 2);
      Write(file, &DList->LRWindow->TopEdge,  2);
      Close(file);
      }
   else DisplayBeep(NULL);
}

VOID
Cleanup(code)
register UBYTE code;
{
   register struct IntuiMessage *msg;


   Forbid();
   while (PList.NextPatch) UnPatchWindow(PList.NextPatch, TRUE);
   Permit();

   if (DList) ReleaseList(DList);

   if (DefaultPort)
      {
      while(msg = (struct IntuiMessage *)GetMsg(DefaultPort)) ReplyMsg(msg);
      DeletePort(DefaultPort);
      }
   if (WakeupPort)     DeletePort(WakeupPort);
   if (IDCMPReplyPort) DeletePort(IDCMPReplyPort);

   if (PatchSignal!=-1)  FreeSignal(PatchSignal);

   if (GfxBase)         CloseLibrary(GfxBase);
   if (IntuitionBase)   CloseLibrary(IntuitionBase);
   if (LayersBase)      CloseLibrary(LayersBase);

   exit(code);
}

VOID
ControlLoop()
{
   BOOL     mousemoved;
   SHORT    x, y, code, itemnum;
   LONG     seconds, micros;
   ULONG    class, mask,
            PatchEvent   = 1 << PatchSignal,
            DefPortEvent = 1 << DefaultPort->mp_SigBit,
            WakeupEvent  = 1 << WakeupPort->mp_SigBit,
            ReqEvent     = 1 << DList->LRWindow->UserPort->mp_SigBit;
   register struct Window        *window;
   register struct IntuiMessage  *msg;
   register struct Gadget        *gadget;

   FOREVER
   {
   WAIT:
   mask = Wait(SIGBREAKF_CTRL_C | DefPortEvent | PatchEvent | ReqEvent | WakeupEvent);

   if (mask & SIGBREAKF_CTRL_C) return;

   if (mask & DefPortEvent) while(msg=(struct IntuiMessage *)GetMsg(DefaultPort)) ReplyMsg(msg);

   if (mask & WakeupEvent)
      {
#ifdef DEBUG
printf("wake up event received\n");
#endif
      /* A wake up signal here means that another SmartIcon task was launched */
      /* and that it is telling us. Time to wake up if we were asleep.        */
      if (Sleeping)
         {
         FixDisplay(FALSE);
         if (!ls_StartRequester(DList, NULL, WindowX, WindowY)) DisplayBeep(NULL);
         else Sleeping = FALSE;
         }
      }

   if (mask & PatchEvent)
      {
      Forbid();
      window = theEventWindow;
      Permit();

#ifdef DEBUG
printf("patch event received: window [%s]\n", window->Title);
#endif

      Iconify(window, !Sleeping);
      }

   if (mask & ReqEvent)
      {
      mousemoved = FALSE;
      while (msg = (struct IntuiMessage *)GetMsg(DList->LRWindow->UserPort))
            {
            gadget  = (struct Gadget *)msg->IAddress;
            class   = msg->Class;
            code    = msg->Code;
            x       = msg->MouseX;
            y       = msg->MouseY;
            seconds = msg->Seconds;
            micros  = msg->Micros;
            ReplyMsg(msg);

            switch(class)
                  {
                  case MOUSEMOVE: mousemoved = TRUE; break;

                  case GADGETDOWN:
                  case GADGETUP:
                     if (ls_HandleGadget(DList, gadget, x, y, seconds, micros))
                        UnIconify(DList->Pick, TRUE);
                  break;

                  case CLOSEWINDOW:
                     /* go to sleep... */
                     Sleeping = TRUE;
                     WindowX = DList->LRWindow->LeftEdge;
                     WindowY = DList->LRWindow->TopEdge;
                     ls_EndRequester(DList);
                     goto WAIT;

                  case MENUPICK:
                     while (code != MENUNULL && code != 252)
                           {
                           itemnum = ITEMNUM(code);

                           switch(itemnum)
                                 {
                                 case 3: WriteRCFile(); break;
                                 case 5: return;
                                 }
                           code = ((struct MenuItem *)ItemAddress(DList->LRWindow->MenuStrip, code))->NextSelect;
                           }
                  break;
                  }
            }
      if (mousemoved) ls_PropMouseMoves(DList);
      }
   }
}

VOID
main(argc, argv)
UBYTE argc, **argv;
{
   extern struct Library *OpenLibrary();
   extern struct MsgPort *CreatePort();
   struct MsgPort *port;

   /* First check if we already have a port somewhere. If yes, then there is  */
   /* already a task running, just signal that we saw it and exit.            */
   if (port = (struct MsgPort *)FindPort("SM2.0"))
      {
      Signal(port->mp_SigTask, 1 << port->mp_SigBit);
      exit(0);
      }

   /* Still here? Just do our normal stuff.                                   */
   if (  (GfxBase        = OpenLibrary("graphics.library", 0))
      && (IntuitionBase  = OpenLibrary("intuition.library", 0))
      && (LayersBase     = OpenLibrary("layers.library", 0))
      && (WakeupPort     = CreatePort("SM2.0", 0))
      && (DefaultPort    = CreatePort(0, 0))
      && (IDCMPReplyPort = CreatePort(0, 0))
      && ((PatchSignal   = AllocSignal(-1))!=-1)
      && (DList          = GetListSupport(NULL, NULL, NULL))
      )
      {
      ReadRCFile();

      PatchTask = (struct Task *)FindTask(0);
      SetHooks();
      PatchCurrentWindows();

      DList->ReqTitle = "Windows  ";
      DList->MaxChars = 14;
      DList->MaxLines = 5;

      if (ls_AllocateData(DList) && ls_StartRequester(DList, NULL, WindowX, WindowY))
         {
         ControlLoop();

         /* Put this here so we get display feedback */
         while (HList.Next) UnIconify(HList.Next, !Sleeping);

         if (!Sleeping) ls_EndRequester(DList);
         ls_DeleteData(DList);
         }

      ClearHooks();
      Cleanup(0);
      }
   Cleanup(10);
}

