#include <stdio.h>
#include <ctype.h>
#include <regex.h>
#include <unistd.h>

#define ML 1024
#define PREFIX "../../texts"

struct lookup_table {
    char *key;
    char *value;
};

static struct lookup_table foo[] =
{
    { "Ap. Met.", "apuleius/met"},
    { "B. Afr.",  "anonymous/ba"},
    { "B. C.",    "caesar/civile"},
    { "B. G.",    "caesar/dbg"},
    { "de M.",    "cato/moribus"},
    { "R. R.",    "cato/rr"},
    { "Catull.",  "catullus/catullus"},

    /* Cicero references do not contain "Cic." */
    { "Acad.",    "cicero/acad"},
    { "Ad Her.",  "cicero/herennium"},
    { "Arch.",    "cicero/archia"},
    { "Att.",     "cicero/atticum"},
    { "Balb.",    "cicero/balbo"},
    { "Brut.",    "cicero/brutus"},
    { "Caec.",    "cicero/caecina"},
    { "Caecil.",  "cicero/caecil"},
    { "Cael.",    "cicero/caelio"},
    { "Cat.",     "cicero/catilin"},
    { "Cat. M.",  "cicero/senectute"},
    { "Clu.",     "cicero/cluentio"},
    { "Deiot.",   "cicero/deiotaro"},
    { "De Or.",   "cicero/oratore"},
    { "Div.",     "cicero/divinatione"},
    { "Dom.",     "cicero/domo"},
    { "Fam.",     "cicero/familiares"},
    { "Fat.",     "cicero/fato"},
    { "Fin.",     "cicero/finibus"},
    { "Flacc.",   "cicero/flacco"},
    { "Font.",    "cicero/fonteio"},
    { "Har. Resp.", "cicero/haruspicum"},
    { "Inv.",     "cicero/inventione"},
    { "Lael.",    "cicero/amicitia"},
    { "Leg. Agr.", "cicero/agraria"},
    { "Legg.",    "cicero/legibus"},
    { "Lig.",     "cicero/ligario"},
    { "Manil.",   "cicero/manilia"},
    { "Marc.",    "cicero/marcello"},
    { "Mil.",     "cicero/milone"},
    { "Mur.",     "cicero/murone"},
    { "N. D.",    "cicero/deorum"},
    { "Off.",     "cicero/officiis"},
    { "Or.",      "cicero/orator"},
    { "Par.",     "cicero/paradoxa"},
    { "Part.",    "cicero/partitione"},
    { "Phil.",    "cicero/phillipicae"},
    { "Planc.",   "cicero/plancio"},
    { "Pison.",   "cicero/pisonem"},
    { "Prov. Cons.", "cicero/consularibus"},
    { "Q. Fr.",   "cicero/fratrem"},
    { "Quinct.",  "cicero/quinctio"},
    { "Rabir.",   "cicero/rabirio"},
    { "Rab. Post.", "cicero/postumo"},
    { "Rep.",     "cicero/republica"},
    { "Rosc. Am.", "cicero/amerino"},
    { "Rosc. Com.", "cicero/comoedo"},
    { "Scaur.",   "cicero/scauro"},
    { "Sest.",    "cicero/sestio"},
    { "Sull.",    "cicero/sulla"},
    { "Tim.",     "cicero/timaeus"},
    { "Top.",     "cicero/topica"},
    { "Tull.",    "cicero/tullio"},
    { "Tusc.",    "cicero/tusculanae"},
    { "Vat.",     "cicero/vatinium"},
    { "Verr.",    "cicero/verrem"},

    { "iv C. H.",   "claudianus/qch"},
    { "Enn.",     "ennius/ennius"},
    { "Gell.",    "gellius/gellius"},
    { "B. Al.",   "hirtius/ba"},
    { "Hor. A. P.", "horatius/poetica"},
    { "Hor. C. S.", "horatius/saeculare"},
    { "Hor. Ep.", "horatius/epistles"},
    { "Hor. Epist.", "horatius/epodes"},
    { "Hor. Od.", "horatius/odes"},
    { "Hor. S.",  "horatius/satires"},
    { "Iust.",    "iustinius/iust"},
    { "Iuv.",     "iuvenalis/iuv"},
    { "Liv.",     "livius/auc"},
    { "Lucr.",    "lucretius/drn"},
    { "Mart. Ep.", "martius/epigrams"},

    { "Nep. Ages.", "nepos/agesilaus"},
    { "Nep. Alc.", "nepos/alcibiades"},
    { "Nep. Att.", "nepos/atticus"},
    { "Nep. Dat.", "nepos/datames"},
    { "Nep. Dion", "nepos/dion"},
    { "Nep. Epam.", "nepos/epaminondas"},
    { "Nep. Eum.", "nepos/eumenes"},
    { "Nep. Hann.", "nepos/hannibal"},
    { "Nep. Milt.", "nepos/miltiades"},
    { "Nep. Paus.", "nepos/pausanias"},
    { "Nep. Them.", "nepos/themistocles"},
    { "Nep. Timoth.", "nepos/timotheus"},

    { "Ov. A. A.", "ovidius/amatoria"},
    { "Ov. F.",   "ovidius/fasti"},
    { "Ov. H.",   "ovidius/heroides"},
    { "Ov. M.",   "ovidius/metamorphoses"},
    { "Ov. Pont.", "ovidius/ponto"},
    { "Ov. Trist.", "ovidius/tristia"},

    { "Pers. Sat.", "persius/satires"},
    { "Pers.",    "persius/satires"},
    { "Phaed.",   "phaedrus/phaedrus"},

    { "Pl. Am.",  "plautus/amphitruo"},
    { "Pl. As.",  "plautus/asinaria"},
    { "Pl. Aul.", "plautus/aulularia"},
    { "Pl. Bac.", "plautus/bacchides"},
    { "Pl. Capt.", "plautus/captivi"},
    { "Pl. Cist.", "plautus/cistellaria"},
    { "Pl. Curc.", "plautus/curculio"},
    { "Pl. Epid.", "plautus/epidicus"},
    { "Pl. Men.",  "plautus/menaechmi"},
    { "Pl. Merc.", "plautus/mercator"},
    { "Pl. Mil.",  "plautus/mg"},
    { "Pl. Most.", "plautus/mostellaria"},
    { "Pl. Pers.", "plautus/persa"},
    { "Pl. Poen.", "plautus/poenulus"},
    { "Pl. Ps.",  "plautus/pseudolus"},
    { "Pl. Pseud.", "plautus/pseudolus"}, /* A & G screw up again... */
    { "Pl. Rud.",  "plautus/rudens"},
    { "Pl. Stich.", "plautus/stichus"},
    { "Pl. Trin.", "plautus/trinummus"},
    { "Pl. Truc.", "plautus/truculentus"},

    { "Plaut. Am.",  "plautus/amphitruo"},
    { "Plaut. As.",  "plautus/asinaria"},
    { "Plaut. Aul.", "plautus/aulularia"},
    { "Plaut. Bac.", "plautus/bacchides"},
    { "Plaut. Capt.", "plautus/captivi"},
    { "Plaut. Cist.", "plautus/cistellaria"},
    { "Plaut. Curc.", "plautus/curculio"},
    { "Plaut. Epid.", "plautus/epidicus"},
    { "Plaut. Men.",  "plautus/menaechmi"},
    { "Plaut. Merc.", "plautus/mercator"},
    { "Plaut. Mil.",  "plautus/mg"},
    { "Plaut. Most.", "plautus/mostellaria"},
    { "Plaut. Pers.", "plautus/persa"},
    { "Plaut. Poen.", "plautus/poenulus"},
    { "Plaut. Ps.",  "plautus/pseudolus"},
    { "Plaut. Pseud.", "plautus/pseudolus"}, /* A & G screw up again... */
    { "Plaut. Rud.",  "plautus/rudens"},
    { "Plaut. Stich.", "plautus/stichus"},
    { "Plaut. Trin.", "plautus/trinummus"},
    { "Plaut. Truc.", "plautus/truculentus"},

    { "Plin. H. N.", "plinius/hn"},
    { "Plin. Ep.", "plinius/epist"},
    { "Prop.",    "propertius/proper"},
    { "Pub. Syr.", "syrus/syrus"},
    { "Q. C.",    "curtius/curtius"},
    { "Quint.",   "quintilianus/quint"},

    /* Iug. has no Sall. before it, either */
    { "Iug.",     "sallustius/iugurtha"},
    { "Sall. Cat.", "sallustius/salcatil"},
    { "Sall. Ep. Mith.", "sallustius/mithridatis"},

    { "S. C. de Bac.", "anonymous/bacchanalibus"},

    { "Sen. Dial.", "seneca/dialogues"},
    { "Sen. Ep.",   "seneca/epistles"},
    { "Sen. Herc. Fur.", "seneca/hf"},
    { "Sen. Herc. Oet.", "seneca/ho"},
    { "Sen. Med.",  "seneca/medea"},
    { "Sen. Q. N.", "seneca/naturales"},
    { "Sil.",     "silius/silius"},
    { "Suet. Aug.", "suetonius/augustus"},
    { "Suet. Dom.", "suetonius/domitianus"},
    { "Suet. Galb.", "suetonius/galba"},
    { "Tac. Agr.", "tacitus/agricola"},
    { "Tac. Ann.", "tacitus/annales"},
    { "Tac. H.",   "tacitus/historiae"},
    { "Ter. Ad.",  "terentius/adelphi"},
    { "Ter. And.", "terentius/andria"},
    { "Ter. Eun.", "terentius/eunuchus"},
    { "Ter. Haut.", "terentius/haut"},
    { "Ter. Hec.", "terentius/hecyra"},
    { "Ter. Ph.",  "terentius/phormio"},

    { "Val.",     "valerius/valerius"},
    { "Varr. R. R.", "varro/rr"},
    { "Vell.",    "velleius/velleius"},

    /* And vergil doesn't need his name noted, either. */
    { "Aen.",     "vergilius/aeneid"},
    { "Ecl.",     "vergilius/ecloga"},
    { "Georg.",   "vergilius/georg"},
    { NULL, NULL }};


/*
 * Convert a Roman numeral into a Decimal value.
 */

int rtoi(char *s)
{
    int r=0;

    while(*s)
    {
        switch(*s)
        {
          case 'm': case 'M':
            r += 1000;
            break;
          case 'd': case 'D':
            r += 500;
            break;
          case 'c': case 'C':
            if(s[1]=='m' || s[1]=='M')
            {
                r += 900;
                s++;
                break;
            }
            if(s[1]=='d' || s[1]=='D')
            {
                r += 400;
                s++;
                break;
            }
            r += 100;
            break;
          case 'l': case 'L':
            r += 50;
            break;
          case 'x': case 'X':
            if(s[1]=='c' || s[1]=='C')
            {
                r += 90;
                s++;
                break;
            }
            if(s[1]=='l' || s[1]=='L')
            {
                r += 40;
                s++;
                break;
            }
            r += 10;
            break;
          case 'v': case 'V':
            r += 5;
            break;
          case 'i': case 'I':
            if(s[1]=='x' || s[1]=='X')
            {
                r += 9;
                s++;
                break;
            }
            if(s[1]=='v' || s[1]=='V')
            {
                r += 4;
                s++;
                break;
            }
            r += 1;
            break;
          default:
            return r;
        }
        s++;
    }
    return r;
}

char *lookup_work(char *s)
{
    int i, j, found;
    char temp[256];

    /* first, standardize spacing */
    for(i=j=0; s[i+j];i++)
    {
        s[i]=s[i+j];
        if(isspace(s[i]))
        {
            while(isspace(s[i+j]))
                j++;
            j--;
        }
    }
    s[i]='\0';

    for(i=0;foo[i].key!=NULL;i++)
    {
        if(strcmp(foo[i].key,s+1)==0)
        {
            found=0;

            sprintf(temp,"../../texts/%s.html",foo[i].value);
            if(access(temp,R_OK)==0)
                found=1;
            sprintf(temp,"../../texts/%s1.html",foo[i].value);
            if(access(temp,R_OK)==0)
                found=1;
            sprintf(temp,"../../texts/%s01.html",foo[i].value);
            if(access(temp,R_OK)==0)
                found=1;
            if(found)
                return foo[i].value;
            else
            {
                 fprintf(stderr,"%s (%s): not found\n",foo[i].value,s+1);
                 return NULL;
            }
        }
    }
    fprintf(stderr,"%s: no match.\n",s+1);
    return NULL;
}

#if 0
# define regcmp(a,b) (re_comp((a)),re_exec((b)))
#else
int regcmp(char *a, char *b)
{
    regex_t preg;
    int results;

    regcomp(&preg,a,REG_NOSUB|REG_EXTENDED);
    results = !regexec(&preg,b,0,NULL,0);
    regfree(&preg);

    return results;
}
#endif

int main(void)
{
    int c, i, line=1, book, sect, chap;
    char s[ML], pre_work[ML], *last_work=NULL;

    while((c=getchar())!=EOF)
    {
        if(c=='\n')
            line++;
        if(c!='(')
            putchar(c);
        else
        {
            i=0;
            do
            {
                if(c=='\n')
                {
                    line++;
                    c=' ';
                }
                s[i++]=c;
            } while((c=getchar())!=EOF && c!=')');
            s[i++]=c;
            s[i]='\0';
            if(regcmp("\\(id\\.[~ ][0-9][0-9]*\\)",s))
            {
                for(i=0;!isdigit(s[i]);i++)
                    ;
                chap = atoi(s+i);
                if(last_work)
                    printf("<a href=\"%s/%s.html#%d\">%s</a>",
                           PREFIX,last_work,chap,s);
                else
                    printf("%s",s);
            }
            else if(regcmp("\\(id\\.[~ ][ivx][ivx]*\\.[~ ][0-9][0-9]*\\)",s))
            {
                for(i=0;!isspace(s[i])&&s[i]!='~';i++)
                    ;
                for(;isspace(s[i])||s[i]=='~';i++)
                    ;
                book = rtoi(s+i);
                for(;!isspace(s[i])&&s[i]!='~';i++)
                    ;
                for(;isspace(s[i])||s[i]=='~';i++)
                    ;
                chap = atoi(s+i);
                
                if(last_work)
                    printf("<a href=\"%s/%s%d.html#%d\">%s</a>",
                           PREFIX,last_work,book,chap,s);
                else
                    printf("%s",s);
            }
            else if(regcmp("\\([A-Z][a-z]*\\.*[ ~][ ~]*[0-9][0-9]*\\)",s))
            {
                for(i=0;!isspace(s[i])&&s[i]!='~';i++)
                    pre_work[i]=s[i];
                pre_work[i]='\0';
                last_work = lookup_work(pre_work);
                for(;isspace(s[i])||s[i]=='~';i++)
                    ;
                chap = atoi(s+i);
                if(last_work)
                    printf("<a href=\"%s/%s.html#%d\">%s</a>",
                           PREFIX,last_work,chap,s);
                else
                    printf("%s",s);
            }
            else if(regcmp("\\([A-Z][a-z]*\\.*[ ~][ ~]*[ivx][ivx]*\\.*[ ~][ ~]*[0-9][0-9]*\\)",s))
            {
                for(i=0;!isspace(s[i])&&s[i]!='~';i++)
                    pre_work[i]=s[i];
                pre_work[i]='\0';
                last_work = lookup_work(pre_work);
                for(;isspace(s[i])||s[i]=='~';i++)
                    ;
                book = rtoi(s+i);
                for(;!isspace(s[i])&&s[i]!='~';i++)
                    ;
                for(;isspace(s[i])||s[i]=='~';i++)
                    ;
                chap = atoi(s+i);
                if(last_work)
                    printf("<a href=\"%s/%s%d.html#%d\">%s</a>",
                           PREFIX,last_work,book,chap,s);
                else
                    printf("%s",s);
            }
            
            else if(regcmp("\\([A-Z][a-z]*\\.*[ ~][ ~]*[A-Z][a-z]*\\.*[ ~][ ~]*[ivx][ivx]*\\.*[ ~][ ~]*[0-9][0-9]*\\)",s))
            {
                for(i=0;!isspace(s[i])&&s[i]!='~';i++)
                    pre_work[i]=s[i];
                for(;isspace(s[i])||s[i]=='~';i++)
                    pre_work[i]=' ';
                for(;!isspace(s[i])&&s[i]!='~';i++)
                    pre_work[i]=s[i];
                pre_work[i]='\0';
                last_work = lookup_work(pre_work);
                for(;isspace(s[i])||s[i]=='~';i++)
                    ;
                book = rtoi(s+i);
                for(;!isspace(s[i])&&s[i]!='~';i++)
                    ;
                for(;isspace(s[i])||s[i]=='~';i++)
                    ;
                chap = atoi(s+i);
                if(last_work)
                    printf("<a href=\"%s/%s%d.html#%d\">%s</a>",
                           PREFIX,last_work,book,chap,s);
                else
                    printf("%s",s);
            }
            else if(regcmp("\\([A-Z][a-z]*\\.*[ ~][ ~]*[A-Z][a-z]*\\.*[ ~][ ~]*[0-9][0-9]*\\)",s))
            {
                for(i=0;!isspace(s[i])&&s[i]!='~';i++)
                    pre_work[i]=s[i];
                for(;isspace(s[i])||s[i]=='~';i++)
                    pre_work[i]=' ';
                for(;!isspace(s[i])&&s[i]!='~';i++)
                    pre_work[i]=s[i];
                pre_work[i]='\0';
                last_work = lookup_work(pre_work);
                for(;isspace(s[i])||s[i]=='~';i++)
                    ;
                chap = atoi(s+i);
                if(last_work)
                    printf("<a href=\"%s/%s.html#%d\">%s</a>",
                           PREFIX,last_work,chap,s);
                else
                    printf("%s",s);
            }
            else
            {
                /* nothing special */
                printf("%s",s);
            }
        }
    }
    return;
}
