//Toto je pokus programu pro sklonovani jmen.
//Umi vysklonovat jen jmena z rodu muzskeho zivotneho a zenskeho.
//vse v cisle jednotnem.
//Hodi se do ceskych her pro oslovovani hracu.


//Padovani probiha tak:
/*
  Ke jmenu je treba znat rod: Muzsky/ Zensky

  Pak podle rodu se hleda ve vzorech pro muzky nebo zesky rod:
  Nejprve se porovnaji dva posledni znaky jmeno s mapou znaku u zkoumaneho
vzoru. Pokud tyto znaky souhlasi, muze byt jmeno vysklonovano.
  Pri sklonovani se neprve z koncovky odebere urcity, nebo zadny pocet znaku.
Potom se pripadne upravi konverze dlouheho 'u' s krouzkem na 'o' "Kun"=>"kone".
Nasledne se pripoji koncovka a nakonec se provede kontrola na znak e pred
souhlaskou, ktere je nutne vypustit: Marek => Marka.
  Pri sklonovani muzou ale vzniknout chybne dvojznakove spojeni: treba znak 'n'
s hackem a 'e'. Tyto dvojice jsou vyhledany a nahrazeny dvojici spravnou,
v nasem pripade 'n' a 'e' s hackem.

Ja jen doufam ze tyto upravy maj obecny charakter :-)
Da se prepokladat ze ve svete existuje plno jmen, ktere nelze takto sklonovat.
U nekterych ani neni jasny jak tato jmena sklonovat. Treba
  Bredy, Bredyho, Bredymu, Bredy, Bredy, Bredym, Bredym - Co je to za vzor ???
Uz nemluvim o jmenach cizich.
*/

//Definice knihoven
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <malloc.h>

typedef char TPAD[8];
//typ TPAD predstavuje koncovku pro jeden pad

typedef char TZNAKY[40];
//typ TZNAKY predstavuje mapu znaku se kterymi vzor pracuje.
//pokud je na prvnim miste znak '*' tak vzor pracuje se vsemy.

typedef struct vzor
  {
  TZNAKY znak1;
  TZNAKY znak2;
  char chrdel;
  TPAD pady[7];
  }TVZOR;
//struktura TVZOR popisuje sklonovani jednoho vzoru
//znak1 predstavuje mapu znaku pro jmeno v prvnim pade na predposledni pozici
// ... pokud znak neni v mape, nelze jmeno v tomto vzoru sklonovat
//znak2 je jako znak1 s tim ze se testuje znak na posledni pozici
//chrdel je pocet znaku, ktere musi byt odebrany pred pridanim pripony.
//navic pokud je chrdel=0 uplatnuje se konverze Kun -> kone a podobne.
//pady predstavuje jednotlive koncovky pro pady
// pokud je pad roven '-' znamena to ze tvar je schodny jako v 1. pade.

TVZOR zena=
  {
  "hkrdtnbflmpsvz",
  "a o¢u£–y˜",
  1,
  "-","y","ˆ","u","o","ˆ","ou"
  };
//Vzor pro zena

TVZOR natasa=
  {
  "c‡ƒj¤©¨Ÿ‘",
  "a ",
  1,
  "-","i","ˆ","u","o","ˆ","ou"
  };
//Vzor pro zena koncici mekkou souhlaskou a a

TVZOR ruze=
  {
  "c‡ƒj¤©¨Ÿ‘",
  "e‚i¡o¢u£–",
  1,
  "-","e","i","i","e","i","¡"
  };
//Vzor pro ruze s mekkou koncovkou

TVZOR ruze2=
  {
  "dtn",
  "i¡ˆ",
  1,
  "-","e","i","i","e","i","¡"
  };
//Vzor pro ruze s tvrdou koncovkou d,t,n s mekkou samohlaskou


TVZOR pisen=
  {
  "*",
  "c‡ƒj¤©¨Ÿ‘flmsx",
  0,
  "-","e","i","-","i","i","¡"
  };
//vzor pisen

TVZOR kost=
  {
  "*",
  "hkrdtnbpvz",
  0,
  "-","i","i","-","i","i","¡"
  };
//vzor kost

TVZOR pan=
  {
  "*",
  "rdtnbflmpsvz",
  0,
  "-","a","ovi","a","e","ovi","em"
  };
//vzor pan standardni

TVZOR pan2=
  {
  "*",
  "hk",
  0,
  "-","a","ovi","a","u","ovi","em"
  };
//vzor pan pro specialni koncovky h nebo k => pro 5. pad
// Rumburak => Rumburaku / nikoliv Rumburake.


TVZOR quasimodo=
  {
  "hkrdtnbflmpsvz",
  "o",
  1,
  "o","a","ovi","a","o","ovi","em"
  };
//vzor quasimodo resici pripad koncovky '-odo'.
//Odo, oda, odovi, oda, odo, odovi, odem

TVZOR pritel=
  {
  "e‚",
  "c‡ƒj¤©¨Ÿ‘bflmpsvz",
  0,
  "-","e","i","e","i","i","em"
  };
//vzor pritel pro vzor muz pro obojetne souhlasky ze samohlaskou e, ‚

TVZOR muz=
  {
  "*",
  "c‡ƒj¤©¨Ÿ‘",
  0,
  "-","e","i","e","i","i","em"
  };
//vzor muz

TVZOR fenix=
  {
  "*",
  "x",
  0,
  "-","e","ovi","e","i","ovi","em"
  };
//vzor pro jmena koncici -x



TVZOR predseda=
  {
  "hkrdtnbpvz",
  "a o¢u£–y˜",
  1,
  "a","y","ovi","u","o","ovi","ou"
  };
//vzor predseda


TVZOR soudce=
  {
  "c‡ƒj¤©¨Ÿ‘flmsx",
  "e‚i¡o¢u£–",
   1,
  "e","e","i","e","e","i","em"
  };
//vzor soudce


TVZOR soudce2=
  {
  "dtn",
  "ˆi¡",
   1,
  "e","e","i","e","e","i","em"
  };
//vzor soudce pro tvrdou koncovku s mekkou samohlaskou -di -ti -ni
//-de -te -ne.

//Nasledujici funkce vraci 1 pokud jmeno muze byt sklonovano vzorem vz
char test_vzor(TVZOR *vz,char *jmeno)
  {
  char *end;
  char testchar;

  end=strchr(jmeno,0)-2;
  testchar=end[0];
  if (vz->znak1[0]!='*' && strchr(vz->znak1,testchar)==NULL) return 0;
  testchar=end[1];
  if (vz->znak2[0]!='*' && strchr(vz->znak2,testchar)==NULL) return 0;
  return 1;
  }

//tato funkce se vola p©ed odejmut¡m ur‡it‚ho znaku.
//Pokud to toti‘ je zmˆk‡ovac¡ samohl ska, mus¡ se p©¡padn‚ d,t,n
//zmˆk‡it p©ed touto samohl skou.
void odejmi_znak(char *znak)
  {
  if (znak[0]=='ˆ' || znak[0]=='¡' || znak[0]=='i')
        switch (znak[-1])
           {
           case 'd': znak[-1]='ƒ';break;
           case 't': znak[-1]='Ÿ';break;
           case 'n': znak[-1]='¤';break;
           }
  }

//Tato funkce upravuje nektere pady jen maji predpredposledni samohlasku e
//Marek => Marka
//Pisen => Pisne
//Zdenek => Zdenka
void uprav_e_nakonci(char *konec)
  {
  char samohlasky[]="a e‚i¡o¢u£y˜";
  char pismena[]="flmn¤r©s¨xpv";
  char *c;

  c=konec-2;
  if (strchr(samohlasky,c[2])!=NULL && strchr(samohlasky,c[1])==NULL && strchr(pismena,c[-1])!=NULL)
     if (c[0] =='e'|| c[0]=='‚'|| c[0] =='ˆ')
        {
        odejmi_znak(c);
        strcpy(c,c+1);
        }
  }


//Naplni buffer spravnym padem jmena podle vzoru vz
//paduje se od 0 => 1. pad
void ziskej_pad(char *buffer,char *jmeno,TVZOR *vz,char pad)
  {
  char *end;
  strcpy(buffer,jmeno);
  if (vz->pady[pad][0]=='-') return;
  end=strchr(buffer,0)-vz->chrdel;
  odejmi_znak(end); //odejme znak, pokud je => znak 0 neni znak cesky.
  strcpy(end,vz->pady[pad]);
  if (pad && !vz->chrdel && end[-2]=='–') end[-2]='o';
  uprav_e_nakonci(end);
  return;
  }


//Tato funkce upravi nektere specialni dvojice znaku do spravne podoby
//prvni sloupec je puvodni dvojice, druhy sloupec je nova dvojice
void uprav_dvojice(char *jmeno)
  {
  static char *dvojice[]=
        {
        "ƒe","dˆ",
        "Ÿe","tˆ",
        "¤e","nˆ",
        "ƒi","di",
        "Ÿi","ti",
        "¤i","ni",
        "ƒ¡","d¡",
        "Ÿ¡","t¡",
        "¤¡","n¡",
        "rˆ","©e",
        "sˆ","¨e",
        "cˆ","‡e",
        "kˆ","ce",
        "¨ˆ","¨e",
        "‘ˆ","‘e",
        "‡ˆ","‡e",
        "©ˆ","©e",
        };

  while (*jmeno)
     {
     int i;
     for(i=0;i<sizeof(dvojice)/sizeof(char *);i+=2)
        {
        if (!strncmp(jmeno,dvojice[i],2))
           {
           strncpy(jmeno,dvojice[i+1],2);
           break;
           }
        }
     jmeno++;
     }
  }

//Pole padovych predlozek
char *jmena_padu[]=
  {
  "kdo",
  "bez",
  "k",
  "vid¡m",
  "vol m",
  "o",
  "s"
  };

//Tato funkce zobrazi vypadovane jmeno
void show_table(char *jmeno,TVZOR *vz,char tabnum)
  {
  int i;
  char *buff;

  buff=alloca(strlen(jmeno)+20);
  printf("%d. mo‘nost\n\n",tabnum);
  for(i=0;i<7;i++)
     {
     if (i)
        {
        ziskej_pad(buff,jmeno,vz,i);
        uprav_e_nakonci(buff);
        }
        else strcpy(buff,jmeno);
     uprav_dvojice(buff);
     printf("  %d. %-6s %s\n",i+1,jmena_padu[i],buff);
     }
  printf("**** Kl vesu ****\n");
  getche();
  }

//Tato funkce vypise celkovy vysledek.
void notabs(int i)
  {
  if (i) printf("Program na¨el %d mo‘most%s.\n",i,(i!=1?(i>1 && i<5?"i":"¡"):""));
  else printf("Program bohu‘el nena¨el ‘ dnou mo‘nost jak sklo¤ovat toto jm‚no.\n");
  puts("-------------------------------------------------------------------------");
  }

//Tato funkce zobrazi vsechny moznosti padovani pro rod zensky
void hledej_zena(char *jmeno)
  {
  int tabnum=0;

  if (test_vzor(&zena,jmeno)) show_table(jmeno,&zena,++tabnum);
  if (test_vzor(&natasa,jmeno)) show_table(jmeno,&natasa,++tabnum);
  if (test_vzor(&ruze,jmeno)) show_table(jmeno,&ruze,++tabnum);
  if (test_vzor(&ruze2,jmeno)) show_table(jmeno,&ruze2,++tabnum);
  if (test_vzor(&pisen,jmeno)) show_table(jmeno,&pisen,++tabnum);
  if (test_vzor(&kost,jmeno)) show_table(jmeno,&kost,++tabnum);
  notabs(tabnum);
  }

//Tato funkce zobrazi vsechny moznosti padovani pro rod muzsky
void hledej_muz(char *jmeno)
  {
  int tabnum=0;

  if (test_vzor(&pritel,jmeno)) show_table(jmeno,&pritel,++tabnum);
  if (test_vzor(&pan,jmeno)) show_table(jmeno,&pan,++tabnum);
  if (test_vzor(&pan2,jmeno)) show_table(jmeno,&pan2,++tabnum);
  if (test_vzor(&muz,jmeno)) show_table(jmeno,&muz,++tabnum);
  if (test_vzor(&quasimodo,jmeno)) show_table(jmeno,&quasimodo,++tabnum);
  if (test_vzor(&predseda,jmeno)) show_table(jmeno,&predseda,++tabnum);
  if (test_vzor(&soudce,jmeno)) show_table(jmeno,&soudce,++tabnum);
  if (test_vzor(&soudce2,jmeno)) show_table(jmeno,&soudce2,++tabnum);
  if (test_vzor(&fenix,jmeno)) show_table(jmeno,&fenix,++tabnum);
  notabs(tabnum);
  }

//Hlavni cast programu
void hlavni()
  {
  char jmeno[51];
  char pohlavi;
  do
  {
  printf("Zadej jm‚no. Vy‘aduje se min 3 znaky v ‡e¨tinˆ kodu kamenick˜ch \n");
  printf("Jm‚no nesm¡ m¡t v¡c ne‘ 50 znak–, a nesm¡ obsahovat mezery:\n");
  printf("Pi¨ mal˜mi p¡smeny, pouze prvn¡ pismeno m–‘e b˜t velk‚:\n");
  printf("(pouh‚ 'x' je odchod z programu)\n");
  jmeno_chyba:
  gets(jmeno);
  if (jmeno[0]=='x' && jmeno[1]==0) return;
  if (strlen(jmeno)<3)
     {
     printf("Jm‚no mus¡ b˜t min 3 znaky dlouh‚\n");
     goto jmeno_chyba;
     }
  chyba:
  printf("Jsi mu‘ nebo ‘ena? (M/Z nebo M/F nebo X):");
  pohlavi=getchar();
  while (getchar()!='\n');
  puts("");
  pohlavi=toupper(pohlavi);
  if (pohlavi=='X') return;
  if (pohlavi=='M') hledej_muz(jmeno);
  else if (pohlavi=='F' || pohlavi=='Z') hledej_zena(jmeno);
  else goto chyba;
  }
  while (1);
  }

main()
  {
  hlavni();
  puts("");
  puts("Pokud jsi objevil p©irozen‚ jm‚no (tj re ln‚ jm‚no), kter‚ program\n"
       "nedok zal vysklo¤ovat, po¨li mi jeho znˆn¡ na adresu:\n"
       "xnovako1@cs.felk.cvut.cz\n");
  puts("Verze Latin2 se p©ipravuje...\n"
       "O slovensk‚ verzi se zat¡m neuva‘uje...\n");
  puts("Napsal: Ond©ej Nov k za 2 a p–l hodiny ve WATCOM C\n"
       "Zdroj ky maj¡ povahu PUBLIC DOMAIN\n");
  }
