/*
 *  WICONVERIFY A companion utility to wIconify that checks the windows
 *              on a given screen (or all screens) to make sure that
 *              all the iconified ones are invisible, and all the uniconified
 *              ones are accessible.
 *
 *  Copyright 1990 by Davide P. Cervone, all rights reserved.
 *  You may use this code, provided this copyright notice is kept intact.
 */


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

#define USAGE   "wIconVerify [screen]"

static char *program = "wIconVerify";
static char *version = "v1.0";
static char *copyright =
   "Copyright (C) 1990 by Davide P. Cervone, all rights reserved.";


#define INTUITION_REV   0L
extern struct IntuitionBase *IntuitionBase;
extern struct IntuitionBase *OpenLibrary();
extern struct Window *wBackDropOf();

#define MAXWINDOW       32          /* largest number of windows per screen */

#define TOUPPER(c)      (((c)>='a'&&(c)<='z')?(c)-'a'+'A':c)

/*
 *  PrefixMatch()
 *
 *  Case-insensitive prefix match.  NULL pointers and empty strings
 *  only match themselves, and are not considered prefixes to any string.
 *
 *  Return <0 if the first is smaller than the second,
 *         =0 if the first is a prefix of the second,
 *         >1 if the first is larger than the second.
 */

static int PrefixMatch(s1,s2)
char *s1,*s2;
{
   int match = -1;
   
   if (s1 && *s1)
   {
      if (s2)
      {
         while (TOUPPER(*s1) == TOUPPER(*s2) && *s2 != 0) s1++,s2++;
         if (*s1 == 0) match = 0; else match = *s1 - *s2;
      } else match = 1;
   } else if (s2 == NULL || *s2 == 0) match = 0;
   return(match);
}


/*
 *  *FindScreen()
 *
 *  Lock IntuitionBase so nothing happens while we look.
 *  If there is a name to look for,
 *    Start at the first screen, and look for a screen whose title
 *      matches the given name.  If none, return NULL.
 *  Otherwise, use the first screen.
 *  Unlock Intuition.
 *  Return the screen pointer found, if any.
 */

static struct Screen *FindScreen(ScreenName)
char *ScreenName;
{
   struct Screen *theScreen;
   long ILock, LockIBase();

   ILock = LockIBase(0L);
   if (ScreenName)
   {
      theScreen = IntuitionBase->FirstScreen;
      while (theScreen && PrefixMatch(ScreenName,theScreen->Title))
         theScreen = theScreen->NextScreen;
   } else {
      theScreen = IntuitionBase->FirstScreen;
   }
   UnlockIBase(ILock);
   return(theScreen);
}


/*
 *  Print()
 *
 *  Find the standard AmigaDOS output file and write the output string
 *  to the output file.  This is intended as a substitute for printf()
 *  when no formatting is required, and when you want a small executable.
 */

static void Print(s)
char *s;
{
   ULONG OutFile;
   extern ULONG Output();
   
   OutFile = Output();
   if (OutFile && s) Write(OutFile,s,strlen(s));
}


/*
 *  Error()
 *
 *  Print the character string, and up to two optional strings, then
 *  go to a new output line, close Intuition, and exit with an error.
 */

static void Error(s,x1,x2)
char *s,*x1,*x2;
{
   Print(s);
   if (x1) Print(x1);
   if (x2) Print(x2);
   Print("\n");
   if (IntuitionBase) CloseLibrary(IntuitionBase);
   _exit(10L);
}


/*
 *  CheckWindows()
 *
 *  Get the wIconify BackDrop window of the given screen
 *  While there are more windows to check
 *    If the window is the BackDrop window, note that we've moved behind it
 *    Otherwise, if the window is iconified
 *      but it is not behind the backdrop window
 *        Print a message saying that it is being restored
 *        Restore it, and mark the change
 *    Otherwise, the window is not iconified
 *      If it is behind the backdrop window
 *        Print a message saying that is is being iconified
 *        Iconify it and note the change
 *    Go on to the next window
 *  Return TRUE if any changes occured
 */

static int CheckWindows(WindowPtr,i,theScreen)
struct Window **WindowPtr;
short i;
struct Screen *theScreen;
{
   struct Window *BackDrop = wBackDropOf(theScreen);
   int BehindBackDrop = FALSE;
   int VerifyFail = FALSE; 
   
   while (i--)
   {
      if (*WindowPtr == BackDrop) BehindBackDrop = TRUE;
      else if (wIsIconified(*WindowPtr))
      {
         if (!BehindBackDrop)
         {
            Print("Restoring window '");
            Print((*WindowPtr)->Title);
            Print("'\n");
            wRestore(wIconOf(*WindowPtr));
            VerifyFail = TRUE;
         }
      } else {
         if (BehindBackDrop)
         {
            Print("Iconifying window '");
            Print((*WindowPtr)->Title);
            Print("'\n");
            wIconify(*WindowPtr);
            VerifyFail = TRUE;
         }
      }
      WindowPtr++;
   }
   return(VerifyFail);
}


/*
 *  Verify()
 *
 *  While there are more screens to look at
 *    Lock Intuition so that nothing changes while we look
 *    Start at the top layer of the screen (the window list is not in front-
 *      to-back order, so we have to use the layer list)
 *    While there are more layers to check and we can hold more windows
 *      If the layer has a window and it is not the last one we recorded
 *        Record the layer's window
 *      Go to the next layer
 *    Unlock Intuition for the moment
 *    Check if any of the windows are in the wrong place
 *    If we are checking a single screen, end the loop,
 *      otherwise go on to the next screen
 */

static void Verify(theScreen,Name)
struct Screen *theScreen;
char *Name;
{
   APTR theWindow = NULL;
   APTR WindowPtr[MAXWINDOW];
   struct Layer *theLayer;
   short i = 0;
   long ILock, LockIBase();
   int VerifyFail = FALSE;
   
   while (theScreen)
   {
      ILock = LockIBase(0L);
      theLayer = theScreen->LayerInfo.top_layer;
      while (theLayer && i < MAXWINDOW)
      {
         if (theLayer->Window && theLayer->Window != theWindow)
            WindowPtr[i++] = theWindow = theLayer->Window;
         theLayer = theLayer->back;
      }
      UnlockIBase(ILock);
      VerifyFail |= CheckWindows(&WindowPtr[0],i,theScreen);
      if (Name) theScreen = NULL; else theScreen = theScreen->NextScreen;
   }
   if (VerifyFail == FALSE) Print("No incorrect windows\n");
}


/*
 *  main()
 *
 *  If there are too many arguments, print the Usage message.
 *  If a screen name is given, use it.
 *  Open Intuition; if successful,
 *    Find the specified screen.
 *    If found, then
 *      If wIconify is running, verify the given screen(s)
 *      Otherwise say that wIconify is not running.
 *    Otherwise say that the screen can't be found.
 *    Close Intuition.
 *  Otherwise say that Intuition can't be openned.
 */

void main(argc,argv)
int argc;
char *argv[];
{
   char *ScreenName = NULL;
   struct Screen *theScreen;

   if (argc > 2) Error("Usage:  ",USAGE,NULL);
   if (argc > 1 && argv[1]) ScreenName = argv[1];

   IntuitionBase = OpenLibrary("intuition.library",INTUITION_REV);
   if (IntuitionBase)
   {
      theScreen = FindScreen(ScreenName);
      if (theScreen)
      {
         if (wIconifyActive()) Verify(theScreen,ScreenName);
          else Error("wIconify not running or incompatible version",NULL,NULL);
      } else Error("Can't find screen '",ScreenName,"'");
      CloseLibrary(IntuitionBase);
   } else Error("Can't Open Intuition Library!",NULL,NULL);
}
