/* ILBMDemo.c  05/91   C. Scheppner CBM
 *
 * Demonstrates displaying an ILBM, loading a brush,
 *   saving an ILBM, and optionally printing a screen (CTRL-p)
 *   Use -c (or -c1, -c2, etc) as filename to read from or save to clipboard.
 *
 * requires linkage with several iffp modules - see Makefile
 */

#include "iffp/ilbmapp.h"


#ifdef LATTICE
int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

void chkmsg(void);
void cleanup(void);
void bye(UBYTE *s,int error);

#define SAVECHANGES

#define MINARGS 3
char *vers = "\0$VER: ILBMDemo 37.5";
char *Copyright = "ILBMDemo v37.5 (Freely Redistributable)";
char *usage =
"Usage: ILBMDemo sourceilbm destilbm [brushname]  (CTRL-p to print screen)\n"
"Displays source, optionally loads and blits brush, saves to dest\n"
"Use filename -c[unit] (ie. -c, -c1, -c2, etc.) for clipboard\n";

char *savename;

struct Library *IntuitionBase  = NULL;
struct Library *GfxBase        = NULL;
struct Library *IFFParseBase   = NULL;

/* Note - these fields are also available in the ILBMInfo structure */
struct   Screen         *scr;         /* for ptr to screen structure */
struct   Window         *win;         /* for ptr to window structure */
struct   RastPort       *wrp;         /* for ptr to RastPort  */
struct   ViewPort       *vp;          /* for ptr to Viewport  */

struct   IntuiMessage   *msg;

struct   NewWindow      mynw = {
   0, 0,                                  /* LeftEdge and TopEdge */
   0, 0,                          	  /* Width and Height */
   -1, -1,                                /* DetailPen and BlockPen */
   VANILLAKEY|MOUSEBUTTONS,               /* IDCMP Flags with Flags below */
   BACKDROP|BORDERLESS|SMART_REFRESH|NOCAREREFRESH|ACTIVATE|RMBTRAP,
   NULL, NULL,                            /* Gadget and Image pointers */
   NULL,                                  /* Title string */
   NULL,                                  /* Screen ptr null till opened */
   NULL,                                  /* BitMap pointer */
   50, 20,                                /* MinWidth and MinHeight */
   0 , 0,                                 /* MaxWidth and MaxHeight */
   CUSTOMSCREEN                           /* Type of window */
   };


BOOL   FromWb, Done;


/* ILBM Property chunks to be grabbed
 * List BMHD, CMAP and CAMG first so we can skip them when we write
 * the file back out (they will be written out with separate code)
 */
LONG	ilbmprops[] = {
		ID_ILBM, ID_BMHD,
		ID_ILBM, ID_CMAP,
		ID_ILBM, ID_CAMG,
		ID_ILBM, ID_CCRT,
		ID_ILBM, ID_AUTH,
		ID_ILBM, ID_Copyright,
		TAG_DONE
		};

/* ILBM Collection chunks (more than one in file) to be gathered */
LONG	ilbmcollects[] = {
		ID_ILBM, ID_CRNG,
		TAG_DONE
		};

/* ILBM Chunk to stop on */
LONG	ilbmstops[] = {
		ID_ILBM, ID_BODY,
		TAG_DONE
		};


/* For test of adding new chunks to saved FORM */
struct Chunk newchunks[2] = {
	{
	&newchunks[1],
	ID_ILBM, ID_AUTH, IFFSIZE_UNKNOWN,
	"CAS_CBM"},
	{
	NULL,
	ID_ILBM, ID_NAME, IFFSIZE_UNKNOWN,
	"Untitled No. 27"},
	};


UBYTE nomem[]  = "Not enough memory\n";
UBYTE noiffh[] = "Can't alloc iff\n";

/* our indexes to reference our frames
 * DEFault, BRUsh, and SCReen
 */
#define DEF	0
#define BRU	1
#define SCR	2
#define UICOUNT 3

/* For our ILBM frames */
struct ILBMInfo  *ilbms[UICOUNT]  = { NULL };


/* 
 * MAIN 
 */
void main(int argc, char **argv)
   {
#ifdef SAVECHANGES
   struct Chunk *chunk;
   CamgChunk *camg;
   LONG saverror;
#endif
   UBYTE *ilbmname=NULL, *brushname=NULL, ans, c;
   BPTR lock;
   LONG error;

   FromWb = argc ? FALSE : TRUE;

   if((argc<MINARGS)||(argv[argc-1][0]=='?'))
	{
	printf("%s\n%s\n",Copyright,usage);
        bye("",RETURN_OK);
	}

   switch(argc)
      {
      case 4:
         brushname	= argv[3];
      case 3:
         savename	= argv[2];
         ilbmname	= argv[1];
         break;
      }

   /* if dest not clipboard, warn if dest file already exists */
   if(strcmp(savename,"-c"))
	{
	if(lock = Lock(savename,ACCESS_READ))
	    {
	    UnLock(lock);
	    printf("Dest file \"%s\" already exists.  Overwrite (y or n) ? ",
			savename);
	    ans = 0;
	    while((c = getchar()) != '\n') if(!ans)  ans = c | 0x20;
	    if(ans == 'n')   bye("Exiting.\n",RETURN_OK);
	    }
	}
	    
   /* Open Libraries */

   if(!(IntuitionBase = OpenLibrary("intuition.library", 0)))
      bye("Can't open intuition library.\n",RETURN_WARN);
      
   if(!(GfxBase = OpenLibrary("graphics.library",0)))
      bye("Can't open graphics library.\n",RETURN_WARN);

   if(!(IFFParseBase = OpenLibrary("iffparse.library",0)))
      bye("Can't open iffparse library.\n",RETURN_WARN);



/* 
 * Alloc three ILBMInfo structs (one each for defaults, screen, brush) 
 */
    if(!(ilbms[0] = (struct ILBMInfo *)
	AllocMem(UICOUNT * sizeof(struct ILBMInfo),MEMF_PUBLIC|MEMF_CLEAR))) 
		bye(nomem,RETURN_FAIL);
    else 
	{
	ilbms[BRU] = ilbms[0] + 1;
	ilbms[SCR] = ilbms[0] + 2;
	}

/*
 * Here we set up default ILBMInfo fields for our
 * application's frames.
 * Above we have defined the propery and collection chunks
 * we are interested in (some required like BMHD)
 * Since all of our frames are for ILBM's, we'll initialize
 * one default frame and clone the others from it.
 */
    ilbms[DEF]->ParseInfo.propchks	= ilbmprops;
    ilbms[DEF]->ParseInfo.collectchks	= ilbmcollects;
    ilbms[DEF]->ParseInfo.stopchks	= ilbmstops;

    ilbms[DEF]->windef	= &mynw;
/* 
 * Initialize our working ILBM frames from our default one
 */
    *ilbms[SCR] = *ilbms[DEF];	/* for our screen */
    *ilbms[BRU] = *ilbms[DEF];	/* for our brush  */

/* 
 * Alloc two IFF handles (one for screen frame, one for brush frame) 
 */
    if(!(ilbms[SCR]->ParseInfo.iff = AllocIFF())) bye(noiffh,RETURN_FAIL);
    if(!(ilbms[BRU]->ParseInfo.iff = AllocIFF())) bye(noiffh,RETURN_FAIL);

/* Load and display an ILBM
 */
    if(error = showilbm(ilbms[SCR],ilbmname))
	{
	printf("Can't load background \"%s\"\n",ilbmname);
	bye("",RETURN_WARN);
	}

    /* These were set up by our successful showilbm() above */
    win = ilbms[SCR]->win;	/* our window */
    wrp = ilbms[SCR]->wrp;	/* our window's RastPort */
    scr = ilbms[SCR]->scr;	/* our screen */
    vp  = ilbms[SCR]->vp;		/* our screen's ViewPort */

    ScreenToFront(scr);


 /* Now let's load a brush and blit it into the window
  */
    if(brushname)
	{
	if (error = loadbrush(ilbms[BRU],brushname))
	    {
	    printf("Can't load brush \"%s\"\n",brushname);
	    bye("",RETURN_WARN);
	    }
	else	/* Success */
	    {
	    D(bug("About to Blt bitmap $%lx to rp $%lx, w=%ld h=%ld\n",
		ilbms[BRU]->brbitmap,wrp,ilbms[BRU]->Bmhd.w,ilbms[BRU]->Bmhd.h));
            BltBitMapRastPort(ilbms[BRU]->brbitmap,0,0,
                     		wrp,0,0,
                     		ilbms[BRU]->Bmhd.w, ilbms[BRU]->Bmhd.h,
                     		0xC0);
     	    }
	}

#ifdef SAVECHANGES

 /* This code is an example for Read/Modify/Write programs
  *
  * We copy off the parsed chunks we want to preserve,
  * close the IFF read file, reopen it for write,
  * and save a new ILBM which
  * will include the chunks we have preserved, but
  * with newly computed and set-up BMHD, CMAP, and CAMG.
  */ 

   if(!(ilbms[SCR]->ParseInfo.copiedchunks =
	copychunks(ilbms[SCR]->ParseInfo.iff,
		   ilbmprops, ilbmcollects,
		   MEMF_PUBLIC)))
		printf("error cloning chunks\n");
   else
	{
        /* we can close the file now */
   	closeifile(ilbms[SCR]);

   	printf("Test of copychunks and findchunk:\n");

   	/* Find copied CAMG chunk if any */
   	if(chunk = findchunk(ilbms[SCR]->ParseInfo.copiedchunks,ID_ILBM,ID_CAMG))
	    {
	    camg = (CamgChunk *)chunk->ch_Data;
	    printf("CAMG: $%08lx\n",camg->ViewModes);
	    }
        else printf("No CAMG found\n");

   	/* Find copied CRNG chunks if any */
   	if(chunk = findchunk(ilbms[SCR]->ParseInfo.copiedchunks,ID_ILBM,ID_CRNG))
	    {
   	    while((chunk)&&(chunk->ch_ID == ID_CRNG))
		{
		printf("Found a CRNG chunk\n");
		chunk = chunk->ch_Next;
		}
	    }
   	else printf("No CRNG chunks found\n");
	}

    printf("\nAbout to save screen as %s, adding NAME and AUTH chunks\n",
		savename);

    if(saverror = screensave(ilbms[SCR], ilbms[SCR]->scr,
				ilbms[SCR]->ParseInfo.copiedchunks,
				newchunks,
				savename))
			printf("%s\n",IFFerr(saverror));

#endif

   Done = FALSE;
   while(!Done)
      {
      Wait(1<<win->UserPort->mp_SigBit);
      chkmsg();
      }


   cleanup();
   exit(RETURN_OK);
   }


void chkmsg(void)
    {
    LONG  error;
    ULONG class;
    UWORD code;
    WORD  mousex, mousey;

    while(msg = (struct IntuiMessage *)GetMsg(win->UserPort))
	{
	class = msg->Class;
      	code  = msg->Code;
      	mousex = msg->MouseX;
      	mousey = msg->MouseY;

      	ReplyMsg(msg);
      	switch(class)
   	    {
	    case MOUSEBUTTONS:
	    switch(code)
		{
		/* emulate a close gadget */
		case SELECTDOWN:
		   if((mousex < 12)&&(mousey < 12))	Done = TRUE;
		   break;
		default:
		   break;
		}
            case VANILLAKEY:
            switch(code)
               	{
		/* also quit on CTRL-C, CTRL-D, or q */
               	case 'q': case 0x04: case 0x03:
                  Done = TRUE;
                  break;
		case 0x10:	/* CTRL-p means print */

		  /* Print the whole screen */
		  if(error=screendump(ilbms[SCR]->scr,
				0,0,
				ilbms[SCR]->scr->Width,
				ilbms[SCR]->scr->Height,
				0,0))
			printf("Screendump printer error=%ld\n",error);
		  break;
			
               	default:
                  break;
		}
            default:
            break;
            }
      	}
    }


void bye(UBYTE *s,int error)
   {
   if((*s)&&(!FromWb)) printf("%s\n",s);
   cleanup();
   exit(error);
   }


void cleanup()
   {
   if(ilbms[SCR])
	{
   	if(ilbms[SCR]->scr)		unshowilbm(ilbms[SCR]);
#ifdef SAVECHANGES
   	freechunklist(ilbms[SCR]->ParseInfo.copiedchunks);
#endif
   	if(ilbms[SCR]->ParseInfo.iff)	FreeIFF(ilbms[SCR]->ParseInfo.iff);
	}

   if(ilbms[BRU])
	{
   	if(ilbms[BRU]->brbitmap)	unloadbrush(ilbms[BRU]);
   	if(ilbms[BRU]->ParseInfo.iff) 	FreeIFF(ilbms[BRU]->ParseInfo.iff);
	}

   if(ilbms[0])
	{
	FreeMem(ilbms[0],UICOUNT * sizeof(struct ILBMInfo));
	}

   if(GfxBase) 	     CloseLibrary(GfxBase);
   if(IntuitionBase) CloseLibrary(IntuitionBase);
   if(IFFParseBase)  CloseLibrary(IFFParseBase);
   }
