#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/libraries.h>
#include <exec/execbase.h>
#include <dos/dos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>

#include <stdio.h>

#include "global.h"
#include "libinfo.h"
#include "output.h"
#include "flush.h"

extern struct ExecBase *SysBase;

/*
** Flush specified library
*/
void FlushLib(STRPTR LibName)
{
  struct Library *Library;
  struct LibInfo *LibInfoItem = NULL;
  
  Forbid();  /* Keep the system to ourself */
  
  Library = (struct Library *)FindName(&SysBase->LibList,LibName);
  if (Library)
  {
    /* OK, we found the library, now let's try to remove it... */
    LibInfoItem = AddLibInfoItem(NULL,Library);  /* Save inportant info... */
    if (LibInfoItem)
    {
      /* Only attempt to flush a library if it isn't being used */
      if (LibInfoItem->OpenCount == 0)
      {
        RemLibrary(Library);
        
        /* Here's an idea - let's search the LibList again.  If the */
        /* Library isn't there, we must have flushed it             */
        if (!FindName(&SysBase->LibList,LibName))
          /* Yay, we got rid of the library! */
          LibInfoItem->Flushed = TRUE;
      }
    }
  }
  
  Permit();  /* OK, back to the ol' multitasking */
  
  if (Library)
  {
    /* The library was present, now we'll see if we flushed it */
    if (LibInfoItem)
    {
      if (LibInfoItem->Flushed)
        OutputFlushedLibInfo(LibInfoItem);
    
      FreeVec((APTR)LibInfoItem);  /* Don't need this memory any more */
    }
    else
    {
      /* Well, we run out of memory. So we're outa here! */
      fputs("Error: Out of memory!\n",stderr);
      clean_exit(20);
    }
  }
  else
    /* The library wasn't found in memory */
    OutputLibNotFound(LibName);
}

  
/*
** Flush all libraries from memory
*/
void FlushLibs(void)
{
  struct List *LibInfoList;
  struct LibInfo *LibInfoItem;
  ULONG FlushCount;
  
  Forbid();  /* Can't have anyone messing up the Library list while we are */
  
  LibInfoList = BuildLibInfoList();
  if (LibInfoList)
  {
    /* Some libraries open others, so we gotta go round and round until */
    /* we get them all                                                  */
    do
    {
      FlushCount = 0;
      LibInfoItem = (struct LibInfo *)LibInfoList->lh_Head;
      while (LibInfoItem->li_Node.ln_Succ)
      {
        /* Don't try to flush anything that's already been flushed */
        /* or is still open ...                                    */
        if ((LibInfoItem->Flushed == FALSE) &&
            (LibInfoItem->OpenCount == 0))
        {
          /* Attemp to flush the library... */
          RemLibrary((struct Library *)LibInfoItem->Address);
          
          /* Check that the library is really gone... */
          if (!FindName(&SysBase->LibList,LibInfoItem->Name))
          {
            LibInfoItem->Flushed = TRUE;
            FlushCount++;
          }
        }
        
        /* Move Along */
        LibInfoItem = (struct LibInfo *)LibInfoItem->li_Node.ln_Succ;
      }
    } while (FlushCount != 0);
    /* Flush count will only be zero if no libraries were flushed, */
    /* hence no more libraries need to be flushed                  */
  }
  
  Permit();
  
  if (!LibInfoList)
  {
    /* Outta memory */
    fputs("Error: Out of memory!\n",stderr);
    clean_exit(20);
  }
  
  /* Goody, now we have a list of libraries with flushing info */
  LibInfoItem = (struct LibInfo *)LibInfoList->lh_Head;
  while (LibInfoItem->li_Node.ln_Succ)
  {
    if (LibInfoItem->Flushed)
      OutputFlushedLibInfo(LibInfoItem);
    
    LibInfoItem = (struct LibInfo *)LibInfoItem->li_Node.ln_Succ;
  }
  
  KillLibInfoList(LibInfoList);
}
