#include <u.h>
#include <libc.h>
#include <bio.h>
#include "dict.h"

/*
* Routines for handling dictionaries in the "Paperback Collins"
* `German' format (with tags surrounded by \5⋯\6 and \xba⋯\xba)
*/

/*
*      \5⋯\6 escapes (fonts, mostly)
*
*      h       headword (helvetica 7 pt)
*      c       clause (helvetica 7 pt)
*      3       helvetica 7 pt
*      4       helvetica 6.5 pt
*      s       helvetica 8 pt
*      x       helvetica 8 pt
*      y       helvetica 5 pt
*      m       helvetica 30 pt
*      1       roman 6 pt
*      9       roman 4.5 pt
*      p       roman 7 pt
*      q       roman 4.5 pt
*      2       italic 6 pt
*      7       italic 4.5 pt
*      b       bold 6 pt
*      a       `indent 0:4 left'
*      k       `keep 9'
*      l       `size 12'
*/

enum {
       IBASE=L'i',     /* dotless i */
       Taglen=32,
};

static Rune intab[256] = {
       /*0*/   /*1*/   /*2*/   /*3*/   /*4*/   /*5*/   /*6*/   /*7*/
/*00*/  NONE,   NONE,   NONE,   NONE,   NONE,   TAGS,   TAGE,   NONE,
       NONE,   NONE,   NONE,   NONE,   NONE,   L' ',   NONE,   NONE,
/*10*/  NONE,   L'-',   L' ',   L' ',   NONE,   NONE,   NONE,   NONE,
       L' ',   NONE,   NONE,   NONE,   L' ',   NONE,   NONE,   L'-',
/*20*/  L' ',   L'!',   L'"',   L'#',   L'$',   L'%',   L'&',   L'\'',
       L'(',   L')',   L'*',   L'+',   L',',   L'-',   L'.',   L'/',
/*30*/  L'0',   L'1',   L'2',   L'3',   L'4',   L'5',   L'6',   L'7',
       L'8',   L'9',   L':',   L';',   L'<',   L'=',   L'>',   L'?',
/*40*/  L'@',   L'A',   L'B',   L'C',   L'D',   L'E',   L'F',   L'G',
       L'H',   L'I',   L'J',   L'K',   L'L',   L'M',   L'N',   L'O',
/*50*/  L'P',   L'Q',   L'R',   L'S',   L'T',   L'U',   L'V',   L'W',
       L'X',   L'Y',   L'Z',   L'[',   L'\\',  L']',   L'^',   L'_',
/*60*/  L'`',   L'a',   L'b',   L'c',   L'd',   L'e',   L'f',   L'g',
       L'h',   L'i',   L'j',   L'k',   L'l',   L'm',   L'n',   L'o',
/*70*/  L'p',   L'q',   L'r',   L's',   L't',   L'u',   L'v',   L'w',
       L'x',   L'y',   L'z',   L'{',   L'|',   L'}',   L'~',   NONE,
/*80*/  NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,
       NONE,   NONE,   L' ',   NONE,   NONE,   NONE,   NONE,   NONE,
/*90*/  L'ß',  L'æ',  NONE,   MOE,    NONE,   NONE,   NONE,   L'ø',
       NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,
/*A0*/  NONE,   NONE,   L'"',   L'£',  NONE,   NONE,   NONE,   NONE,
       NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,
/*B0*/  NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   L'~',
       NONE,   IBASE,  SPCS,   NONE,   NONE,   NONE,   NONE,   NONE,
/*C0*/  NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,
       NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,
/*D0*/  NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,
       NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,
/*E0*/  NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,
       NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,
/*F0*/  L' ',   L' ',   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,
       NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,   NONE,
};

static Nassoc numtab[] = {
       {1,     L'+'},
       {4,     L'='},
       {7,     L'°'},
       {11,    L'≈'},
       {69,    L'♦'},
       {114,   L'®'},
       {340,   L'ɛ'},
       {341,   L'ɔ'},
       {342,   L'ʌ'},
       {343,   L'ə'},
       {345,   L'ʒ'},
       {346,   L'ʃ'},
       {347,   L'ɵ'},
       {348,   L'ʊ'},
       {349,   L'ˈ'},
       {351,   L'ɪ'},
       {352,   L'ɜ'},
       {354,   L'ɑ'},
       {355,   L'~'},
       {356,   L'ɒ'},
       {384,   L'ɳ'},
       {445,   L'ð'}, /* BUG -- should be script eth */
};

static Nassoc overtab[] = {
       {L',',  LCED},
       {L'/',  LACU},
       {L':',  LUML},
       {L'\\', LGRV},
       {L'^',  LFRN},
       {L'~',  LTIL},
};

static uchar *reach(uchar*, int);

static Entry    curentry;
static char     tag[Taglen];

void
pcollgprintentry(Entry e, int cmd)
{
       uchar *p, *pe;
       int r, rprev = NONE, rx, over = 0, font;
       char buf[16];

       p = (uchar *)e.start;
       pe = (uchar *)e.end;
       curentry = e;
       if(cmd == 'h')
               outinhibit = 1;
       while(p < pe){
               if(cmd == 'r'){
                       outchar(*p++);
                       continue;
               }
               switch(r = intab[*p++]){        /* assign = */
               case TAGS:
                       if(rprev != NONE){
                               outrune(rprev);
                               rprev = NONE;
                       }
                       p = reach(p, 0x06);
                       font = tag[0];
                       if(cmd == 'h')
                               outinhibit = (font != 'h');
                       break;

               case TAGE:      /* an extra one */
                       break;

               case SPCS:
                       p = reach(p, 0xba);
                       r = looknassoc(numtab, asize(numtab), strtol(tag,0,0));
                       if(r < 0){
                               if(rprev != NONE){
                                       outrune(rprev);
                                       rprev = NONE;
                               }
                               sprint(buf, "\\N'%s'", tag);
                               outchars(buf);
                               break;
                       }
                       /* else fall through */

               default:
                       if(over){
                               rx = looknassoc(overtab, asize(overtab), r);
                               if(rx > 0)
                                       rx = liglookup(rx, rprev);
                               if(rx > 0 && rx != NONE)
                                       outrune(rx);
                               else{
                                       outrune(rprev);
                                       if(r == ':')
                                               outrune(L'¨');
                                       else{
                                               outrune(L'^');
                                               outrune(r);
                                       }
                               }
                               over = 0;
                               rprev = NONE;
                       }else if(r == '^'){
                               over = 1;
                       }else{
                               if(rprev != NONE)
                                       outrune(rprev);
                               rprev = r;
                       }
               }

       }
       if(rprev != NONE)
               outrune(rprev);
       if(cmd == 'h')
               outinhibit = 0;
       outnl(0);
}

long
pcollgnextoff(long fromoff)
{
       int c, state = 0, defoff = -1;

       if(Bseek(bdict, fromoff, 0) < 0)
               return -1;
       while((c = Bgetc(bdict)) >= 0){
               if(c == '\r')
                       defoff = Boffset(bdict);
               switch(state){
               case 0:
                       if(c == 0x05)
                               state = 1;
                       break;
               case 1:
                       if(c == 'h')
                               state = 2;
                       else
                               state = 0;
                       break;
               case 2:
                       if(c == 0x06)
                               return (Boffset(bdict)-3);
                       else
                               state = 0;
                       break;
               }
       }
       return defoff;
}

void
pcollgprintkey(void)
{
       Bprint(bout, "No pronunciation key yet\n");
}

static uchar *
reach(uchar *p, int tagchar)
{
       int c; char *q=tag;

       while(p < (uchar *)curentry.end){
               c = *p++;
               if(c == tagchar)
                       break;
               *q++ = c;
               if(q >= &tag[sizeof tag-1])
                       break;
       }
       *q = 0;
       return p;
}