/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* |_o_o|\\ Copyright (c) 1989 The Software Distillery.                    *
* |. o.| ||          All Rights Reserved                                  *
* | .  | ||          Written by John Toebes and Doug Walker               *
* | o  | ||          The Software Distillery                              *
* |  . |//           235 Trillingham Lane                                 *
* ======             Cary, NC 27513                                       *
*                    BBS:(919)-471-6436                                   *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <exec/types.h>
#include <intuition/intuition.h>
#include <graphics/gfxmacros.h>
#include <graphics/rastport.h>
#include <libraries/dos.h>
#include <proto/intuition.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <string.h>

#include "pickpack.h"
#include "struct.h"

static struct STGLOB stg;

#define ROUND(len) ((len) + 4 - ((len)%4))

int stsize[ST_NUM] = 
{
   sizeof(struct BUFDATA),
   sizeof(struct VIEWDATA),
   sizeof(struct FileInfoBlock),
   sizeof(struct FileHandle),
   sizeof(struct FileLock),
   sizeof(struct InfoData),
};

char *wnames[ST_NUM] =
{
   "Data Buffer %d",
   "Help Window",
   "FileInfoBlock %d",
   "FileHandle %d",
   "FileLock %d",
   "InfoData %d",
};

int InitST(port)
struct MsgPort *port;
{
   BUG(1, ("InitST: Enter, port 0x%08.9x\n", port))

   memset((char *)&stg, 0, sizeof(struct STGLOB));
   stg.Port = port;

   BUG(1, ("InitST: Exit\n"))
   return(RC_OK);
}

int TermST()
{
   int rc;
   struct STNODE *tmpnode;
   struct Message *msg;

   BUG(1, ("TermST: Enter\n"))

   while(stg.stlist)
   {
      if(RC_OK != (rc=UnlinkST(stg.stlist->w)))
      {
         BUG(1, ("TermST: Can't UnLink %08lx, rc %d\n", stg.stlist, rc))
         tmpnode = stg.stlist;
         if(stg.stlist = stg.stlist->next)
            stg.stlist->prev = NULL;
         FreeMem(tmpnode, tmpnode->len);
      }
   }

   /* Make sure the port is clear */
   while(msg=GetMsg(stg.Port)) ReplyMsg(msg);

   PurgeST();

   BUG(1, ("TermST: Exit\n"))

   return(RC_OK);
}

struct Window *AllocST(type, data, olen)
int type;
APTR data;
int olen;
{
   struct STNODE *stnode;
   int len, dlen, rc;
   char *tmpchar;
   struct NewWindow *nw;
   struct IntuiText *it;

   BUG(1, ("AllocST: Enter, type %d data 0x%08x len %d\n",
      type, data, olen))

   if(data == NULL)
      len = olen + stsize[type];
   else 
      len = 0;
   dlen = len;

   len += ROUND(sizeof(struct STNODE));

   BUG(5, ("AllocST: dlen %d len %d\n"))

   if(!(tmpchar=(char *)AllocMem(len, MEMF_CLEAR)))
      return(NULL);

   stnode = (struct STNODE *)tmpchar;

   if(dlen > 0)
      data = (APTR)(tmpchar+ROUND(sizeof(struct STNODE)));

   sprintf(stnode->wname, wnames[type], ++stg.count[type]);

   stnode->d.data = data;

   if(type == ST_DATA || type == ST_VIEW)
      stnode->d.bdata->size = olen;

   stnode->len = len;
   stnode->type = type;
   stnode->num = stg.count[type];


   /* Now open the window */
   switch(type)
   {
      case ST_HANDLE: stfhnew(  &nw, &it, stnode); break;
      case ST_LOCK:   stlocknew(&nw, &it, stnode); break;
      case ST_FIB:    stfibnew( &nw, &it, stnode); break;
      case ST_INFO:   stinfnew( &nw, &it, stnode); break;
      case ST_DATA:   stbufnew( &nw, &it, stnode); break;
      case ST_VIEW:   
         stnode->d.vdata->lines = CountLines(stnode->d.vdata->buf, 
            olen-sizeof(struct VIEWDATA));
         stviewnew( &nw, &it, stnode); 
         break;
      default:
         BUG(1, ("AllocST: Unknown type code %d\n", type))
         FreeMem((char *)stnode, len);
         return(NULL);
   }  

   if(nw)
   {
      nw->IDCMPFlags = NULL;   /* Just 'cause PW keeps insisting... */
      nw->Title = stnode->wname;
      if(!(stnode->w = OpenWindow(nw))) 
      {
         BUG(2, ("AllocST: Couldn't open window\n"))
         goto ERRSPOT;
      }
      if(it) PrintIText(stnode->w->RPort, it, 0, 0);
   }
   else
   {
      BUG(2, ("AllocST: No new window\n"))
      goto ERRSPOT;
   }


   BUG(2, ("AllocST: Opened window 0x%08x\n", stnode->w))

   /* Set up the UserData pointer to point to the STNode structure so */
   /* we can find stnode from the window pointer later on             */
   stnode->w->UserData = (BYTE *)stnode;


   /**********************************************************************/
   /* We want to use the same UserPort for all our windows;  to do this, */
   /* we allocated the window above with NULL for its IDCMPFlags.        */
   /* Intuition sees the NULL and doesn't initialize the IDCMP.  We can  */
   /* then set up the UserPort field to point to our own port;  after    */
   /* doing so, a call to ModifyIDCMP will set up the rest of the        */
   /* required fields.                                                   */
   /**********************************************************************/

   stnode->w->UserPort = stg.Port;
   ModifyIDCMP(stnode->w, MENUPICK|ACTIVEWINDOW|INACTIVEWINDOW|CLOSEWINDOW|
                          GADGETUP|NEWSIZE|RAWKEY);

   SetMenuStrip(stnode->w, &Menu1);

   if(rc = DisplayST(stnode->w))
   {
      BUG(1, ("AllocST: Bad RC from DisplayST = %d\n", rc))
      goto ERRSPOT;
   }

   if(stg.stlist) stg.stlist->prev = stnode;
   stnode->next = stg.stlist;
   stg.stlist = stnode;

   BUG(1, ("AllocST: Exit, returning %08lx\n", stnode->w))

   return(stnode->w);

ERRSPOT:
   if(type == ST_VIEW) 
   {
      FreeMem((char *)data, olen);
      stnode->d.data = NULL;
   }
   stnode->type = ST_UNLINKED;

   if(stg.unlist) stg.unlist->prev = stnode;
   stnode->next = stg.unlist;
   stg.unlist = stnode;
   
   BUG(1, ("AllocST: ERROR EXIT, returning NULL\n"))
   return(NULL);
}

int WindSize(window)
struct Window *window;
{
   struct STNODE *n;

   n = (struct STNODE *)window->UserData;
   if (n->type == ST_DATA)
      return(n->d.bdata->size);
   return(0);
}
   
void MoveWind(window, dir)
struct Window *window;
int dir;
{
   struct STNODE *n;
   if(!window) return;

   n = (struct STNODE *)window->UserData;
   switch(n->type)
      {
      case ST_DATA: stbufmove(n, dir);  break;
      case ST_VIEW: stviewmove(n, dir); break;
      default:      DisplayST(window);  break;
      }
}

#define NAMELEN 50

int NameST(window, name, pid)
struct Window *window;
char *name;
struct MsgPort *pid;
{
   struct STNODE *n;
   int rc;

   BUG(1, ("NameST: Entry, window 0x%08x name %s\n", window,
      name == NULL ? "NULL" : name))

   if(!window) return(RC_ERRNOWIND);

   n = (struct STNODE *)window->UserData;

   n->pid = pid;

   if(!name)
   {
      if(n->oname) FreeMem(n->oname, NAMELEN);
      n->oname = NULL;
   }
   else
   {
      if(!n->oname) 
      {
         if(!(n->oname = AllocMem(NAMELEN, 0)))
            return(RC_ERRNOMEM);
      }

      memset(n->oname, ' ', NAMELEN-1);
      memcpy(n->oname, name, min(strlen(name), NAMELEN-1));
      n->oname[NAMELEN-1] = '\0';
   }

   rc = DisplayST(window);

   BUG(1, ("NameST: Exit, returning %d\n", rc))

   return(rc);
}

APTR FindST(name, type)
char *name;
int type;
{
   struct STNODE *n;
   BUG(1, ("FindST: Entry, name '%s'\n", name))

   for(n=stg.stlist; n; n=n->next)
   {
      if(!stricmp(name, n->wname) && n->type == type)
      {
         if(type == ST_DATA) 
         {
            BUG(1, ("FindST: Exit, returning 0x%08x\n", n->d.bdata->buf))
            return((APTR)n->d.bdata->buf);
         }
         BUG(1, ("FindST: Exit, returning 0x%08x\n", n->d.data))
         return(n->d.data);
      }
   }
   BUG(1, ("FindST: Exit, no match\n"))
   return(NULL);
}

APTR WindToST(window)
struct Window *window;
{
   BUG(1, ("WindToST: Entry, Exit, returning 0x%08x\n",
      ((struct STNODE *)window->UserData)->d.data))
   if(!window) return(NULL);
   return((((struct STNODE *)window->UserData)->d.data));
}

struct Window *STToWind(data)
APTR data;
{
   struct STNODE *n;
   BUG(1, ("STToWind: Entry, looking for 0x%08x\n", data))

   for(n=stg.stlist; n; n=n->next)
   {
      if(n->d.data == data ||
         (n->type == ST_HANDLE && n->d.fh->fh_Arg1 == (BPTR)data) ||
         (n->type == ST_DATA && n->d.bdata->buf == (char *)data)
        )
      {
         BUG(1, ("STToWind: returning 0x%08x\n", n->w))
         return(n->w);
      }
   }
   BUG(1, ("STToWind: returning NULL\n"))
   return(NULL);
}

int DisplayST(window)
struct Window *window;
{
   struct STNODE *n;
   int rc;

   BUG(1, ("DisplayST: Enter, window 0x%08x\n", window))

   if(!window) return(RC_ERRNOWIND);

   n = (struct STNODE *)window->UserData;
   if(n->type == ST_UNLINKED) return(RC_UNLINKED);

   switch(n->type)
   {
      case ST_HANDLE:  rc = stfhdisp(n);      break;
      case ST_LOCK:    rc = stlockdisp(n);    break;
      case ST_FIB:     rc = stfibdisp(n);     break;
      case ST_INFO:    rc = stinfdisp(n);     break;
      case ST_DATA:    rc = stbufdisp(n);     break;
      case ST_VIEW:    rc = stviewdisp(n);    break;
      default:
         BUG(1, ("DisplayST: Bad type %d\n", n->type))
         rc = RC_ERRBADTYPE; 
         break;
   }

   BUG(1, ("DisplayST: Exit, returning %d\n", rc))
   return(rc);
}

int UnlinkST(window)
struct Window *window;
{
   struct STNODE *n;
   char msg[100];

   BUG(1, ("UnlinkST: Enter, window 0x%08x\n", window))

   if(!window) return(RC_ERRNOWIND);

   n = (struct STNODE *)window->UserData;

   /* We don't want the user generating any more IDCMP messages for this */
   /* window, so clear its menus and modify the IDCMP flags to only give */
   /* menu selections.  We can't send 0 for the flags or it would free   */
   /* the IDCMP port stuff, which would crash us.                        */
   ClearMenuStrip(window);
   ModifyIDCMP(window, MENUPICK);

   window->UserPort = NULL;

   if(n->type == ST_LOCK && n->oname && n->oname[0] != ' ')
   {
      long arg;
      arg = (long)MKBADDR(n->d.lock);
      sendpkt(n->pid, ACTION_FREE_LOCK, &arg, 1, NULL);
      sprintf(msg, "%s was unlocked on your behalf", n->wname);
      n->d.lock = NULL;
      status(msg);
   }
   else if(n->type == ST_HANDLE && n->oname && n->oname[0] != ' ')
   {
      sendpkt(n->pid, ACTION_END, &n->d.fh->fh_Arg1, 1, NULL);
      n->oname[0] = ' ';
      sprintf(msg, "%s was closed on your behalf", n->wname);
      status(msg);
   }
   else if(n->type == ST_VIEW)
   {
      FreeMem((char *)n->d.vdata, n->d.vdata->size);
      n->d.vdata = NULL;
   }

   n->type = ST_UNLINKED;
   if(n->next) n->next->prev = n->prev;
   if(n->prev) n->prev->next = n->next;
   else        stg.stlist = n->next;

   if(stg.unlist) stg.unlist->prev = n;
   n->next = stg.unlist;
   stg.unlist = n;

   BUG(1, ("UnlinkST: Exit\n"))

   return(RC_OK);
}

int PurgeST()
{
   struct STNODE *n, *p;

   BUG(1, ("PurgeST: Enter\n"))

   p=stg.unlist;
   stg.unlist = NULL;
   while(p)
   {
      BUG(5, ("PurgeST: Closing window 0x%08x\n"))

      n = p->next;
      CloseWindow(p->w);

      BUG(8, ("PurgeST: Freeing STNODE type %d, %d bytes\n", 
         p->type, p->len))

      if(p->oname) FreeMem(p->oname, NAMELEN);

      FreeMem((char *)p, p->len);
      p=n;
   }

   BUG(1, ("PurgeST: Exit\n"))
   
   return(RC_OK);
}

