/*
 * Font utils - Mitch <m.dsouza@mrc-apu.cam.ac.uk> - 31-5-94 
 * vga_initfont() - initalize a font pointer with the named charset.
 * vga_write() - write some text at a certain point on the screen in a
 *				given foreground and background color.
 */

#include <stdio.h>
#include <memory.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <vga.h>
#include <asm/bitops.h>
#include "fontutils.h"
#include "paths.h"

int
vga_putc (char letter, short x, short y,
	   font_t *font, short fg, short bg) {
  int i, j, k;
  unsigned char data[8*font->xscale], *c;

  if (!letter || font == NULL || font->font == NULL || x < 0 || y < 0)
      return 0;

    for (j = 0; j < font->font_height; j++)
      {
	c = font->font + (letter << 5) + j;

	if (*c && (font->misc & FONT_XOR))
		vga_getscansegment (data, x, y+j, 8*font->xscale);
	else
		memset(data,bg,8*font->xscale);

	if (*c || !(font->misc & FONT_XOR)) {
	for (k = 7; k >= 0; k--)
		if (test_bit(k,c))
			memset(data+(7-k)*font->xscale,fg,font->xscale);
	for (i = y+j*font->yscale; i < y+j*font->yscale+font->yscale; i++)
			vga_drawscansegment (data, x, i, 8*font->xscale);
	}

      }
  return 1;
}

int
vga_write (char *text, short x, short y,
	   font_t *font, short fg, short bg, char align)
{

  int i, j, k, len;
  char *data;
  unsigned char *c;

  if (text == NULL || font == NULL || font->font == NULL || x < 0 || y < 0)
    return 0;

  len = strlen (text);

  switch(align) {
	case ALIGN_CENTER:
		x -= (len*font->xscale << 3) >> 1;
		break;
	case ALIGN_RIGHT:
		x -= len*font->xscale << 3;
		break;
	case ALIGN_LEFT:
	default:
  }

  for (i = 0; i < len; i++)
	vga_putc (text[i], x + (i*font->xscale<<3), y, font, fg, bg);
  return 1;
}

/*
 * This rest of this file is a blatant ripoff of the setfont.c and findfile.c
 * that appears in the kbd-x.y.tar.gz keyboard package.
 *
 */

/*
 * setfont.c - Eugene Crosser & aeb
 *
 * Version 0.85
 *
 */

/* search for the font in these directories (with trailing /) */
static char *dirpath[] = { "", DATADIR "/" FONTDIR "/", 0 };
static char *suffixes[] = { "", ".psf", ".cp", ".fnt", 0 };
static char pathname[1024];
static void position_codepage(int iunit, FILE *fpi);
static FILE *findfile(char *fnam);

int
vga_initfont (char *ifil, font_t *buf, char xscale, char yscale)
{
	FILE *fpi, *fpo;
	char defname[20];

	int fd, i, j, iunit=16, unit, hdr, size;
	struct stat stbuf;

	if (!buf) return 0;

	if (ifil) {
	    if (!*ifil) {
		/* try to find some default file */

		if (iunit < 0 || iunit > 32)
		  iunit = 0;
		if (iunit == 0) {
		    if ((fpi = findfile(ifil = "default")) == NULL &&
			(fpi = findfile(ifil = "default8x16")) == NULL &&
			(fpi = findfile(ifil = "default8x14")) == NULL &&
			(fpi = findfile(ifil = "default8x8")) == NULL) {
			fprintf(stderr, "Cannot find default font\n");
			exit(1);
		    }
		} else {
		    sprintf(defname, "default8x%d", iunit);
		    if ((fpi = findfile(ifil = defname)) == NULL) {
			fprintf(stderr, "Cannot find %s font\n", ifil);
			exit(1);
		    }
		}
	    } else {
		if ((fpi = findfile(ifil)) == NULL) {
		    fprintf(stderr, "Cannot open font file %s\n", ifil);
		    exit(1);
		}
	    }

	    if (stat(pathname, &stbuf)) {
		perror(pathname);
		exit(1);
	    }
	    size = stbuf.st_size;

	    if (size == 9780) {
		position_codepage(iunit, fpi);
		unit = iunit;
		goto readit;
	    }

	    hdr = (size & 0377);
	    unit = (size - hdr)/256;

	    if (hdr == 4) {
		char psfhdr[4];
		if (fread(psfhdr, 4, 1, fpi) != 1) {
		    perror("Error reading header input font");
		    exit(1);
		}
		/* note: this depends on endianness */
		if (psfhdr[1] != 0x04 || psfhdr[0] != 0x36) {
		    fprintf(stderr, "Unrecognized font format\n");
		    exit(1);
		}
		if (psfhdr[2] != 0) {
		    fprintf(stderr, "Unsupported psf file mode\n");
		    exit(1);
		}
		if(size != hdr + 256*psfhdr[3]) {
		    fprintf(stderr, "Input file: bad length\n");
		    exit(1);
		}
	    }

	    if ((hdr != 0 && hdr != 4) || unit < 1 || unit > 32) {
		fprintf(stderr, "Bad input file size\n");
		exit(1);
	    }

	  readit:
	    memset(buf->font,0,sizeof(buf->font));

	    for (i = 0; i < 256; i++)
	      if (fread(buf->font+(32*i), unit, 1, fpi) != 1) {
		  perror("Cannot read font from file");
		  exit(1);
	      } 
	    fclose(fpi);
#if 0
	    fprintf(stderr,"Loading 8x%d font from file %s\n", unit, pathname);
#endif
	}
buf->font_height = iunit;
buf->misc = FONT_COPY;
buf->xscale = xscale < 1 ? 1 : xscale ;
buf->yscale = yscale < 1 ? 1 : yscale ;
return 1;
}

static void
position_codepage(int iunit, FILE *fpi) {
        int offset;

	/* code page: first 40 bytes, then 8x16 font,
	   then 6 bytes, then 8x14 font,
	   then 6 bytes, then 8x8 font */

	if (!iunit) {
	    fprintf(stderr, "\
This file contains 3 fonts: 8x8, 8x14 and 8x16. Please indicate
using an option -8 or -14 or -16 which one you want loaded.\n");
	    exit(1);
	}
	switch (iunit) {
	  case 8:
	    offset = 7732; break;
	  case 14:
	    offset = 4142; break;
	  case 16:
	    offset = 40; break;
	  default:
	    fprintf(stderr, "\
You asked for font size %d, but only 8, 14, 16 are possible here.\n",
		    iunit);
	    exit(1);
	}
	if(fseek(fpi,offset,0)) {
	    perror("seek error on input file");
	    exit(1);
	}
}

/* find input file; leave name in pathname[] */
static FILE *findfile(char *fnam) {
        char **dp, **sp;
	FILE *fp;

	for (dp = dirpath; *dp; dp++) {
	    if (*fnam == '/' && **dp)
	      continue;
	    for (sp = suffixes; *sp; sp++) {
		if (strlen(*dp) + strlen(fnam) + strlen(*sp) + 1
		    > sizeof(pathname))
		  continue;
		sprintf(pathname, "%s%s%s", *dp, fnam, *sp);
		if((fp = fopen(pathname, "r")) != NULL)
		  return fp;
	    }
	}
	return NULL;
}
