#include <u.h>
#include <libc.h>
#include <bio.h>
#include "hdr.h"
#include "conv.h"

typedef struct Tmap Tmap;
struct Tmap
{
       Rune u;
       Rune t;
};

static Tmap t1[] =
{
       {0x0b85/*அ*/, 0xe201/**/},
       {0x0b86/*ஆ*/, 0xe202/**/},
       {0x0b87/*இ*/, 0xe203/**/},
       {0x0b88/*ஈ*/, 0xe204/**/},
       {0x0b89/*உ*/, 0xe205/**/},
       {0x0b8a/*ஊ*/, 0xe206/**/},
       {0x0b8e/*எ*/, 0xe207/**/},
       {0x0b8f/*ஏ*/, 0xe208/**/},
       {0x0b90/*ஐ*/, 0xe209/**/},
       {0x0b92/*ஒ*/, 0xe20a/**/},
       {0x0b93/*ஓ*/, 0xe20b/**/},
       {0x0b94/*ஔ*/, 0xe20c/**/},
       {0x0b83/*ஃ*/, 0xe20d/**/}
};

static Rune t2[] =
{
       0x0bcd/*்*/,
       0x0bcd/*்*/,  // filler
       0x0bbe/*ா*/,
       0x0bbf/*ி*/,
       0x0bc0/*ீ*/,
       0x0bc1/*ு*/,
       0x0bc2/*ூ*/,
       0x0bc6/*ெ*/,
       0x0bc7/*ே*/,
       0x0bc8/*ை*/,
       0x0bca/*ொ*/,
       0x0bcb/*ோ*/,
       0x0bcc/*ௌ*/
};

static Tmap t3[] =
{
       {0x0b95/*க*/, 0xe211/**/},
       {0x0b99/*ங*/, 0xe221/**/},
       {0x0b9a/*ச*/, 0xe231/**/},
       {0x0b9c/*ஜ*/, 0xe331/**/},
       {0x0b9e/*ஞ*/, 0xe241/**/},
       {0x0b9f/*ட*/, 0xe251/**/},
       {0x0ba3/*ண*/, 0xe261/**/},
       {0x0ba4/*த*/, 0xe271/**/},
       {0x0ba8/*ந*/, 0xe281/**/},
       {0x0ba9/*ன*/, 0xe321/**/},
       {0x0baa/*ப*/, 0xe291/**/},
       {0x0bae/*ம*/, 0xe2a1/**/},
       {0x0baf/*ய*/, 0xe2b1/**/},
       {0x0bb0/*ர*/, 0xe2c1/**/},
       {0x0bb1/*ற*/, 0xe311/**/},
       {0x0bb2/*ல*/, 0xe2d1/**/},
       {0x0bb3/*ள*/, 0xe301/**/},
       {0x0bb4/*ழ*/, 0xe2f1/**/},
       {0x0bb5/*வ*/, 0xe2e1/**/},
       {0x0bb6/*ஶ*/, 0xe341/**/},
       {0x0bb7/*ஷ*/, 0xe351/**/},
       {0x0bb8/*ஸ*/, 0xe361/**/},
       {0x0bb9/*ஹ*/, 0xe371/**/}
};

static Rune
findbytune(Tmap *tab, int size, Rune t)
{
       int i;

       for(i = 0; i < size; i++)
               if(tab[i].t == t)
                       return tab[i].u;
       return Runeerror;
}

static Rune
findbyuni(Tmap *tab, int size, Rune u)
{
       int i;

       for(i = 0; i < size; i++)
               if(tab[i].u == u)
                       return tab[i].t;
       return Runeerror;
}

static int
findindex(Rune *rstr, int size, Rune r)
{
       int i;

       for(i = 0; i < size; i++)
               if(rstr[i] == r)
                       return i;
       return -1;
}

void
tune_in(int fd, long *, struct convert *out)
{
       Biobuf b;
       Rune *r, *er, tr;
       int c, i;

       r = runes;
       er = runes+N-3;
       Binit(&b, fd, OREAD);
       while((c = Bgetrune(&b)) != Beof){
               ninput += b.runesize;
               if(r >= er){
                       OUT(out, runes, r-runes);
                       r = runes;
               }
               if(c>=0xe210/**/ && c <= 0xe38c/**/ && (i = c%16) < nelem(t2)){
                       if(c >= 0xe380/**/){
                               *r++ = 0x0b95/*க*/;
                               *r++ = 0x0bcd/*்*/;
                               *r++ = 0x0bb7/*ஷ*/;
                       }else
                               *r++ = findbytune(t3, nelem(t3), c-i+1);
                       if(i != 1)
                               *r++ = t2[i];
               }else if((tr = findbytune(t1, nelem(t1), c)) != Runeerror)
                       *r++ = tr;
               else switch(c){
                       case 0xe3d0/**/:
                               *r++ = 0x0ba3/*ண*/; *r++ = 0x0bbe/*ா*/;
                               break;
                       case 0xe3d1/**/:
                               *r++ = 0x0bb1/*ற*/; *r++ = 0x0bbe/*ா*/;
                               break;
                       case 0xe3d2/**/:
                               *r++ = 0x0ba9/*ன*/; *r++ = 0x0bbe/*ா*/;
                               break;
                       case 0xe3d4/**/:
                               *r++ = 0x0ba3/*ண*/; *r++ = 0x0bc8/*ை*/;
                               break;
                       case 0xe3d5/**/:
                               *r++ = 0x0bb2/*ல*/; *r++ = 0x0bc8/*ை*/;
                               break;
                       case 0xe3d6/**/:
                               *r++ = 0x0bb3/*ள*/; *r++ = 0x0bc8/*ை*/;
                               break;
                       case 0xe3d7/**/:
                               *r++ = 0x0ba9/*ன*/; *r++ = 0x0bc8/*ை*/;
                               break;
                       case 0xe38d/**/:
                               *r++ = 0x0bb6/*ஶ*/; *r++ = 0x0bcd/*்*/; *r++ = 0x0bb0/*ர*/; *r++ = 0x0bc0/*ீ*/;
                               break;
                       default:
                               if(c >= 0xe200 && c <= 0xe3ff){
                                       if(squawk)
                                               warn("rune 0x%x not in output cs", c);
                                       nerrors++;
                                       if(clean)
                                               break;
                                       c = BADMAP;
                               }
                               *r++ = c;
                               break;
               }
       }
       if(r > runes)
               OUT(out, runes, r-runes);
       OUT(out, runes, 0);
}

void
tune_out(Rune *r, int n, long *)
{
       static int state = 0;
       static Rune lastr;
       Rune *er, tr, rr;
       char *p;
       int i;

       nrunes += n;
       er = r+n;
       for(p = obuf; r < er; r++){
               switch(state){
               case 0:
               case0:
                       if((tr = findbyuni(t3, nelem(t3), *r)) != Runeerror){
                               lastr = tr;
                               state = 1;
                       }else if(*r == 0x0b92/*ஒ*/){
                               lastr = 0xe20a/**/;
                               state = 3;
                       }else if((tr = findbyuni(t1, nelem(t1), *r)) != Runeerror)
                               p += runetochar(p, &tr);
                       else
                               p += runetochar(p, r);
                       break;
               case 1:
               case1:
                       if((i = findindex(t2, nelem(t2), *r)) != -1){
                               if(lastr && lastr != Runeerror)
                                       lastr += i-1;
                               if(*r ==0x0bc6/*ெ*/)
                                       state = 5;
                               else if(*r ==0x0bc7/*ே*/)
                                       state = 4;
                               else if(lastr == 0xe210/**/)
                                       state = 2;
                               else if(lastr == 0xe340/**/)
                                       state = 6;
                               else{
                                       if(lastr)
                                               p += runetochar(p, &lastr);
                                       state = 0;
                               }
                       }else if(lastr && lastr != Runeerror && (*r == 0x00b2/*²*/ || *r == 0x00b3/*³*/ || *r == 0x2074/*⁴*/)){
                               if(squawk)
                                       warn("character <U+%.4X, U+%.4X> not in output cs", lastr, *r);
                               lastr = clean ? 0 : Runeerror;
                               nerrors++;
                       }else{
                               if(lastr)
                                       p += runetochar(p, &lastr);
                               state = 0;
                               goto case0;
                       }
                       break;
               case 2:
                       if(*r == 0x0bb7/*ஷ*/){
                               lastr = 0xe381/**/;
                               state = 1;
                               break;
                       }
                       p += runetochar(p, &lastr);
                       state = 0;
                       goto case0;
               case 3:
                       state = 0;
                       if(*r == 0x0bd7/*ௗ*/){
                               rr = 0xe20c/**/;
                               p += runetochar(p, &rr);
                               break;
                       }
                       p += runetochar(p, &lastr);
                       goto case0;
               case 4:
                       state = 0;
                       if(*r == 0x0bbe/*ா*/){
                               if(lastr){
                                       if(lastr != Runeerror)
                                               lastr += 3;
                                       p += runetochar(p, &lastr);
                               }
                               break;
                       }
                       if(lastr)
                               p += runetochar(p, &lastr);
                       goto case0;
               case 5:
                       state = 0;
                       if(*r == 0x0bbe/*ா*/ || *r == 0x0bd7/*ௗ*/){
                               if(lastr){
                                       if(lastr != Runeerror)
                                               lastr += *r == 0x0bbe/*ா*/ ? 3 : 5;
                                       p += runetochar(p, &lastr);
                               }
                               break;
                       }
                       if(lastr)
                               p += runetochar(p, &lastr);
                       goto case0;
               case 6:
                       if(*r == 0x0bb0/*ர*/){
                               state = 7;
                               break;
                       }
                       p += runetochar(p, &lastr);
                       state = 0;
                       goto case0;
               case 7:
                       if(*r == 0x0bc0/*ீ*/){
                               rr = 0xe38d/**/;
                               p += runetochar(p, &rr);
                               state = 0;
                               break;
                       }
                       p += runetochar(p, &lastr);
                       lastr = 0xe2c1/**/;
                       state = 1;
                       goto case1;
               }
       }
       if(n == 0 && state != 0){
               if(lastr)
                       p += runetochar(p, &lastr);
               state = 0;
       }
       noutput += p-obuf;
       if(p > obuf)
               write(1, obuf, p-obuf);
}