/*
 * fax2iff.c
 */

#include <stdlib.h>

#include "iffp/iff.h"
#include "iffp/ilbm.h"
#include "iffp/packer.h"
#include "faxfile.h"

void	       *IFFParseBase;
struct ParseInfo ParseInfo;
int		verbose;
int		invert;

/* Assumes malloc()ed pointer */
void
meminvert(unsigned char *d, int size)
{
    while (size >= 4) {
	*(long *)d ^= 0xFFFFFFFF;
	d += 4;
	size -= 4;
    }
    while (size > 0) {
	*d++ ^= 0xFF;
	size--;
    }
}

long
dobody(FILE *faxfile, struct ParseInfo *pi)
{
    unsigned char  *planedata;
    unsigned char  *bodydata;
    int 	    planedatasize;
    int 	    bodydatasize;
    int 	    lines;

    planedatasize = BytesPerRow(LINE_BITS);
    bodydatasize  = MaxPackedSize(BytesPerRow(LINE_BITS));
    planedata = malloc(4 + planedatasize);
    bodydata  = malloc(4 + bodydatasize);

    for (lines=0;;lines++) {
	unsigned char  *p, *b;
	long		size;

	memset(planedata, 0, planedatasize);
	size = fromfax(faxfile, planedata);
	if (size == -1)
	    break;
	if (invert)
	    meminvert(planedata, planedatasize);
	p = planedata;
	b = bodydata;
	size = PackRow(&p, &b, LINE_BITS / 8);
	WriteChunkBytes(pi->iff, bodydata, size);
    }

    free(bodydata);
    free(planedata);

    return lines;
}

long
dopage(FILE *faxfile, struct ParseInfo *pi)
{
    long	    bmhdpos;
    long	    currpos;
    int 	    lines;
    FILE	   *ifffile;
    BitMapHeader    bmhd = {
			LINE_BITS, 9999,    /* w, h (unknown yet) */
			0, 0,		    /* x, y */
			1,		    /* nPlanes */
			mskNone,	    /* masking */
			cmpByteRun1,	    /* compression */
			0,		    /* reserved1 */
			0,		    /* transparentcolor */
			Y_DPI, X_DPI,	    /* xAspect, yAspect */
			LINE_BITS, 9999,    /* pageWidth, pageHeight */
		    };

    PushChunk(pi->iff, ID_ILBM, ID_FORM, IFFSIZE_UNKNOWN);

    /*
     * This is DIRTY DIRTY DIRTY!!
     * We need to update the BitMapHeader later on because we
     * don't know the y size yet.
     */
    ifffile = (FILE *)pi->iff->iff_Stream;
    bmhdpos = ftell(ifffile) + 8;
    putbmhd(pi->iff, &bmhd);

    PushChunk(pi->iff, ID_ILBM, ID_BODY, IFFSIZE_UNKNOWN);

    lines = dobody(faxfile, pi);

    PopChunk(pi->iff);  /* BODY */
    PopChunk(pi->iff);  /* FORM ILBM */

    /* Update BMHD */
    bmhd.h = lines;
    bmhd.pageHeight = lines;
    currpos = ftell(ifffile);
    if (fseek(ifffile, bmhdpos, SEEK_SET) == 0) {
	fwrite(&bmhd, sizeof(bmhd), 1, ifffile);
	fseek(ifffile, currpos, SEEK_SET);
    } else {
	fprintf(stderr, "fseek on iff-file failed\n");
    }

    return 0;
}

long
dofile(char *faxname, struct ParseInfo *pi)
{
    FILE	   *faxfile;
    long	    error;

    faxfile = fopen(faxname, "rb");
    if (faxfile == NULL)
	return 1;

    error = faxin_open_fp(faxfile, 0);

    while (error == 0 && faxin_begin_page(faxfile) == 0) {
	error = dopage(faxfile, pi);
    }

error:
    fclose(faxfile);
    return error;
}


/*
 * Clean up system stuff in case of exit
 */
void
cleanup(void)
{
    if (IFFParseBase) {
	if (ParseInfo.iff) {
	    closeifile(&ParseInfo);
	    FreeIFF(ParseInfo.iff);
	}
	CloseLibrary(IFFParseBase);
    }
}

int
main(int argc, char **argv)
{
    struct IFFHandle *iff;
    char	   *outfile = "fax.iff";
    extern char    *optarg;
    extern int	    optind;
    extern int	    getopt(int, char **, char *);
    int 	    errflg = 0;
    int 	    c;

    while ((c = getopt(argc, argv, "io:v")) != -1) {
	switch (c) {
	case 'i':
	    invert = 1;
	    break;
	case 'o':
	    outfile = optarg;
	    break;
	case 'v':
	    verbose = TRUE;
	    break;
	case '?':
	    errflg++;
	    break;
	}
    }

    if (errflg || optind >= argc) {
	printf(
"Usage: fax2iff [-o iff-file (fax.iff)] [-v] [-i (invert)] fax-files\n");
	exit(EXIT_FAILURE);
    }

    atexit(cleanup);

    IFFParseBase = OpenLibrary("iffparse.library", 0);
    if (IFFParseBase == NULL) {
	printf("Needs iffparse.\n");
	exit(10);
    }

    iff = AllocIFF();
    ParseInfo.iff = iff;
    openifile(&ParseInfo, outfile, IFFF_WRITE);
    PushChunk(iff, ID_ILBM, ID_CAT, IFFSIZE_UNKNOWN);

    while (optind < argc) {
	dofile(argv[optind], &ParseInfo);
	optind++;
    }

    PopChunk(iff);
    closeifile(&ParseInfo);
    FreeIFF(iff);
    ParseInfo.iff = NULL;

    /*CloseLibrary(IFFParseBase);*/
}
