/* Tile v1.0 */
/* Written in 1995 by Ben Matthew */

/* This code is based on the public domain program ViewDT which was written
by Cloanto , Inc - writers of Personal Paint.  I do not claim to have
written any of the code specifically dealing with the reading of the
datatypes and the images used in the backdrop.  Most of the code in ViewDT
has been left alone - I have adapted the code in several major ways when
dealing with the displaying of the images.  */

/* Because of the nature of this code, none of the below is copyrighted
in any way and is submitted to the public domain in all senses. */

/* Note that we do not pull in proto/datatpes.h because I do not want
to restrict this program to OS 2.1+ users - if proto/#? are included then
SAS will auto open libs at the start.  This way backdrops are not 
available to older Amigas but the rest of the program will work with
OS 2.04 machines! */


//#include <proto/datatypes.h>  /* Old system */
#include <clib/datatypes_protos.h>
#include <pragmas/datatypes_pragmas.h>
//#include <proto/exec.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <proto/intuition.h>
#include <intuition/intuition.h>
#include <datatypes/datatypes.h>
#include <datatypes/pictureclass.h>
#include <exec/exec.h>
#include <dos/dosasl.h>
#include <clib/dos_protos.h>
#include <clib/graphics_protos.h>

#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/datatypes_protos.h>

#include <proto/locale.h>

extern struct Catalog *catalog;

extern void msg(char *msg);

extern struct Library *DataTypesBase;
extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;
extern struct Library *UtilityBase;
extern struct Library *GadToolsBase;
extern struct Library *DiskfontBase;
extern struct Library *AslBase;
extern struct Library *IFFParseBase;
extern struct Library *DOSBase;


struct Picture
{
   struct BitMapHeader bmhd;  /* format and infos */
   struct BitMap *bmap;       /* bitmap */
   ULONG *palette;            /* color table in LoadRGB32() format */
   LONG palette_size;         /* mem usage */
   LONG palette_entries;      /* number of colors */
   ULONG display_ID;          /* video mode */
   UBYTE *author;             /* author info */
   UBYTE *copyright;          /* copyright info */
   UBYTE *annotation;         /* other info */
   LONG author_size;          /* mem usage */
   LONG copyright_size;       /* mem usage */
   LONG annotation_size;      /* mem usage */
};

extern struct Picture piccy;

struct AnchorPath *ap;

void FreePicture(struct Picture *pic);
LONG GetDataTypesPicture(UBYTE *file_name, struct Picture *pic, ULONG, struct Screen *scr);
BOOL IsDataTypes(UBYTE *file_name, UBYTE *name_buff, LONG nbuff_size);
BOOL ViewPicture(struct Picture *pic, struct Window *win, struct Screen *scr, int x, int y);
BOOL loadpic(char *fname, struct Screen *scr);
void pattern(struct Window *win_p, struct Screen *scr,struct Picture pic);
void unloadpic(struct Picture pic);


/*
   IsDataTypes

   Parameters
      file_name: name of the file to inspect
      name_buff: (optional) buffer to store the file format name
      nbuff_size: size of name_buff

   Return value
      TRUE if DataTypes recognized the file as a valid picture file
      FALSE otherwise
*/
BOOL IsDataTypes(UBYTE *file_name, UBYTE *name_buff, LONG nbuff_size)
{
   struct DataType *dtn;
   struct DataTypeHeader *dth;
   BPTR lock;
   BOOL it_is;

   it_is = FALSE;
   if (lock = Lock(file_name, ACCESS_READ))
   {
      /* inspect file */
      if (dtn = ObtainDataTypeA(DTST_FILE, (APTR)lock, NULL))
      {
         dth = dtn->dtn_Header;
         if (dth->dth_GroupID == GID_PICTURE)   /* is it a picture? */
         {
            it_is = TRUE;
            if (name_buff)
            {
               strncpy(name_buff, dth->dth_Name, nbuff_size);
               *(name_buff + nbuff_size - 1) = 0;  /* safe strncpy() termination */
            }
         }
         ReleaseDataType(dtn);
      }
      UnLock(lock);
   }
   return(it_is);
}

/*
   GetDataTypesPicture

   Parameters
      file_name: name of the file to load
      pic: work structure
      bmap_flags: AllocBitMap() flags (BMF_DISPLAYABLE, BMF_INTERLEAVED etc.)

   Return value
      0 if successful (picture info and data in "pic" structure) or
      error code as from dos.library IoErr() function
*/
LONG GetDataTypesPicture(UBYTE *file_name, struct Picture *pic, ULONG bmap_flags, struct Screen *scr)
{
   Object *obj;
   struct BitMapHeader *bmh;
   struct BitMap *bmap;
   struct gpLayout layout;
   ULONG *creg, *ctab;
   UBYTE *str;
   LONG ncol, crsize, err;

   memset(pic, 0, sizeof(struct Picture));   /* clear pic structure */
   err = 0;

   if (obj = NewDTObject(file_name,
		DTA_SourceType, DTST_FILE,
		DTA_GroupID, GID_PICTURE,
		PDTA_Remap, FALSE,
		PDTA_Screen, scr,
	TAG_DONE))    /* get the picture object */
   {
      
      if (GetDTAttrs(obj,
                     PDTA_ModeID, &pic->display_ID,
                     PDTA_BitMapHeader, &bmh,
                     TAG_DONE) == 2)   /* get the bitmap_header and mode_id */
      {
         pic->bmhd = *bmh;

         /*
            query the object about its author, copyright and annotation
         */
         if (GetDTAttrs(obj, DTA_ObjAuthor, &str, TAG_DONE) == 1)
         {
            if (str)
            {
               pic->author_size = strlen(str) + 1;
               if (pic->author = AllocMem(pic->author_size, 0))
                  strcpy(pic->author, str);
            }
         }
         if (GetDTAttrs(obj, DTA_ObjCopyright, &str, TAG_DONE) == 1)
         {
            if (str)
            {
               pic->copyright_size = strlen(str) + 1;
               if (pic->copyright = AllocMem(pic->copyright_size, 0))
                  strcpy(pic->copyright, str);
            }
         }
         if (GetDTAttrs(obj, DTA_ObjAnnotation, &str, TAG_DONE) == 1)
         {
            if (str)
            {
               pic->annotation_size = strlen(str) + 1;
               if (pic->annotation = AllocMem(pic->annotation_size, 0))
                  strcpy(pic->annotation, str);
            }
         }

         layout.MethodID = 	DTM_PROCLAYOUT;   /* render the object (PROC)*/
         layout.gpl_GInfo = NULL;
         layout.gpl_Initial = 1;
         
		//DoAsyncLayout(obj,&layout);
         if (DoDTMethodA(obj, NULL, NULL, (Msg)&layout)) {
         
         //if(1) {
            if (GetDTAttrs(obj,
                           PDTA_DestBitMap, &bmap,
                           PDTA_CRegs, &creg,
                           PDTA_NumColors, &ncol,
                           TAG_DONE) == 3)   /* get the bitmap and its colors */
            {
               if (bmap != NULL && creg != NULL && ncol != 0)
               {
                  crsize = (ncol * 3) * 4;
                  pic->palette_entries = ncol;
                  pic->palette_size = crsize + (2 * 4);  /* LoadRGB32() table requirements */

                  if (pic->palette = AllocMem(pic->palette_size, 0))
                  {
                     ctab = pic->palette;
                     *ctab++ = (ncol << 16) | 0;   /* number of colors and first color to load */
                     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, bmap))
                  {
                     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 = ERROR_REQUIRED_ARG_MISSING;
            }
            else err = IoErr();
         }
         else err = IoErr();
      }
      else err = ERROR_REQUIRED_ARG_MISSING;

      DisposeDTObject(obj);   /* free the object */
   }
   else err = IoErr();

   if (err)
      FreePicture(pic);

   return(err);
}

/*
   FreePicture

   Parameters
      pic: Picture structure with resources to free

   Return value
      none
*/
void FreePicture(struct Picture *pic)
{
   if (pic->bmap)
   {
      WaitBlit();
      FreeBitMap(pic->bmap);
   }
   if (pic->palette)
      FreeMem(pic->palette, pic->palette_size);

   if (pic->author)
      FreeMem(pic->author, pic->author_size);

   if (pic->copyright)
      FreeMem(pic->copyright, pic->copyright_size);

   if (pic->annotation)
      FreeMem(pic->annotation, pic->annotation_size);

   memset(pic, 0, sizeof(struct Picture));   /* clear it all */
}

/*
   ViewPicture

   Parameters
      pic: picture infos and data

   Return value
      TRUE if the user cancelled the view sequence (<Esc> key)
      FALSE otherwise
*/
BOOL ViewPicture(struct Picture *pic, struct Window *win, struct Screen *scr, int x, int y)
{
	int width=0, height=0;


	width=pic->bmhd.bmh_Width;
	height=pic->bmhd.bmh_Height;

	if(width+x > win->Width-18) width=(win->Width-18)-x;
	if(height+y > win->Height-scr->WBorBottom) height=win->Height-(scr->WBorBottom)-y;

	if(width < 1 || height < 1) return(0);


   BltBitMapRastPort(pic->bmap, 0,0, win->RPort, x/*+win->LeftEdge*/,y/*+win->TopEdge*/, width, height, 0xC0/*, 0xFF, NULL*/);
   WaitBlit();
   return(1);
}

BOOL loadpic(char *fname, struct Screen *scr) {

	UBYTE pic_type[80];
	LONG err;
	BOOL flag=FALSE;
	
	if(!strcmp(fname,""))
		return(0);

	DataTypesBase=OpenLibrary("datatypes.library",0);
		if(!DataTypesBase) {
			msg(GetCatalogStr(catalog,31,"Sorry I am unable to open datatypes.library!"));
			return(0);
		}

		ap=AllocMem(sizeof(struct AnchorPath) + 240, MEMF_CLEAR);
		if(!ap) {
			msg(GetCatalogStr(catalog,30,"Unable to allocate memory for backdrop!"));
			CloseLibrary(DataTypesBase);
			return(0);
		}

		ap->ap_Strlen=240;

		for (err=MatchFirst(fname,ap); err==0; err=MatchNext(ap)) {
			if(IsDataTypes(ap->ap_Buf, pic_type, 80)) {
				if(GetDataTypesPicture(ap->ap_Buf, &piccy, 0, scr) == 0) 
					flag=TRUE;
			}
		}
	MatchEnd(ap);
	FreeMem(ap,sizeof(struct AnchorPath) + 240);

	CloseLibrary(DataTypesBase);

	return(flag);

}

void pattern(struct Window *win_p, struct Screen *scr,struct Picture pic) {
	int i=0, hcount=0, vcount=0 ,p=0;

	if(!win_p) {
			msg("Error loading backdrop (Debug: No win_p)");
			return;
		}

	hcount=win_p->Width-(scr->WBorLeft+18);
	hcount=hcount/pic.bmhd.bmh_Width;
	hcount++;
	vcount=win_p->Height-(scr->BarHeight+scr->WBorBottom+1);
	vcount=vcount/pic.bmhd.bmh_Height;
	vcount++;
	for(p=0; p<vcount; p++) {
		for(i=0; i<hcount; i++) {
				ViewPicture(&pic, win_p, scr, scr->WBorLeft+(i*pic.bmhd.bmh_Width), (scr->BarHeight+1)+(p*pic.bmhd.bmh_Height));
		}
	}
	
}

void unloadpic(struct Picture pic) {
	if(!(DataTypesBase=OpenLibrary("datatypes.library",0))) {
		msg(GetCatalogStr(catalog,31,"Unable to re-open datatypes library!!!"));
		return;
	}

	FreePicture(&pic);

	CloseLibrary(DataTypesBase);

}

/* For testing only */

/*
void main(int argc, char *argv[]) {
	struct Window *win_p;
	struct Screen *scr;
	struct IntuiMessage *msg2;
	ULONG class;
	
	scr=LockPubScreen(NULL);
	if(!scr) {
		msg(GetCatalogStr(catalog,1,"Unable to lock WB!"));
		exit(NULL);
	}
	win_p=(struct Window *)OpenWindowTags(NULL,	WA_Left,50,
												WA_Top,50,
												WA_Width,500,
												WA_Height,50,
												WA_MaxHeight,256,
												WA_MaxWidth,640,
												WA_MinWidth,10,
												WA_MinHeight,10,
												WA_SimpleRefresh,TRUE,
												WA_DragBar,TRUE,
												WA_CloseGadget,TRUE,
												WA_SizeGadget,TRUE,
												WA_IDCMP,IDCMP_NEWSIZE|IDCMP_CLOSEWINDOW|IDCMP_REFRESHWINDOW,
												TAG_END);
			
	if(!win_p) {
		msg("Unable to open window!");
		exit(NULL);
	}
							
	printf("Loadpic returned %d\n",loadpic(argv[1],scr));
	pattern(win_p,scr,piccy);

	while(1) {
		Wait(1<<win_p->UserPort->mp_SigBit);
		msg2=(struct IntuiMessage *)GetMsg(win_p->UserPort);
		class=msg2->Class;
		ReplyMsg((struct IntuiMessage *)msg2);

		switch(class) {
			case IDCMP_NEWSIZE:
			case IDCMP_REFRESHWINDOW:
				pattern(win_p,scr,piccy);
			break;
			case IDCMP_CLOSEWINDOW:
      		CloseWindow(win_p);
				unloadpic(piccy);
				exit(NULL);
			break;
		}
	}
}
*/