/*
 *  WEXAMPLE3.C     Example program for wIconify.
 *                  This program uses an icon with an IconPort to check
 *                  when its window is iconified.  Then it closes the
 *                  window and adds an icon to the screen (this saves
 *                  space, since the window is a SMART_REFRESH window).
 *                  When the icon is openned, the window is re-openned.
 */

#define INTUITION_PREFERENCES_H             /* don't need 'em */
#include <intuition/intuition.h>

#include "wIcon.h"

/*
 *  The revision levels needed to the libraries
 */

#define INTUITION_REV   0
#define GRAPHICS_REV    0
extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;


/*
 *  Return codes for error and OK
 */

#define ERROR_EXIT      10
#define OK_EXIT         0


/*
 *  Some routines we need
 */

extern struct Window *OpenWindow();
extern struct Node *GetMsg();
extern struct MsgPort *CreatePort();
extern APTR OpenLibrary();
extern WICONREF *wAddIcon();


/*
 *  Types of IconMessage to report
 */

#define REPORTFLAGS\
  (WI_REPORTICONVERIFY| WI_REPORTOPEN| WI_REPORTCLOSE| WI_REPORTSCREENCLOSE)

/*
 *  The definition for our window
 */

static struct NewWindow NewWindow =
{
   160,50, 320,100, 0,1, CLOSEWINDOW,
   WINDOWCLOSE| WINDOWDRAG| WINDOWDEPTH| WINDOWSIZING|
     SMART_REFRESH| NOCAREREFRESH,
   NULL, NULL, "wExample3", NULL, NULL, 20,10, -1,-1, WBENCHSCREEN
};
static struct Window *myWindow;
static struct Screen *theScreen;


/*
 *  This is the icon definition.  It uses the default imagery and flags,
 *  but adds report flags.
 */

static WICON myIcon =
{
   "wExample3",         /* No window for this icon, so must provide name */
   NULL,NULL,NULL,      /* Use default Image, Select, and Mask */
   0,0,                 /* Let wIconify place it where it wants */
   0,                   /* No special flags  */
   REPORTFLAGS,         /* The special report flags needed */
   NULL                 /* We'll add the icon port once it is created */
};
static WICONREF *IconRef;


/*
 *  The Ports and Signals used
 */

static struct MsgPort *WindowPort;
static struct MsgPort *IconPort;
static long WindowSignal;
static long IconSignal;

/*
 *  DoExit()
 *
 *  Print an error message, if necessary, and then clean up any allocated
 *  memory, close the windows and libraries, etc.  Finally, exit.
 */

static void DoExit(s,x1,x2,x3)
char *s, *x1,*x2,*x3;
{
   int status = OK_EXIT;

   if (s)
   {
      printf(s,x1,x2,x3);
      printf("\n");
      status = ERROR_EXIT;
   }
   if (IconRef)         wRemoveIcon(IconRef);
   if (myWindow)        CloseWindow(myWindow);
   if (IconPort)        DeletePort(IconPort);
   if (IntuitionBase)   CloseLibrary(IntuitionBase);
   if (GfxBase)         CloseLibrary(GfxBase);
   exit(status);
}


/*
 *  CheckLibOpen()
 *
 *  Check to see if the specified library can be openned, and exit with
 *  an error if not.
 */

static void CheckLibOpen(lib,name,rev)
APTR *lib;
char *name;
int rev;
{
   extern APTR OpenLibrary();
   
   if ((*lib = OpenLibrary(name,(ULONG)rev)) == NULL)
      DoExit("Can't open '%s'",name);
}


/*
 *  GetPort()
 *
 *  Create the IconPort and attach it to the Icon
 *  Get the signal bit in use by the port
 */

static void GetPort()
{
   IconPort = CreatePort(0,0);
   if (IconPort == NULL) DoExit("Can't Create IconPort");
   myIcon.IconPort = IconPort;
   IconSignal = (1 << IconPort->mp_SigBit);
}


/*
 *  OpenMyWindow()
 *
 *  If an icon is open,
 *    Open the window on the screen where the icon currently exists.
 *  Attempt to open the window (error if unsuccessful).
 *  Add the icon to the window once it's open.
 *  return the window pointer
 */

static struct Window *OpenMyWindow()
{
   if (theScreen)
   {
      NewWindow.Screen = theScreen;
      NewWindow.Type = CUSTOMSCREEN;
   }
   myWindow = OpenWindow(&NewWindow);
   if (myWindow == NULL)
   {
      printf("Can't open my window");
   } else {
      wSetIcon(myWindow,&myIcon);
      WindowPort = myWindow->UserPort;
      WindowSignal = (1 << WindowPort->mp_SigBit);
   }
   return(myWindow);
}


/*
 *  DisplayMessage()
 *
 *  Set the pen color, and write out the message telling the user
 *  what he should do with this window.
 */

static void DisplayMessage()
{
   struct RastPort *rp = myWindow->RPort;

   SetAPen(rp,3);
   Move(rp,110,43);
   Text(rp,"Iconify Me!",11);
   Move(rp,42,59);
   Text(rp,"(Close me when you're done.)",28);
}


/*
 *  WaitForAction()
 *
 *  While there is still more to do
 *    Wait for a message to arrive at the window's UserPort
 *    If the window is open
 *      While there are more messages in the port
 *        If the message class is a CLOSEWINDOW message, we're done
 *        Reply to the message
 *    While there are more IconMessages in the port
 *      If the message is ICONVERIFY
 *        Tell wIconify NOT to iconify the window and return the message
 *        Now add the icon to the screen manually
 *        If successful,
 *          if the window is selected, select the new icon
 *          remove the window - it will appear iconify!
 *          clear the window, port and signal variables
 *        Otherwise tell the user we couldn't add the icon
 *      If the message is OPEN
 *        If we have an icon on the screen
 *          Re-open the window and display its message
 *          Get the icon's current data (we are after it's position and flags)
 *          Remove the icon and clear the reference
 *      If the message is CLOSE or SCREENCLOSE
 *        If the icon exists, we're done
 *      Reply to the message
 */

static void WaitForAction()
{
   struct IntuiMessage *intuiMessage;
   struct wIconMessage *iconMessage;
   short NotDone = TRUE;

   while (NotDone)
   {
      Wait(WindowSignal | IconSignal);
      if (myWindow)
      {
         while (intuiMessage = (struct IntuiMessage *)GetMsg(WindowPort))
         {
            if (intuiMessage->Class == CLOSEWINDOW) NotDone = FALSE;
            ReplyMsg(intuiMessage);
         }
      }
      while (iconMessage = (struct wIconMessage *)GetMsg(IconPort))
      {
         switch(iconMessage->Action)
         {
            case WI_REPORTICONVERIFY:
               iconMessage->Flags &= ~WI_ICONIFYOK;
               ReplyMsg(iconMessage); iconMessage = NULL;
               theScreen = myWindow->WScreen;
               IconRef = wAddIcon(theScreen,&myIcon);
               if (IconRef)
               {
                  if (myWindow->Flags & WINDOWACTIVE)
                     wSelectIcon(IconRef,FALSE);
                  CloseWindow(myWindow); myWindow = NULL;
                  WindowPort = NULL; WindowSignal = 0;
               } else printf(">> Can't Add Icon!");
               break;

            case WI_REPORTOPEN:
               if (IconRef)
               {
                  if (OpenMyWindow())
                  {
                     wGetIconData(&myIcon,IconRef);
                     wRemoveIcon(IconRef); IconRef = NULL;
                     DisplayMessage();
                  }
               }
               break;

            case WI_REPORTCLOSE:
            case WI_REPORTSCREENCLOSE:
               if (IconRef) NotDone = FALSE;
               break;
         }
         if (iconMessage) ReplyMsg(iconMessage);
      }
   }
}


/*
 *  main()
 *
 *  If wIconify is running
 *    Open the libraries
 *    Create the IconPort
 *    Open the window and add its icon
 *    Display the message in the window
 *    Wait for something to happen
 *  Otherwise
 *    Print an error message
 *  Clean up and exit
 */

void main()
{
   if (wIconifyActive())
   {
      CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV);
      CheckLibOpen(&GfxBase,"graphics.library",GRAPHICS_REV);
      GetPort();
      if (OpenMyWindow())
      {
         DisplayMessage();
         WaitForAction();
      }
   } else printf("wIcoinfy not running or version mismatch\n");
   DoExit(NULL);
}
