#include <intuition/intuitionbase.h>

#include <datatypes/pictureclass.h>

#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <graphics/modeid.h>

#include <dos/dosextens.h>
#include <dos/rdargs.h>

#include <exec/memory.h>

#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/utility_protos.h>
#include <clib/layers_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/alib_protos.h>

#include <string.h>

struct Library * __asm __saveds LibInit(register __a0 BPTR Segment,
                                register __d0 struct Library *Base);
struct Library * __asm __saveds LibOpen(register __a6 struct Library *Base);
BPTR __asm __saveds             LibExpunge(register __a6 struct Library *Base);
BPTR __asm __saveds             LibClose(register __a6 struct Library *Base);
LONG __asm __saveds             LibNull(register __a6 struct Library *Base);

Class * __saveds         GetClassEngine(VOID);

BPTR                     LibSegment  = NULL;
UBYTE __aligned          LibName[]   = "geo.datatype";
UBYTE __aligned          LibID[]     = "geo.datatype 1.0 (11.7.94)\r\n";

struct ExecBase         *SysBase;
struct DosLibrary       *DOSBase;
struct IntuitionBase    *IntuitionBase;
struct GfxBase          *GfxBase;
struct Library          *LayersBase,
                        *UtilityBase,
                        *DataTypesBase,
                        *SuperClassBase;
struct SignalSemaphore   LockSemaphore;
Class                   *ImageClass;

APTR LibVectors[] =  /* die Sprungtabelle */
{   LibOpen,
    LibClose,
    LibExpunge,
    LibNull,
    GetClassEngine,
    (APTR)-1
};

struct { ULONG DataSize; APTR Table; APTR Data; struct Library * (*Init)(); }
    __aligned LibInitTab =
{
    sizeof(struct Library),
    LibVectors,
    NULL,
    LibInit
};

struct Library * __asm __saveds
LibInit(register __a0 BPTR Segment,register __d0 struct Library *Base)
{
    Base -> lib_Node . ln_Type  = NT_LIBRARY;
    Base -> lib_Node . ln_Name  = LibName;
    Base -> lib_Flags           = LIBF_CHANGED | LIBF_SUMUSED;
    Base -> lib_Version         = 1;
    Base -> lib_Revision        = 0;
    Base -> lib_IdString        = LibID;

    LibSegment = Segment;
    SysBase = *(struct ExecBase **)4;
    InitSemaphore(&LockSemaphore);
    return(Base);
}

struct Library * __asm __saveds
LibOpen(register __a6 struct Library *Base)
{
    Base -> lib_OpenCnt++;
    Base -> lib_Flags &= ~LIBF_DELEXP;

    if(Base -> lib_OpenCnt == 1)
    {   ObtainSemaphore(&LockSemaphore);
        if(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",37))
        {   if(IntuitionBase =
                (struct IntuitionBase *)OpenLibrary("intuition.library",37))
            {   if(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",39))
                {   if(UtilityBase = OpenLibrary("utility.library",0))
                    {   if(LayersBase = OpenLibrary("layers.library",0))
                        {   if(DataTypesBase = OpenLibrary("datatypes.library",0))
                            {   if(SuperClassBase =
                                    OpenLibrary("datatypes/picture.datatype",0))
                                {   if(ImageClass = MakeClass("geo.datatype",
                                        PICTUREDTCLASS,NULL,NULL,NULL))
                                    {
                                        extern ULONG ClassDispatch();
                                        ImageClass -> cl_Dispatcher . h_Entry =
                                            (HOOKFUNC)ClassDispatch;
                                        AddClass(ImageClass);
                                        ReleaseSemaphore(&LockSemaphore);
                                        return(Base);
                                    }
                                    CloseLibrary(SuperClassBase);
                                    SuperClassBase = NULL;
                                }
                                CloseLibrary(DataTypesBase);
                                DataTypesBase = NULL;
                            }
                            CloseLibrary(LayersBase);
                            LayersBase = NULL;
                        }
                        CloseLibrary(UtilityBase);
                        UtilityBase = NULL;
                    }
                    CloseLibrary(GfxBase);
                    GfxBase = NULL;
                }
                CloseLibrary(IntuitionBase);
                IntuitionBase = NULL;
            }
            CloseLibrary(DOSBase);
            DOSBase = NULL;
        }
        ReleaseSemaphore(&LockSemaphore);
        return(NULL);
    }
    else
        return(Base);
}

BPTR __asm __saveds
LibExpunge(register __a6 struct Library *Base)
{
    BPTR TempSegment = LibSegment;

    if(!Base -> lib_OpenCnt && TempSegment)
    {   Remove((struct Node *)Base);
        FreeMem((BYTE *)Base - Base -> lib_NegSize,
            Base -> lib_NegSize + Base -> lib_PosSize);
        LibSegment = NULL;
        return(TempSegment);
    }
    else
    {   Base -> lib_Flags |= ~LIBF_DELEXP;
        return(NULL);
    }
}

BPTR __asm __saveds
LibClose(register __a6 struct Library *Base)
{
    if(!(Base -> lib_OpenCnt--)) Base -> lib_OpenCnt = 0;
    if(!Base -> lib_OpenCnt)
    {
        ObtainSemaphore(&LockSemaphore);
        if(ImageClass)
        {   RemoveClass(ImageClass);
            FreeClass(ImageClass);
            ImageClass = NULL;
        }
        CloseLibrary(SuperClassBase); SuperClassBase = NULL;
        CloseLibrary(DataTypesBase);  DataTypesBase = NULL;
        CloseLibrary(LayersBase);     LayersBase = NULL;
        CloseLibrary(UtilityBase);    UtilityBase = NULL;
        CloseLibrary(IntuitionBase);  IntuitionBase = NULL;
        CloseLibrary(GfxBase);        GfxBase = NULL;
        CloseLibrary(DOSBase);        DOSBase = NULL;
        ReleaseSemaphore(&LockSemaphore);
    }
    if((Base -> lib_Flags & LIBF_DELEXP) && !Base -> lib_OpenCnt)
        return(LibExpunge(Base));
    return(NULL);
}

LONG __asm __saveds
LibNull(register __a6 struct Library *Base)
{
    return(NULL);
}

Class * __saveds GetClassEngine()
{   Class *class;
    ObtainSemaphore(&LockSemaphore);
    class = ImageClass;
    ReleaseSemaphore(&LockSemaphore);
    return(class);
}
