/*
 */

#include "xface.h"

typedef int boolean;

FILE *fp;

int XC = 0, YC = 0,		/* Output X and Y coords of current pixel */
    Width, Height,		/* image dimensions */
    BytesPerScanline;		/* bytes per scanline in output raster */

boolean HasColormap = True;
boolean Verbose = False;

byte *Image;			/* The result array */

byte Red[256], Green[256], Blue[256], used[256];
int  numused = 0;


/*****************************/
LoadFACE(fname)
  char *fname;
/*****************************/
{
    int i;

    if (strcmp(fname,"-")==0) { fp = stdin;  fname = "<stdin>"; }
                         else fp = fopen(fname,"r");

    if (!fp) FatalError("file not found");

    init();

    numcols = 256;

    for( i = 0 ; i < 256 ; ++i )
	used[i] = 0, Red[i] = Green[i] = Blue[i] = cols[i] = i;

/* Allocate the X Image */
    Image = (byte *) malloc(Width*Height);
    if (!Image) FatalError("not enough memory for XImage");

    theImage = XCreateImage(theDisp,theVisual,8,ZPixmap,0,Image,
                         Width,Height,8,Width);
    if (!theImage) FatalError("unable to create XImage");

    BytesPerScanline = Width;

    YC = Height - 1;

    fillitup();

    ColorDicking(fname);
}

AddToPixel(Index)
byte Index;
{

    if (!used[Index]) { used[Index]=1;  numused++; }

    if (YC>=0)
        *(Image + YC * BytesPerScanline + XC) = Index;

/* Update the X-coordinate, and if it overflows, update the Y-coordinate */

    if (++XC == Width) {
	XC = 0;
	YC--;
    }
}



/*************************/
ColorDicking(fname)
char *fname;
{
    /* we've got the picture loaded, we know what colors are needed. get 'em */

    register int   i,j;
    static byte    lmasks[8] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80};
    byte           lmask, *ptr;


    if (!HasColormap) return;

    /* Allocate the X colors for this picture */

    if (nostrip)  {   /* nostrip was set.  try REAL hard to do it */
        for (i=j=0; i<numcols; i++) {
            if (used[i]) {
                defs[i].red   = Red[i]<<8;
                defs[i].green = Green[i]<<8;
                defs[i].blue  = Blue[i]<<8;
                defs[i].flags = DoRed | DoGreen | DoBlue;
                if (!XAllocColor(theDisp,theCmap,&defs[i])) { 
                    j++;  defs[i].pixel = 0xffff;
                    }
                cols[i] = defs[i].pixel;
                }
            }

        if (j) {		/* failed to pull it off */
            XColor ctab[256];
            int    dc;

            dc = (dispcells<256) ? dispcells : 256;

            fprintf(stderr,"failed to allocate %d out of %d colors.  Trying extra hard.\n",j,numused);

            /* read in the color table */
            for (i=0; i<dc; i++) ctab[i].pixel = i;
            XQueryColors(theDisp,theCmap,ctab,dc);
                
            /* run through the used colors.  any used color that has a pixel
               value of 0xffff wasn't allocated.  for such colors, run through
               the entire X colormap and pick the closest color */

            for (i=0; i<numcols; i++)
                if (used[i] && cols[i]==0xffff) {  /* an unallocated pixel */
                    int d, mdist, close;
                    unsigned long r,g,b;

                    mdist = 100000;   close = -1;
                    r =  Red[i];
                    g =  Green[i];
                    b =  Blue[i];
                    for (j=0; j<dc; j++) {
                        d = abs(r - (ctab[j].red>>8)) +
                            abs(g - (ctab[j].green>>8)) +
                            abs(b - (ctab[j].blue>>8));
                        if (d<mdist) { mdist=d; close=j; }
                        }
                    if (close<0) FatalError("simply can't do it.  Sorry.");
                    /*bcopy(&defs[close],&defs[i],sizeof(XColor));*/
                    memcpy(&defs[close],&defs[i],sizeof(XColor));
                    cols[i] = ctab[close].pixel;
                    }
            }	/* end 'failed to pull it off' */
        }

    else {          /* strip wasn't set, do the best auto-strip */
        j = 0;
        while (strip<8) {
            lmask = lmasks[strip];
            for (i=0; i<numcols; i++)
                if (used[i]) {
                    defs[i].red   = (Red[i]  &lmask)<<8;
                    defs[i].green = (Green[i]&lmask)<<8;
                    defs[i].blue  = (Blue[i] &lmask)<<8;
                    defs[i].flags = DoRed | DoGreen | DoBlue;
                    if (!XAllocColor(theDisp,theCmap,&defs[i])) break;
                    cols[i] = defs[i].pixel;
                    }

            if (i<numcols) {		/* failed */
                strip++;  j++;
                for (i--; i>=0; i--)
                    if (used[i]) XFreeColors(theDisp,theCmap,cols+i,1,0L);
                }
            else break;
            }

        if (j && strip<8)
            fprintf(stderr,"%s:  %s stripped %d bits\n",cmd,fname,strip);

        if (strip==8) {
            fprintf(stderr,"UTTERLY failed to allocate the desired colors.\n");
            for (i=0; i<numcols; i++) cols[i]=i;
            }
        }

    ptr = Image;
    for (i=0; i<Height; i++)
        for (j=0; j<Width; j++,ptr++) 
            *ptr = (byte) cols[*ptr];
}


#define BUFSIZE	1024
#define PIXSIZE	2
#define MAXBPL	15	/* Max bytes per output line in resultant XBM */

char line[BUFSIZE];

char firstname[BUFSIZE];
char lastname [BUFSIZE];
char email    [BUFSIZE];

int depth;
int iwidth, iheight, idepth;

int totalpixels;

/* Scan line Enum junk */
    char *enum_ptr; /* local to enum routines */
void
init_enum(buf)
    char *buf;
{
    enum_ptr = buf;
}

/* Dithering junk */
char **dithtab;

int
next_enum(out)
    char *out;
{
    if( enum_ptr[0] == '\n'  ||  enum_ptr[0] == '\0' )
	return False;

    strncpy(out, enum_ptr, PIXSIZE);
    out[PIXSIZE] = '\0';
    enum_ptr += PIXSIZE;

    return True;
}

init()
{
    int nlcounter = 1;

    fgets(line, BUFSIZE, fp);
    sscanf(line, "%*s %s", firstname);

    fgets(line, BUFSIZE, fp);
    sscanf(line, "%*s %s", lastname);

    fgets(line, BUFSIZE, fp);
    sscanf(line, "%*s %s", email);

    fgets(line, BUFSIZE, fp);
    while (sscanf(line, "PicData: %d %d %d", &Width, &Height, &depth) != 3)
	fgets(line, BUFSIZE, fp);

    fgets(line, BUFSIZE, fp);
    sscanf(line, "Image: %d %d %d", &iwidth, &iheight, &idepth);

    fgets(line, BUFSIZE, fp);

    totalpixels = Width * Height;
}

fillitup()
{
    while( fgets(line, BUFSIZE, fp) != NULL ) {
	char pixel[PIXSIZE+1];

	init_enum(line);

	while( next_enum(pixel)  ) {
	    unsigned int value;

	    sscanf(pixel, "%x", &value);
	    AddToPixel((byte)value);
	}
    }
}
