#include <exec/types.h>
#include <exec/memory.h>

#include <graphics/gfx.h>
#include <graphics/displayinfo.h>

#include <intuition/intuitionbase.h>
#include <intuition/gadgetclass.h>

#include <datatypes/datatypes.h>
#include <datatypes/datatypesclass.h>
#include <datatypes/pictureclass.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <proto/datatypes.h>

#include <string.h>
#include <stdio.h>


struct Picture
{
	struct BitMapHeader bmhd;	/* format i info */
	struct BitMap *bmap;			/* bitmapa */
	ULONG *palette;				/* paleta w formacie LoadRGB32() */
	LONG palette_size;			/* rozmiar palety */
	LONG palette_entries;		/* liczba kolorów */
	ULONG display_ID;				/* video mode */
};

void FreePicture(struct Picture *pic);
LONG GetDataTypesPicture(UBYTE *file_name, struct Picture *pic, ULONG);
BOOL IsDataTypes(UBYTE *file_name);
void ViewPicture(struct Picture *pic);

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *DataTypesBase;



/*
	IsDataTypes - sprawdzenie czy rozpoznawalny przez DT

	Parametery:
		file_name: nazwa pliku do sprawdzenia

	Wyjôcie
		TRUE jeôli plik rozpoznawalny przez DT jako obrazek
		FALSE w innych wypakdach
*/
BOOL IsDataTypes(UBYTE *file_name)
{
	struct DataType *dtn;
	struct DataTypeHeader *dth;
	BPTR lock;
	BOOL it_is;

	it_is = FALSE;
	if(lock = Lock(file_name, ACCESS_READ))
	{
		/* sprawdzamy plik */
		if(dtn = ObtainDataTypeA(DTST_FILE, (APTR)lock, NULL))
		{
			dth = dtn->dtn_Header;

			if(dth->dth_GroupID == GID_PICTURE)	/* obrazek? */
				it_is = TRUE;

			ReleaseDataType(dtn);
		}
		UnLock(lock);
	}
	return(it_is);
}


/*
	GetDataTypesPicture - informacje o obrazku

	Parametery
		file_name: nazwa pliku
		pic: pomocnicza struktura
		bmap_flags: flagi dla AllocBitMap()
						(np. BMF_DISPLAYABLE, BMF_INTERLEAVED)

	Wyjôcie
		0 jeôli wszysto OK i dane sâ w pic lub
		kod bîëdu jak w dos/IoErr()
*/
LONG GetDataTypesPicture(UBYTE *file_name, struct Picture *pic, ULONG bmap_flags)
{
	Object *obj;
	struct BitMapHeader *bmh;
	struct BitMap *bmap;
	struct gpLayout layout;
	ULONG *creg, *ctab;
	LONG ncol, crsize;
	LONG err = 0;

	/* nowy obiekt DT - obrazek */
	if(obj = NewDTObject(file_name,
								DTA_SourceType, DTST_FILE,
								DTA_GroupID, GID_PICTURE,
								PDTA_Remap, FALSE,
								TAG_DONE))
	{
		/* pobierz bitmap_header i mode_id */
		if(GetDTAttrs(obj,
							PDTA_ModeID, &pic->display_ID,
							PDTA_BitMapHeader, &bmh,
							TAG_DONE) == 2)
		{
			pic->bmhd = *bmh;

			/* render the object */
			layout.MethodID = DTM_PROCLAYOUT;
			layout.gpl_GInfo = NULL;
			layout.gpl_Initial = TRUE;

			if(DoDTMethodA(obj, NULL, NULL, (Msg)&layout))
			{
				/* pobierz bitmapë i kolory */
				if(GetDTAttrs(obj,
									PDTA_BitMap, &bmap,
									PDTA_CRegs, &creg,
									PDTA_NumColors, &ncol,
									TAG_DONE) == 3)
				{
					crsize = (ncol * 3) * 4;
					pic->palette_entries = ncol;
					/* wymogi LoadRGB32(): */
					pic->palette_size = crsize + (2 * 4);

					/* przepisanie palety */
					if(pic->palette = AllocMem(pic->palette_size, 0))
					{
						ctab = pic->palette;
						// liczba kolorów i pierwszy kolor:
						*ctab++ = (ncol << 16) | 0;
						memcpy(ctab, creg, crsize);
						*(ctab + (crsize / 4)) = 0;	// "terminator"
					}
					else
						err = ERROR_NO_FREE_STORE;

					if(pic->bmap = AllocBitMap(pic->bmhd.bmh_Width, pic->bmhd.bmh_Height,
														pic->bmhd.bmh_Depth, bmap_flags, NULL))
					{
						BltBitMap(bmap, 0, 0, pic->bmap, 0, 0,
										pic->bmhd.bmh_Width, pic->bmhd.bmh_Height,
										0xC0, 0xFF, NULL);
						WaitBlit();
					}
					else
						err = ERROR_NO_FREE_STORE;
				}
				else
					err = IoErr();
			}
			else
				err = IoErr();
		}
		else
			err = ERROR_REQUIRED_ARG_MISSING;

		DisposeDTObject(obj);	/* zwolnij objekt DT */
	}
	else
		err = IoErr();

	if(err)
		FreePicture(pic);

	return(err);
}


/*
	FreePicture - zwolnienie danych ze struktury pomocniczej

	Parametery
		pic: structura pomocnicza
*/
void FreePicture(struct Picture *pic)
{
	if(pic->bmap)
	{
		WaitBlit();
		FreeBitMap(pic->bmap);
	}

	if(pic->palette)
		FreeMem(pic->palette, pic->palette_size);
}


/*
	ViewPicture - pokazanie obrazka

	Parametery
		pic: struktura opisujâca caîoôê
*/
void ViewPicture(struct Picture *pic)
{
	struct Screen *scr;
	struct Window *win;

	/* otwarcie odpowiedniego ekranu */
	if(scr = OpenScreenTags(NULL,
					SA_Width, pic->bmhd.bmh_Width,
					SA_Height, pic->bmhd.bmh_Height,
					SA_Depth, pic->bmhd.bmh_Depth,
					SA_ShowTitle, FALSE,	/* no title bar */
					SA_Behind, TRUE,
					SA_Type, CUSTOMSCREEN,
					SA_DisplayID, pic->display_ID,
					SA_Overscan, OSCAN_TEXT,
					SA_AutoScroll, TRUE,
					SA_Colors32, pic->palette,
					/* no screen-clearing when the window is closed (is faster) */
					SA_BackFill, LAYERS_NOBACKFILL,
					TAG_END))
	{
		/* otwarcie okna */
		if(win = OpenWindowTags(NULL,
					WA_Width, scr->Width,
					WA_Height, scr->Height,
					/* wyjôcie przez naciôniëcie myszy lub klawisza */
					WA_IDCMP, MOUSEBUTTONS | RAWKEY,
					WA_CustomScreen, scr,
					WA_Backdrop, TRUE,
					WA_Borderless, TRUE,
					WA_Activate, TRUE,
					WA_RMBTrap, TRUE,
					WA_SimpleRefresh, TRUE,
					/* no screen-clearing when the window is opened (is faster) */
					WA_BackFill, LAYERS_NOBACKFILL,
					TAG_END))
		{
			/* skopiowanie bitmapy do okna */
			BltBitMap(pic->bmap, 0, 0, scr->RastPort.BitMap,
							0, 0, pic->bmhd.bmh_Width, pic->bmhd.bmh_Height,
							0xC0, 0xFF, NULL);
			WaitBlit();
			ScreenToFront(scr);

			/* czekanie na dowolny komunikat w oknie i wyôcie */
			Wait(1 << win->UserPort->mp_SigBit);
			CloseWindow(win);
		}
		CloseScreen(scr);
	}
}


void main(int argc, char *argv[])
{
	struct Picture pic;

	if(argc == 2)
	{
		if(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 39))
		{
			if(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 39))
			{
				if(DataTypesBase = OpenLibrary("datatypes.library", 39))
				{
					if(IsDataTypes(argv[1]))
					{
						if(!GetDataTypesPicture(argv[1], &pic, 0))
						{
							printf("%s (%dx%d, %d colors)\n",
										argv[1],
										pic.bmhd.bmh_Width, pic.bmhd.bmh_Height,
										pic.palette_entries);
							ViewPicture(&pic);
							FreePicture(&pic);
						}
					}
					CloseLibrary(DataTypesBase);
				}
				CloseLibrary((struct Library *)GfxBase);
			}
			CloseLibrary((struct Library *)IntuitionBase);
		}
	}
}
