#include <intuition/intuitionbase.h>
#include <graphics/gfxbase.h>
#include <datatypes/pictureclass.h>
#include <exec/memory.h>

#include <clib/datatypes_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/alib_protos.h>
#include <clib/macros.h>

#include <stdio.h>

struct IntuitionBase    *IntuitionBase = 0;
struct GfxBase          *GfxBase       = 0;
struct Library          *DataTypesBase = 0;

VOID          CloseAll(VOID);
BOOL          OpenAll(VOID);
VOID          HandleWindow(struct Screen *, struct Window *);
BOOL          ShowPicture(Object *Picture,struct Screen **ScreenPtr,
                          struct Window **WindowPtr);
Object *      LoadPicture(STRPTR Name);

int main(int argc,char **argv)
{   int Result = RETURN_FAIL;

    if(OpenAll())
    {   Object  *Picture;
        int      i;

        Result = RETURN_OK;
        for(i = 1 ; i < argc ; i++)
        {   Printf("Versuche Bild \"%s\" zu laden.\n",argv[i]);

            if(Picture = LoadPicture(argv[i]))
            {   struct Screen   *Screen;
                struct Window   *Window;

                PutStr("Zeige Bild an\n");
                if(ShowPicture(Picture,&Screen,&Window))
                    HandleWindow(Screen,Window);
            }
        }
    }
    CloseAll();
    return(Result);
}

VOID CloseAll()
{
    if (IntuitionBase)
       CloseLibrary((struct Library *)IntuitionBase);
    if (GfxBase)
       CloseLibrary((struct Library *)GfxBase);
    if (DataTypesBase)
       CloseLibrary(DataTypesBase);
}

struct LibTab { STRPTR name; int version; struct Library **l; };
struct LibTab LT[4] = {
{  "intuition.library", 39, &IntuitionBase },
{  "graphics.library",  39, &GfxBase       },
{  "datatypes.library", 39, &DataTypesBase },
{  0L, 0, 0L }};


BOOL OpenAll()
{   int i;

    for (i = 0; LT[i].name != 0L; i++)
    { if (!(*(LT[i].l) = OpenLibrary(LT[i].name,LT[i].version)))
      { Printf("Kann %s v%ld nicht öffnen\n",LT[i].name,LT[i].version);
        return FALSE;
      }
    }
    return(TRUE);
}

VOID HandleWindow(struct Screen *Screen,struct Window *Window)
{
    BOOL                 Done = FALSE;
    struct IntuiMessage *Message;

    do
    {   WaitPort(Window -> UserPort);

        while(Message = (struct IntuiMessage *)GetMsg(Window -> UserPort))
        {
            Done |= (Message -> Class == IDCMP_VANILLAKEY ||
                    (Message -> Class == IDCMP_MOUSEBUTTONS &&
                    !(Message -> Code & IECODE_UP_PREFIX)));
            ReplyMsg((struct Message *)Message);
        }
    }
    while(!Done);

    CloseWindow(Window);
    CloseScreen(Screen);
}

BOOL ShowPicture(Object *Picture,struct Screen **ScreenPtr,
    struct Window **WindowPtr)
{
    ULONG                ModeID,
                        *Colours;
    LONG                 NumColours;
    struct BitMapHeader *BitMapHeader;
    struct BitMap       *BitMap;

    if(GetDTAttrs(Picture,
        PDTA_ModeID,        &ModeID,
        PDTA_CRegs,         &Colours,
        PDTA_NumColors,     &NumColours,
        PDTA_BitMapHeader,  &BitMapHeader,
        PDTA_BitMap,        &BitMap,
    TAG_DONE) == 5)
    {
        if(!ModeNotAvailable(ModeID))
        {
            ULONG *ColourTable;

            if(ColourTable = (ULONG *)AllocVec(
                sizeof(ULONG) * (1 + 3 * NumColours + 1),
                MEMF_ANY | MEMF_CLEAR))
            {
                struct Screen *Screen;

                ColourTable[0] = NumColours << 16;
                CopyMem(Colours,ColourTable + 1,
                    sizeof(ULONG) * 3 * NumColours);

                if(Screen = OpenScreenTags(NULL,
                    SA_Width,       MAX(BitMapHeader -> bmh_Width,
                                        BitMapHeader -> bmh_PageWidth),
                    SA_Height,      MAX(BitMapHeader -> bmh_Height,
                                        BitMapHeader -> bmh_PageHeight),
                    SA_Depth,       BitMapHeader -> bmh_Depth,
                    SA_ShowTitle,   FALSE,
                    SA_Quiet,       TRUE,
                    SA_DisplayID,   ModeID,
                    SA_Interleaved, TRUE,
                    TAG_DONE))
                {
                    struct Window *Window;

                    LoadRGB32(&Screen -> ViewPort,ColourTable);
                    FreeVec(ColourTable);
                    ColourTable = NULL;

                    if(Window = OpenWindowTags(NULL,
                        WA_Left,        0,
                        WA_Top,         0,
                        WA_Width,       Screen -> Width,
                        WA_Height,      Screen -> Height,
                        WA_Activate,    TRUE,
                        WA_Backdrop,    TRUE,
                        WA_Borderless,  TRUE,
                        WA_RMBTrap,     TRUE,
                        WA_IDCMP,       IDCMP_VANILLAKEY | IDCMP_MOUSEBUTTONS,
                        WA_CustomScreen,Screen,
                        TAG_DONE))
                    {
                        BltBitMapRastPort(BitMap,0,0,Window -> RPort,0,0,
                            BitMapHeader -> bmh_Width,
                            BitMapHeader -> bmh_Height,0xC0);

                        DisposeDTObject(Picture);

                        *ScreenPtr = Screen;
                        *WindowPtr = Window;

                        return(TRUE);
                    }
                    CloseScreen(Screen);
                }
                FreeVec(ColourTable);
            }
        }
    }

    DisposeDTObject(Picture);
    return(FALSE);
}

Object *
LoadPicture(STRPTR Name)
{
    Object *Picture;

    if(Picture = NewDTObject(Name,
        DTA_SourceType, DTST_FILE,
        DTA_GroupID,    GID_PICTURE,
        PDTA_Remap,     FALSE,
        TAG_DONE))
    {
        if(DoMethod(Picture,DTM_PROCLAYOUT,NULL,TRUE))
            return(Picture);
        else
            DisposeDTObject(Picture);
    }

    return(NULL);
}
