/*
**  BMP DataType
**  Written by Gunther Nikl (gnikl@informatik.uni-rostock.de)
*/

#include "classbase.h"

/****************************************************************************/

#define VERSION  40
#define REVISION  8
#define IDSTRING "bmp 40.8 (3.6.97) by Gunther Nikl\r\n"

#if !defined(mc68020) && !defined(mc68030) && !defined(mc68040) && !defined(mc68060)
#define REQUIRES_68020(x) (0)
#else
#define REQUIRES_68020(x) ((((struct ExecBase *)x)->AttnFlags & AFF_68020) == 0)
#endif

#define IntuitionBase cb->IntuitionBase

/****************************************************************************/

  // First executable routine of this library; must return an error
  // to the unsuspecting caller

LONG
ReturnError(VOID)
{
  return -1;
}

/****************************************************************************/

  /* CloseLibraries(struct ClassBase *cb):
   *
   *  Closes all the libraries opened by LibrarySetup().
   */

STATIC VOID
CloseLibraries(struct ClassBase *cb)
{
  struct Library *SysBase = cb->SysBase;

  CloseLibrary(cb->SuperClassBase);
  cb->SuperClassBase = NULL;

  CloseLibrary(cb->DataTypesBase);
  cb->DataTypesBase = NULL;

  CloseLibrary(cb->UtilityBase);
  cb->UtilityBase = NULL;

  CloseLibrary(cb->GfxBase);
  cb->GfxBase = NULL;

  CloseLibrary(IntuitionBase);
  IntuitionBase = NULL;

  CloseLibrary(cb->DOSBase);
  cb->DOSBase = NULL;
}

  /* GetClassEngine(REG(a6) struct ClassBase *cb):
   *
   *  Get access to the class this library implements.
   */

struct IClass *
GetClassEngine(struct ClassBase *cb REG(a6))
{
  return cb->PictureClass;
}

  /* LibReserved(VOID):
   *
   *  The mandatory reserved library function.
   */

LONG
LibReserved(VOID)
{
  return 0;
}

  /* LibExpunge(REG(a6) struct ClassBase *cb):
   *
   *  Expunge the library, remove it from memory
   */

BPTR
LibExpunge(struct ClassBase *cb REG(a6))
{
  BPTR Result = 0;

  // Expunge it later

  cb->LibNode.lib_Flags |= LIBF_DELEXP;

  // Can we get away with this?

  if (!cb->LibNode.lib_OpenCnt && !cb->PictureClass) {

    struct Library *SysBase = cb->SysBase;

    // Return the seglist, so it can be unloaded

    Result = cb->SegList;

    // Remove the library from the public list

    Remove((struct Node *)cb);

    // Free the vector table and the library data

    FreeMem((UBYTE *)cb-cb->LibNode.lib_NegSize,cb->LibNode.lib_NegSize+cb->LibNode.lib_PosSize);
  }

  // Return the segment pointer, if any

  return Result;
}

STATIC inline struct IClass *AttemptFreeClass(struct ClassBase *cb)
{
  struct IClass *cl;

  if ((cl=cb->PictureClass) != NULL && FreeClass(cl))
    cl=0;
  return cl;
}

  /* LibClose(REG(a6) struct ClassBase *cb):
   *
   *  Close the library, as called by CloseLibrary()
   */

BPTR
LibClose(struct ClassBase *cb REG(a6))
{
  BPTR Result = 0;

  // Decrement usage count and check how
  // many customers we still have

  if (!cb->LibNode.lib_OpenCnt || !--cb->LibNode.lib_OpenCnt) {

    struct Library *SysBase = cb->SysBase;

    // We are going to modify shared data,
    // so watch out

    ObtainSemaphore(&cb->LockSemaphore);

    // Clean up; note that if AttemptFreeClass()
    // fails the behaviour of this library is
    // somewhat undefined. The best the code can
    // do is try not to crash the machine due to
    // this kind of error.

    if ((cb->PictureClass=AttemptFreeClass(cb)) == NULL)
      CloseLibraries(cb);

    // Release the lock

    ReleaseSemaphore(&cb->LockSemaphore);

    // Can we remove ourselves?

    if (cb->LibNode.lib_Flags & LIBF_DELEXP)
      Result = LibExpunge(cb);
  }

  return Result;
}

const char pictDTname[] = "datatypes/picture.datatype";

STATIC inline struct IClass *CreateClass(struct ClassBase *cb)
{
  struct IClass *cl = MakeClass("bmp.datatype",(UBYTE *)&pictDTname[10],NULL,0,0);
  ULONG Dispatch();

  if (cl != NULL) {
    cl->cl_Dispatcher.h_Entry = (HOOKFUNC)Dispatch; cl->cl_UserData = (ULONG)cb; AddClass(cl);
  }
  return cl;
}

  /* LibOpen(REG(a6) struct ClassBase *cb):
   *
   *  Open the library, as called via OpenLibrary()
   */

struct ClassBase *
LibOpen(struct ClassBase *cb REG(a6))
{
  struct Library *SysBase = cb->SysBase;
  struct ClassBase *Result = cb;

  // We are going to modify data while in multitasking,
  // so watch out

  ObtainSemaphore(&cb->LockSemaphore);

  // Increment the user count and revent delayed expunge

  cb->LibNode.lib_OpenCnt++;
  cb->LibNode.lib_Flags &= ~LIBF_DELEXP;

  // Is this the first initialization ?

  if (1 == cb->LibNode.lib_OpenCnt &&
      ((cb->DOSBase=OpenLibrary("dos.library",39)) == NULL ||
       (IntuitionBase=OpenLibrary("intuition.library",39)) == NULL ||
       (cb->GfxBase=OpenLibrary("graphics.library",39)) == NULL ||
       (cb->UtilityBase=OpenLibrary("utility.library",39)) == NULL ||
       (cb->DataTypesBase=OpenLibrary("datatypes.library",39)) == NULL ||
       (cb->SuperClassBase=OpenLibrary((UBYTE *)&pictDTname[0],39L)) == NULL ||
       (cb->PictureClass=CreateClass(cb)) == NULL))
  {
    CloseLibraries(cb); Result = NULL;
  }

  // Release the lock

  ReleaseSemaphore(&cb->LockSemaphore);

  // Return the library base, if any

  return Result;
}

  /* LibInit():
   *
   *  Initialize the library.
   */

struct ClassBase *
LibInit(BPTR SegList REG(a0),struct ClassBase *cb REG(d0),struct Library *SysBase REG(a6))
{
  // Set up the header data; everything that doesn't get set
  // up here will have been set up by InitResident().

  cb->LibNode.lib_Revision = REVISION;

  // Remember the segment pointer

  cb->SegList = SegList;

  // Remember the exec library base pointer

  cb->SysBase = SysBase;

  // Initialize the shared data access semaphore

  InitSemaphore(&cb->LockSemaphore);

  if ((39>SysBase->lib_Version) || REQUIRES_68020(SysBase)) {
    FreeMem((UBYTE *)cb-cb->LibNode.lib_NegSize,cb->LibNode.lib_NegSize+cb->LibNode.lib_PosSize);
    cb = NULL;
  }

  return cb;
}

/****************************************************************************/

  // This is the table of functions that make up the library. The first
  // four are mandatory, everything following it are user callable
  // routines. The table is terminated by the value -1.

const APTR LibVectors[] = {
  LibOpen,
  LibClose,
  LibExpunge,
  LibReserved,
  GetClassEngine,
  (APTR) -1L
};

  // The following data structures and data are responsible for
  // setting up the Library base data structure and the library
  // function vector.

const ULONG LibInitTable[] = {
  (ULONG) sizeof(struct ClassBase), // Size of the base data structure
  (ULONG) LibVectors,               // Points to the function vector
  (ULONG) NULL,                     // Library base data structure setup table
  (ULONG) LibInit                   // The address of the routine to do the setup
};

/****************************************************************************/

  // The library loader looks for this marker in the memory
  // the library code and data will occupy. It is responsible
  // setting up the Library base data structure.

const struct Resident RomTag = {
  RTC_MATCHWORD,                // Marker value.
  (struct Resident *)&RomTag,   // This points back to itself.
  (struct Resident *)&RomTag+1, // This points behind this marker.
  RTF_AUTOINIT,                 // The Library should be set up according to the given table.
  VERSION,                      // The version of this Library.
  NT_LIBRARY,                   // This defines this module as a Library.
  0,                            // Initialization priority of this Library; unused.
  "bmp.datatype",               // Points to the name of the Library.
  IDSTRING,                     // The identification string of this Library.
  (APTR)&LibInitTable           // This table is for initializing the Library.
};
