#include <stdio.h>
#include <strings.h>
/*
#include <sys/file.h>
*/

#include "X.h"
#include "Xmd.h"
#include "Xproto.h"
#include "misc.h"
#include "fontstruct.h"

#include "port.h"	/* used by converters only */
#include "fc.h"		/* used by converters only */

#ifndef u←char
#define u←char	unsigned char
#endif

extern int	glyphPad;

char *	malloc();
char *	invertbitsandbytes();

/*
 * Computes accelerators, which by definition can be extracted from
 * the font; therefore a pointer to the font is the only argument.
 *
 * Should also give a final sanity-check to the font, so it can be
 * written to disk.
 *
 * Generates values for the following fields in the FontInfo structure:
 *	version
 *	minbounds
 *	maxbounds	- except byteOffset 
 * Generates values for the following fields in the CharInfo array.
 *	u.flags
 */
computeNaccelerators(font)
    TempFont *font;
{
    int		chi, nchars;
    register CharInfoPtr minbounds = &font->pFI->minbounds;
    register CharInfoPtr maxbounds = &font->pFI->maxbounds;

    int		maxoverlap = MINSHORT;		/* used to set fiFlags */
    int		nnonexistchars = 0;	/* used to set fiFlags */

    font->pFI->version1 = font->pFI->version2 = FONT←FILE←VERSION;

    minbounds->metrics.ascent = MAXSHORT;
    minbounds->metrics.descent = MAXSHORT;
    minbounds->metrics.leftSideBearing = MAXSHORT;
    minbounds->metrics.rightSideBearing = MAXSHORT;
    minbounds->metrics.characterWidth = font->pCI->metrics.characterWidth;
    /* don't touch byteOffset! */
    minbounds->exists = 0;
    minbounds->metrics.attributes = 0xFFFF;	/* all bits on */

    maxbounds->metrics.ascent = MINSHORT;
    maxbounds->metrics.descent = MINSHORT;
    maxbounds->metrics.leftSideBearing = MINSHORT;
    maxbounds->metrics.rightSideBearing = MINSHORT;
    maxbounds->metrics.characterWidth = font->pCI->metrics.characterWidth;
    /* don't touch byteOffset! */
    maxbounds->exists = 0;
    maxbounds->metrics.attributes = 0;

    nchars = n2dChars(font->pFI);
    for (chi = 0; chi < nchars; chi++)
	{
    	register CharInfoPtr pci = &font->pCI[chi];

	if (	pci->metrics.ascent == 0
	     &&	pci->metrics.descent == 0
	     &&	pci->metrics.leftSideBearing == 0
	     &&	pci->metrics.rightSideBearing == 0
	     &&	pci->metrics.characterWidth == 0) {
	    nnonexistchars++;
	    pci->exists = FALSE;
	}
	else {

#define MINMAX(field) \
	if (minbounds->metrics.field > pci->metrics.field) \
	     minbounds->metrics.field = pci->metrics.field; \
	if (maxbounds->metrics.field < pci->metrics.field) \
	     maxbounds->metrics.field = pci->metrics.field;

	    pci->exists = TRUE;
	    MINMAX(ascent);
	    MINMAX(descent);
	    MINMAX(leftSideBearing);
	    MINMAX(rightSideBearing);
	    MINMAX(characterWidth);
	    minbounds->metrics.attributes &= pci->metrics.attributes;
	    maxbounds->metrics.attributes |= pci->metrics.attributes;
	    maxoverlap = MAX(
		maxoverlap,
		pci->metrics.rightSideBearing-pci->metrics.characterWidth);
#undef MINMAX
	}
    }

    if ( maxoverlap <= minbounds->metrics.leftSideBearing)
	font->pFI->noOverlap = TRUE;
    else
	font->pFI->noOverlap = FALSE;

    if ( nnonexistchars == 0)
	font->pFI->allExist = TRUE;
    else
	font->pFI->allExist = FALSE;

    if ( (minbounds->metrics.ascent == maxbounds->metrics.ascent) &&
         (minbounds->metrics.descent == maxbounds->metrics.descent) &&
	 (minbounds->metrics.leftSideBearing ==
		maxbounds->metrics.leftSideBearing) &&
	 (minbounds->metrics.rightSideBearing ==
		maxbounds->metrics.rightSideBearing) &&
	 (minbounds->metrics.characterWidth ==
		maxbounds->metrics.characterWidth) &&
	 (minbounds->metrics.attributes == maxbounds->metrics.attributes)) {
	font->pFI->constantMetrics = TRUE;
	if ( maxbounds->metrics.rightSideBearing + maxbounds->metrics.leftSideBearing ==
	     maxbounds->metrics.characterWidth)
	         font->pFI->terminalFont = TRUE;
    }
    else {
	font->pFI->constantMetrics = FALSE;
	font->pFI->terminalFont = FALSE;
    }
}



/*
 * Note that ReadNFont lives in dix/fontserver.c.  It would seem cleaner if
 * ReadNFont and WriteNFont could live together.
 */
WriteNFont( pfile, font)
    FILE *	pfile;
    TempFont	*font;
{
    int		np;
    FontPropPtr	fp;
    int		off;		/* running index into string table */
    int		strbytes;	/* size of string table */
    char	*strings;	/* string table */
    long	zero = 0;

    /* run through the properties and add up the string lengths */
    strbytes = 0;
    for (fp=font->pFP,np=font->pFI->nProps; np; np--,fp++)
    {
	strbytes += strlen((char *)fp->name)+1;
	if (fp->indirect)
		strbytes += strlen((char *)fp->value)+1;
    }
    font->pFI->lenStrings = strbytes;

    /* build string table and convert pointers to offsets */
    strings = malloc(strbytes);
    off = 0;
    for (fp=font->pFP,np=font->pFI->nProps; np; np--,fp++)
    {
	int l;
	l = strlen((char *)fp->name)+1; /* include null */
	bcopy((char *)fp->name, strings+off, l);
	fp->name = off;
	off += l;
	if (fp->indirect) {
		l = strlen(fp->value)+1; /* include null */
		bcopy((char *)fp->value, strings+off, l);
		fp->value = off;
		off += l;
	}
    }

    fwrite( (char *)font->pFI, BYTESOFFONTINFO(font->pFI), 1, pfile);

    fwrite( (char *)(font->pCI + font->pFI->chFirst),
	    (int)BYTESOFCHARINFO(font->pFI), (int)1, pfile);

    fwrite( (char *)font->pGlyphs, (int)1, (int)BYTESOFGLYPHINFO(font->pFI), pfile);

    fwrite( (char *)font->pFP, (int)1, (int)BYTESOFPROPINFO(font->pFI), pfile);

    fwrite( (char *)strings, (int)1, (int)BYTESOFSTRINGINFO(font->pFI), pfile);
}



DumpFont( pfont, bVerbose)
    TempFont *	pfont;
    int		bVerbose;
{
    FontInfoPtr	pfi = pfont->pFI;
    int bFailure = 0;
    int i;

    if ( pfont == NULL)
    {
	fprintf( stderr, "DumpFont: NULL FONT pointer passed\n");
	exit( 1);
    }
    if ( pfi == NULL)
    {
	fprintf( stderr, "DumpFont: NULL FontInfo pointer passed\n");
	exit( 1);
    }

    printf("version1: 0x%x (version2: 0x%x)\n", pfi->version1, pfi->version2);
    if ( pfi->version1 != FONT←FILE←VERSION)
	printf( "*** NOT CURRENT VERSION ***\n");
    if ( pfi->noOverlap)
	printf( " no overlap");
    if ( pfi->allExist)
	printf( " all exist");
    printf("\n\tprinting direction: ");
    switch ( pfi->drawDirection)
    {
      case FontLeftToRight:
	printf( "left-to-right\n");
	break;
      case FontRightToLeft:
	printf( "right-to-left\n");
	break;
    }
    printf("first character: 0x%x\n", pfi->chFirst);
    printf("last characters:  0x%x\n", pfi->chLast);

    printf("number of font properties:  0x%x\n", pfi->nProps);
    for (i=0; i<pfi->nProps; i++) {
	printf("  %-15s  ", pfont->pFP[i].name);
	if (pfont->pFP[i].indirect)
		printf("%s\n", pfont->pFP[i].value);
	else
		printf("%d\n", pfont->pFP[i].value);
    }

    printf("default character: 0x%x\n", pfi->chDefault);

    printf("minbounds:\n");
    DumpCharInfo( &pfi->minbounds, 1);
    printf("maxbounds:\n");
    DumpCharInfo( &pfi->maxbounds, 1);
    printf("FontInfo struct: virtual memory address == %x\tsize == %x\n",
	    pfont->pFI, sizeof(FontInfoRec));

    printf("CharInfo array: virtual memory base address == %x\tsize == %x\n",
	    pfont->pCI, n1dChars(pfi)*sizeof(CharInfoRec));

    printf("glyph block: virtual memory address == %x\tsize == %x\n",
	    pfont->pGlyphs, pfi->maxbounds.byteOffset );

    if ( bVerbose>0)
	DumpCharInfo( &pfont->pCI[ pfont->pFI->chFirst],
					n1dChars(pfont->pFI));

    if ( bVerbose>1)
    {
        if (bFailure)
            fprintf( stderr, "verbosity not possible with failed read");
        else
/*
	    if ( pixDepth > 1)
		DumpAABitmaps( pfont);
	    else
 */
		DumpBitmaps( pfont);
    }
    printf("\n");
}

DumpCharInfo( pxci, count)
    CharInfoPtr	pxci;
    int		count;
{
/*
    printf( "\nrbearing\tlbearing\tdescent\tascent\nwidth\tbyteOffset\tbitOffset\tciFlags");
*/
    printf( "rbearing\tdescent\t\twidth\t\tbitOffset\n");
    printf( "\tlbearing\tascent\t\tbyteOffset\tciFlags\n");

    while( count--)
    {
	printf( "%d d\t%d d\t%d d\t%d d\t%d d\t%x x\t%x x\t%x x\n",
	    pxci->metrics.rightSideBearing, pxci->metrics.leftSideBearing, pxci->metrics.descent, pxci->metrics.ascent,
	    pxci->metrics.characterWidth, pxci->byteOffset, pxci->exists, pxci->metrics.attributes);
	pxci++;
    }
}

DumpBitmaps( pFont)
    TempFont *pFont;
{
    int			ch;	/* current character */
    int			r;	/* current row */
    int			b;	/* current bit in the row */
    FontInfoPtr		pFI = pFont->pFI;
    CharInfoPtr		pCI = pFont->pCI;
    u←char *		bitmap = (u←char *)pFont->pGlyphs;

    for (ch = pFI->chFirst; ch <= pFI->chLast; ch++)
    {
	int bpr = GLWIDTHBYTESPADDED(pCI[ch].metrics.rightSideBearing
		- pCI[ch].metrics.leftSideBearing, glyphPad);
        printf("character %d\n", ch);
        if ( pCI[ch].metrics.characterWidth == 0)
            continue;		/* ?? */
        for (r=0; r <  pCI[ch].metrics.descent + pCI[ch].metrics.ascent; r++)
        {
	    unsigned char *row = bitmap + pCI[ch].byteOffset+(r*bpr);
            for ( b=0;
		b < pCI[ch].metrics.rightSideBearing - pCI[ch].metrics.leftSideBearing;
		b++) {
                putchar((row[b>>3] & (1<<(b&7)))? '#' : '←');
	    }
            putchar('\n');
        }
    }
}