#include    <stdio.h>
#include    <stdlib.h>
#include    "defs.h"

#define HASH    16
#define MAX     64

typedef struct _LRU {
    UNSIG   code;
    struct _LRU *next;
    UCHAR   font[72];
} LRU;

       char	*fnt_dir=NULL;
static FILE	*kan_fp=NULL,*ank_fp=NULL;
static int	ank_cnt=0;
static char	*kanfile[]={
		    "\\KYOU\\KYOU24.FNT",
		    "\\MINN\\MINN24.FNT",
		    "\\MARU\\MARU24.FNT",
		    "\\GOTH\\GOTH24.FNT" };
static char	*ankfile[]={
		    "\\KYOU\\KYOU24HK.FNT",
		    "\\MINN\\MINN24HK.FNT",
                    "\\MARU\\MARU24HK.FNT",
                    "\\GOTH\\GOTH24HK.FNT" };
static char	*kanfile2[]={
		    "\\KYOU24.FNT",
		    "\\MINN24.FNT",
		    "\\MARU24.FNT",
		    "\\GOTH24.FNT" };
static char	*ankfile2[]={
		    "\\KYOU24HK.FNT",
		    "\\MINN24HK.FNT",
                    "\\MARU24HK.FNT",
                    "\\GOTH24HK.FNT" };
static LRU	*top[HASH];
static LRU	*lru_buf=NULL;

void    helf_cnv(font)
register UCHAR   *font;
{
    int     i;
    register UCHAR   *p;

    p = font;
    for ( i = 0 ; i < 12 ; i++ ) {
        *(font++) = *p | *(p+3); p++;
        *(font++) = *p | *(p+3); p++;
        *(font++) = *p | *(p+3); p++;
        p += 3;
    }
}
UCHAR	*read_font(code,font)
UNSIG   code;
UCHAR   *font;
{
    UNSIG    cd;
    int      i,j,n,k,c;
    long     l;
    register UCHAR   *p;
    register UCHAR   *s;
    UCHAR   tmp[72];
    static UCHAR mska[]={ 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01 };
    static UCHAR msko[]={ 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 };

    if ( code & 0xFF00 ) {
        i = (code >> 8) - 0x21;
        j = (code & 0xff) - 0x21;
        l = (i * 94L + j) * 74L + 16L;
        fseek(kan_fp,l,0);
        fread(&cd,1,2,kan_fp);
        fread(tmp,1,72,kan_fp);
    } else if ( code == '{' ) {
        if ( (font = read_font(0x2150,font)) != NULL )
            helf_cnv(font);
        return font;
    } else if ( code == '}' ) {
        if ( (font = read_font(0x2151,font)) != NULL )
            helf_cnv(font);
        return font;
    } else {
        l = code * 74L;
        fseek(ank_fp,l,0);
        fread(&cd,1,2,ank_fp);
        fread(tmp,1,72,ank_fp);
    }
    cd = (cd >> 8) | (cd << 8);
    if ( code != cd )
	return NULL;

    s = font;
    for ( i = 0 ; i < 3 ; i++ ) {
        for ( n = 0 ; n < 8 ; n++ ) {
            p = &tmp[i];
            for ( j = 0 ; j < 3 ; j++ ) {
                for ( c = k = 0 ; k < 8 ; k++ ) {
                    if ( *p & mska[n] )
                        c |= (typ_flg == PC98 ? msko[k]:mska[k]);
                    p += 3;
                }
                *(s++) = c;
            }
	    PRB_out();
        }
    }
    return font;
}
UCHAR   *get_font(code)
UNSIG   code;
{
    int     hs;
    LRU     *p,*s;
 
    hs = code & (HASH-1);   /* code % hash */
    s = p = top[hs];
    while ( p->code != code ) {
        if ( p->next == NULL ) {
            p->code = code;
            p->next = top[hs];
            top[hs] = p;
            s->next = NULL;
            return read_font(code,p->font);
        }
        s = p;
        p = p->next;
    }
    if ( s != p ) {
	s->next = p->next;
	p->next = top[hs];
	top[hs] = p;
    }
    return p->font;
}
void    fnt_spc(n)
int     n;
{
    char    tmp[20];

    if ( n <= 0 )
        return;
    switch(typ_flg) {
        case FUJITU:
	    sprintf(tmp,"\x1bQ%d W",n);
	    prn_line_out(tmp);
            break;
        case ESCP:
            PRB_byte("\x1b\x2a\x27",3);
            PRB_chr(n & 0xFF);
            PRB_chr(n >> 8);
            break;
        case PC98:
	    sprintf(tmp,"\x1bJ%04d",n);
	    prn_line_out(tmp);
            break;
    }
    while ( n-- > 0 )
        PRB_byte("\x00\x00\x00",3);
}
void    fnt_kan(code)
UNSIG   code;
{
    int     i;
    UCHAR   *font;

    if ( (font = get_font(code)) == NULL ) {
        switch(typ_flg) {
            case FUJITU: prn_line_out("\x1b$B"); break;
            case ESCP:   prn_line_out("\x1c\x12"); break;
        }
        PRB_chr((UCHAR)(code >> 8));
        PRB_chr((UCHAR)code);
        return;
    }
    i = yousi[paper].spc / 2;
    fnt_spc(i);
    switch(typ_flg) {
        case FUJITU:
	    prn_line_out("\x1bQ24 W");
            break;
        case ESCP:
            PRB_byte("\x1b\x2a\x27\x18\x00",5);
            break;
        case PC98:
	    prn_line_out("\x1bJ0024");
            break;
    }
    PRB_byte(font,72);
    fnt_spc(yousi[paper].spc - i);
}
void    fnt_ank(code)
UNSIG   code;
{
    int     i;
    UCHAR   *font;

    if ( code < ' ' ) {
        if ( code == '\n' ) {
            ank_cnt = 0;
            PRB_chr('\x0D');
        }
        PRB_chr(code);
        return;
    }
    if ( (font = get_font(code & 0xFF)) == NULL ) {
        PRB_chr('\x07');
        return;
    }
    i = yousi[paper].spc / 2;
    fnt_spc(i/2);
    if ( yousi[paper].spc & 1 ) {
        if ( ank_cnt & 1 )
            fnt_spc(1);
        ank_cnt++;
    }
    switch(typ_flg) {
        case FUJITU:
	    prn_line_out("\x1bQ12 W");
            break;
        case ESCP:
            PRB_byte("\x1b\x2a\x27\x0C\x00",5);
            break;
        case PC98:
	    prn_line_out("\x1bJ0012");
            break;
    }
    PRB_byte(font,36);
    fnt_spc(i-(i/2));
}
int	lru_init()
{
    int     i,j;
    LRU	    *p;

    if ( (lru_buf = (LRU *)malloc(sizeof(LRU) * HASH * MAX)) == NULL )
	return ERR;
    p = lru_buf;
    for ( j = 0 ; j < HASH ; j++ ) {
	top[j] = p;
        for ( i = 0 ; i < (MAX-1) ; i++ ) {
            p->code = 0xFFFF;
            p->next = p + 1;
	    p++;
        }
        p->code = 0xFFFF;
	p->next = NULL;
	p++;
    }
    return FALSE;
}
int     fnt_init()
{
    int     rt = 0;
    char    *p;
    char    tmp[128];

LOOP:
    if ( rt > 3 )
	return ERR;

    switch(rt) {
    case 0:
	if ( fnt_dir == NULL && (fnt_dir = getenv("FNTDIR")) == NULL )
	    fnt_dir = "Q:\\FJ\\FNT";
	break;
    case 1:
	if ( fnt_dir == NULL && (fnt_dir = getenv("FNTDIR")) == NULL )
	    fnt_dir = "Q:\\FJ2\\FONT";
	break;
    case 2:
	fnt_dir = "Q:\\FJ\\FNT";
	break;
    case 3:
	fnt_dir = "Q:\\FJ2\\FONT";
	break;
    }

    strcpy(tmp,fnt_dir);
    switch(rt) {
	case 0: case 2: strcat(tmp,kanfile[fnt_flg]); break;
	case 1: case 3: strcat(tmp,kanfile2[fnt_flg]); break;
    }

    if ( (kan_fp = fopen(tmp,"rb")) == NULL ) {
	rt++;
	goto LOOP;
    }

    strcpy(tmp,fnt_dir);
    switch(rt) {
	case 0: case 2: strcat(tmp,ankfile[fnt_flg]); break;
	case 1: case 3: strcat(tmp,ankfile2[fnt_flg]); break;
    }

    if ( (ank_fp = fopen(tmp,"rb")) == NULL ) {
        fclose(kan_fp);
	rt++;
	goto LOOP;
    }

    if ( lru_init() != FALSE ) {
        fclose(kan_fp);
	fclose(ank_fp);
        return ERR;
    }
    ank_cnt = 0;
    return FALSE;
}
void    fnt_close()
{
    fclose(kan_fp);
    fclose(ank_fp);
    free(lru_buf);
}
