import morfeusz2

class MorphologyError(Exception):
    pass

morfeusz = morfeusz2.Morfeusz(generate=True, analyse=False, expand_tags=True)

LEMMA_KILL_LIST = {
    'oko:Sn_ncol', 'ucho:Sn_ncol',                         # ~a
    'łeb:Sm2', 'powód:Sm1',                        # ~owie
    'lew:Sm2~ewa',                                    # ~owi
    'paragraf:Sm1', 'sen:Sm2.m3', 'lot:Sm3~a~u', 'lód:Sm2', # ~a; para-graf
    'bat:Sm3~u', 'żywot:Sm3~u',                        # ~u
    # fikać kozły, spuszczać basałyki
    'kozioł:Sm1', 'basałyk:Sm1.m2',                   # ~ów
    # ciągnąć druta, fiknąć kozła/koziołka, puścić kura, spiąć muła, popuścić pasa, zapuścić żurawia
    'drut:Sm3~a~u', 'drut:Sm3~u', 'kozioł:Sm3', 'koziołek:Sm3', 'kur:Sm3', 'muł:Sm3', 'pas:Sm3~s~u', 'pas:Sn_ncol', 'żuraw:Sm3', # ~-
    # m1:
    'as:Sm1', 'baba:Sm1', 'biegun:Sm1', 'bzik:Sm1', 'fioł:Sm1', 'jeleń:Sm1', 'kułak:Sm1', 'lamus:Sm1', 'lis:Sm1.m2', 'nurek:Sm1', 'osioł:Sm1.m2', 'orzeł:Sm1',
    'szach:Sm1', 'admirał:Sm2', 'bęben:Sm2', 'głup:Sm2', 'kasztan:Sm2', 'król:Sm2', 'kurek:Sm2', 'młot:Sm2', 'pajac:Sm2', 'pion:Sm2.m3',
    # m2:
    'grabarz:Sm2',
    'płaz:Sm2', 'szatan:Sm2',
    'tchórz:Sm2',
    'Abraham:Sf', 'Grek:Sm1~kowie', 'Grek:Sf', 'Kajfasz:Sf', 'Marek:Sf', 'Polak:Sf', 'Polska:Sf~ej',
    'Wisła:Sm1', 'Zawisza:Sf',  # nazwiska (w tym żeńskie)
    'Marcin:Sm3',           # człon nazwy geogr.
    'galop:Sm2',            # chor.
    'profit:Sm2', 'profit:Sm3',          # pro-fit
    'jeż:Sm3', 'kaduk:Sm3', 'lek:Sm2', 'smok:Sm3', 'ślimak:Sm3', # m3
    'kapitan:Sf',          # f
    'dziób:Sm3~oba~obu',            # żegl.
    'mat:Sm1', 'mat:Sm3',    # mors., matowy
    'as:Sm2.m3', 'as:Sn_ncol',      # hist., muz.
    'przenosić:Vp',
    'kasztan:Sm3',
    'stać:Vp',             # perf
    'wpaść:Vp~sę',            # wpasie
    'należeć:Vp',          # perf (należał się w łóżku)
    'głąb:Sm2.m3', 'głąb:Sm1.m2',  # zostawiamy żeńską „w głąb”
    # z semantyki ==============================================================
    # członek w znaczeniu części ciała:
    'członek:Sm1', 'członek:Sm2',
    # antytalent:s2 jest m1, anty-talent:s2 – m2 (monet.), chcemy antytalent m3
    #'antytalent:Sm1',
    # nie chcemy m1
    'asfalt:Sm1',
    # nie chcemy m2 leśń.
    'aspirant:Sm3',
    # nie chcemy m1
    'bas:Sm1',
    'samolot:Sm3~a~u', #~a samo-lot
    'dopaść:Vp~sę', # dopasł
    'napaść:Vp~sę', # napasł
    'dostawać:Vi~wam', # dostawa
    'reżyser:Sm1', 'sędzia:Sm1', # chcemy f, precz z patriarchatem
    'operator:Sm1', # chcemy m3
    'Rzym:Sm1', 'Rzym:Sf', # nazwiska, chcemy m3
    'śpiewak:Sm2', #chcemy m1
    'model:Sm1', # chcemy m3
    'mikser:Sm1', # chcemy m3
    'sport:Sm2.m3', # chcemy m3
    'pilot:Sm2', 'pilot:Sm3', # chcemy m1
    'oblec:Vp~egnę~egę', # oblókł
    'wał:Sm1', 'wał:Sm2', # chcemy m3
    'odlew:Sm2~ewa', 'odlew:Sm2~lwa', # od-lew...
    'odpaść:Vp~sę', # odpadł
    'opaść:Vp~sę', # opadły
    'pasać:Vi~am~zę', # pasa
    #'pluskać', # ???
    'Księżyc:Sm1', 'Księżyc:Sf', # nazwiska, chcemy m3
    'podpaść:Vp~sę', # podpadł
    'popaść:Vp~sę', # popadł
    'pasza:Sm1', # chcemy f
    'ssak:Sm3', # chcemy m2
    'przypaść:Vp~sę', # przypadło
    'fotograf:Sm3', # chcemy m1; foto-graf
    'sygnalizator:Sm1', # chcemy m3
    'pająk:Sm3', # chcemy m2
    'wąż:Sm2.m3', # chcemy m2
    'tłumacz:Sm2', # chcemy m1
    'samiec:Sm1', # chcemy m2
    'automat:Sm2', 'automat:Sm1', # auto-mat
    'gad:Sm1', # chcemy m2
    'ruda:Sf~ej', # chcemy rudę (metalu), nie rudą
    'marsz:Sm3', # chcemy ~a
    'drapieżnik:Sm1', # chcemy m2
    'zbieg:Sm1', # chcemy m3 (zbieg okoliczności)
    'polityk:S', # poli-tyk...
}
FORM_KILL_LIST = (
    ('amen', 'amen:S', 'subst:sg:nom:n:ncol', ['nazwa_pospolita'], []),                       # m3
    ('amen', 'amen:S', 'subst:sg:acc:n:ncol', ['nazwa_pospolita'], []),
    ('Amora', 'Amor', 'subst:sg:gen:m2', ['imię'], ['mit.']),                                 # m1
    ('aniołków', 'aniołek', 'subst:pl:gen:m1', ['nazwa_pospolita'], []),                      # m2
    ('aniołów', 'anioł', 'subst:pl:gen:m2', ['nazwa_pospolita'], []),                         # m1
    ('awansy', 'awans', 'subst:pl:acc:m3', ['nazwa_pospolita'], []),                          # awanse
    ('baja', 'bajać', 'fin:sg:ter:imperf', [], []),                                           # baje
    ('bambusa', 'bambus:Sm2.m3', 'subst:sg:acc:m2', ['nazwa_pospolita'], []),                 # w bambus
    ('blues', 'blues', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                           # bluesa
    ('bogowi', 'bóg', 'subst:sg:dat:m1', ['nazwa_pospolita'], []),                            # bogu
    ('burak', 'burak:Sm2.m3', 'subst:sg:nom:m2', ['nazwa_pospolita'], ['bot.']),              # m3
    ('całuski', 'całusek', 'subst:pl:acc:m2', ['nazwa_pospolita'], []),                       # m3
    ('całusków', 'całusek', 'subst:pl:gen:m2', ['nazwa_pospolita'], []),                      # m3
    ('cepu', 'cep:Sm3', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                          # cepa
    ('chlaszcze', 'chlastać', 'fin:sg:ter:imperf', [], []),                                   # chlasta
    ('chleje', 'chlać', 'fin:sg:ter:imperf', [], ['pot.,rzad.']),                             # chla
    ('chluszcze', 'chlustać', 'fin:sg:ter:imperf', [], []),                                   # chlusta
    ('chujów', 'chuj:Sm1', 'subst:pl:acc:m1', ['nazwa_pospolita'], ['wulg.']),                # obciągać chuja
    ('cudy', 'cud', 'subst:pl:acc:m3', ['nazwa_pospolita'], []),                              # wyczyniać cuda
    ('czartem', 'czart', 'subst:sg:inst:m2', ['nazwa_pospolita'], []),                        # m1
    ('czole', 'czoło:Sn_ncol~ole', 'subst:sg:loc:n:ncol', ['nazwa_pospolita'], []),           # postawić na czele
    ('czort', 'czort', 'subst:sg:nom:m2', ['nazwa_pospolita'], ['pot.']),                     # m1
    ('diabeł', 'diabeł', 'subst:sg:nom:m2', ['nazwa_pospolita'], []),                         # m1
    ('diabła', 'diabeł', 'subst:sg:acc:m2', ['nazwa_pospolita'], []),                         # m1
    ('diabła', 'diabeł', 'subst:sg:gen:m2', ['nazwa_pospolita'], []),                         # m1
    ('diabłami', 'diabeł', 'subst:pl:inst:m2', ['nazwa_pospolita'], []),                      # m1
    ('diabłem', 'diabeł', 'subst:sg:inst:m2', ['nazwa_pospolita'], []),                       # m1
    ('diabłu', 'diabeł', 'subst:sg:dat:m2', ['nazwa_pospolita'], []),                         # m1
    ('diabłów', 'diabeł', 'subst:pl:acc:m1', ['nazwa_pospolita'], []),                        # w diabły
    ('diabłów', 'diabeł', 'subst:pl:gen:m2', ['nazwa_pospolita'], []),                        # m1
    ('diabły', 'diabeł', 'subst:pl:nom:m2', ['nazwa_pospolita'], []),                         # diabli wiedzą
    ('DNA', 'DNA', 'subst:sg:nom:m3', ['nazwa_pospolita'], []),                               # n
    ('DNA', 'DNA', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),
    ('drapak', 'drapak:Sm3', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                     # dać drapaka
    ('dwu', 'dwa', 'num:pl:loc:f:congr:ncol', [], []),                                        # dwóch
    ('dwu', 'dwa', 'num:pl:acc:m1:rec:ncol', [], []),
    ('dwu', 'dwa', 'num:pl:loc:m1:rec:ncol', [], []),
    ('dwu', 'dwa', 'num:pl:inst:m3:congr:ncol', [], []),
    ('dwu', 'dwa', 'num:pl:loc:m3:congr:ncol', [], []),
    ('dwu', 'dwa', 'num:pl:loc:n:congr:ncol', [], []),
    ('dygocą', 'dygotać', 'fin:pl:ter:imperf', [], []),                                       # dygoczą
    ('dzióba', 'dziób:Sm3~oba~óba', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),              # dzioba
    ('dzióbach', 'dziób:Sm3~oba~óba', 'subst:pl:loc:m3', ['nazwa_pospolita'], []),
    ('dzióbem', 'dziób:Sm3~oba~óba', 'subst:sg:inst:m3', ['nazwa_pospolita'], []),
    ('dzióby', 'dziób:Sm3~oba~óba', 'subst:pl:acc:m3', ['nazwa_pospolita'], []),
    ('figiel', 'figiel', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                         # figla
    ('garba', 'garb', 'subst:sg:acc:m2', ['nazwa_pospolita'], []),                            # wziąć sobie garb na plecy
    ('gąsiora', 'gąsior:Sm2', 'subst:sg:acc:m2', ['nazwa_pospolita'], []),                    # osuszać gąsior
    #('głąba', 'głąb:Sm2.m3', 'subst:sg:acc:m2', ['nazwa_pospolita'], []),                    # uciec w głąb
    ('gore', 'gorzeć', 'fin:sg:ter:imperf', [], ['przest.,podniosłe']),                       # gorzeje
    ('gorze', 'gorzeć', 'fin:sg:ter:imperf', [], ['przest.,podniosłe']),
    ('gorą', 'gorzeć', 'fin:pl:ter:imperf', [], ['przest.,podniosłe']),                       # gorzeją
    ('gorzą', 'gorzeć', 'fin:pl:ter:imperf', [], ['przest.,podniosłe']),
    ('grzęzie', 'grzęznąć', 'fin:sg:ter:imperf', [], []),                                     # grzęźnie
    ('grzybki', 'grzybek', 'subst:pl:acc:m2', ['nazwa_pospolita'], []),                       # m3
    ('grzyb', 'grzyb:Sm2.m3', 'subst:sg:nom:m2', ['nazwa_pospolita'], ['mikol.']),            # m3
    ('grzyb', 'grzyb:Sm2.m3', 'subst:sg:acc:m3', ['nazwa_pospolita'], ['mikol.']),            # grzyba
    ('grzyby', 'grzyb:Sm2.m3', 'subst:pl:nom:m2', ['nazwa_pospolita'], ['mikol.']),           # m3
    ('guz', 'guz', 'subst:sg:nom:m2', ['nazwa_pospolita'], []),                               # m3
    ('guz', 'guz', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                               # ale: guza
    ('guza', 'guz', 'subst:sg:gen:m2', ['nazwa_pospolita'], []),                              # m3
    ('kaduk', 'kaduk:Sm1.m2', 'subst:sg:nom:m2', ['nazwa_pospolita'], ['przest.']),           # m1
    ('kołata', 'kołatać', 'fin:sg:ter:imperf', [], []),                                       # kołacze (kołace usunie filter_ending)
    ('kopniak', 'kopniak', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                       # kopniaka
    ('kloc', 'kloc:Sm3', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                         # walnąć kloca
    ('klientowi', 'klient:Sm2', 'subst:sg:dat:m2', ['nazwa_pospolita'], []),                  # m1
    ('klin', 'klin:Sm3', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                         # klina
    ('klina', 'klin:Sm2', 'subst:sg:gen:m2', ['nazwa_pospolita'], []),                        # m3
    ('klinem', 'klin:Sm2', 'subst:sg:inst:m2', ['nazwa_pospolita'], []),                      # m3
    ('kilku', 'kilka:N', 'num:pl:inst:m3:congr:ncol', [], []),                                # kilkoma
    ('kopniakiem', 'kopniak', 'subst:sg:inst:m2', ['nazwa_pospolita'], []),                   # m3
    ('kosz', 'kosz:Sm3', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                         # kosza
    ('kosza', 'kosz:Sm3', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                        # TODO do usunięcia po poprawce?
    ('koszu', 'kosz:Sm2', 'subst:sg:loc:m2', ['nazwa_pospolita'], []),                        # m3
    ('koszty', 'koszt', 'subst:pl:acc:m3', ['nazwa_pospolita'], []),                          # koszta
    ('krzaku', 'krzak', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                          # krzaka
    ('krzyw', 'krzywy', 'adj:sg:nom:m1:pos', [], []),                                         # krzywy
    ('kserze', 'ksero', 'subst:sg:loc:n:ncol', ['nazwa_pospolita'], []),                      # na ksero
    ('łga', 'łgać', 'fin:sg:ter:imperf', [], ['przest.,rzad.']),                              # łże
    ('marsz', 'marsz:Sm2.m3', 'subst:sg:acc:m3', ['nazwa_pospolita'], ['muz.']),              # grać marsza
    ('marźnie', 'marznąć', 'fin:sg:ter:imperf', [], []),                                      # marznie
    ('napoi', 'napój', 'subst:pl:gen:m3', ['nazwa_pospolita'], []),                           # napojów
    ('nasiąknął', 'nasiąknąć', 'praet:sg:m1:perf', [], []),                                   # nasiąkł
    ('nasiąknął', 'nasiąknąć', 'praet:sg:m3:perf', [], []),
    ('nieciekaw', 'nieciekawy', 'adj:sg:nom:m1:pos', [], []),                                 # nieciekawy
    #('nasiąknęła', 'nasiąknąć', 'praet:sg:f:perf', [], []),
    ('nic', 'nic', 'subst:sg:gen:n:ncol', [], []),                                            # niczego
    ('oboruje', 'oborywać', 'fin:sg:ter:imperf', [], []),                                     # oborywa
    ('obydwóch', 'obydwa', 'num:pl:loc:f:congr:ncol', [], []),                                # obydwu
    ('obydwóch', 'obydwa', 'num:pl:loc:m3:congr:ncol', [], []),
    ('obydwóch', 'obydwa', 'num:pl:loc:n:congr:ncol', [], []),
    ('odtchu', 'oddech', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                         # od-tchu ;)
    ('oczyma', 'oko:Sn_col', 'subst:pl:inst:n:col', ['nazwa_pospolita'], ['anat.']),          # oczami
    ('oczów', 'oko:Sn_col', 'subst:pl:gen:n:col', ['nazwa_pospolita'], ['anat.']),            # oczu
    ('ofiarowywa', 'ofiarowywać', 'fin:sg:ter:imperf', [], ['rzad.']),                        # ofiarowuje
    #('oklapnęła', 'oklapnąć', 'praet:sg:f:perf', [], []),                                    # oklapła
    ('oklapnął', 'oklapnąć', 'praet:sg:m3:perf', [], []),
    ('oklapnęło', 'oklapnąć', 'praet:sg:n:perf', [], []),
    ('otworzoną', 'otworzyć', 'ppas:sg:inst:f:perf:aff', [], []),                             # otwartą
    ('otworzony', 'otworzyć', 'ppas:sg:nom:m1:perf:aff', [], []),                             # otwarty
    ('paple', 'paplać', 'fin:sg:ter:imperf', [], ['pot.']),                                   # papla
    ('paru', 'parę', 'num:pl:inst:m3:congr', [], []),                                         # paroma
    ('pasjanse', 'pasjans', 'subst:pl:acc:m2', ['nazwa_pospolita'], []),                      # pasjanse m3
    ('pasjansy', 'pasjans', 'subst:pl:acc:m2', ['nazwa_pospolita'], []),
    ('pasjansy', 'pasjans', 'subst:pl:acc:m3', ['nazwa_pospolita'], []),
    ('pełen', 'pełny', 'adj:sg:nom:m1:pos', [], []),                                          # pełny
    ('pełźnie', 'pełznąć', 'fin:sg:ter:imperf', [], []),                                      # pełznie
    ('pewien', 'pewny', 'adj:sg:nom:m1:pos', [], []),                                         # pewny
    ('pewien', 'pewny', 'adj:sg:acc:m3:pos', [], []),
    #('pierzchnęła', 'pierzchnąć:Vp', 'praet:sg:f:perf', [], []),                              # pierzchła
    ('podobien', 'podobny', 'adj:sg:nom:m1:pos', [], []),                                     # podobny
    ('policzeki', 'policzek', 'subst:pl:nom:m3', ['nazwa_pospolita'], []),                    # poli-czeki ;)
    ('procha', 'proch', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                          # prochu
    ('proga', 'próg', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                            # progu
    ('programa', 'program', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                      # pro-gram ;)
    ('prysznicu', 'prysznic', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                    # prysznica
    ('przedzie', 'przód', 'subst:sg:loc:m3', ['nazwa_pospolita'], []),                        # na przodzie
    ('przekonywa', 'przekonywać', 'fin:sg:ter:imperf', [], []),                               # przekonuje
    ('przemyśliwuje', 'przemyśliwać', 'fin:sg:ter:imperf', [], []),                           # przemyśliwa
    ('przykląkł', 'przyklęknąć', 'praet:sg:m1:perf', [], []),                                 # przyklęknął
    ('rażony', 'razić', 'ppas:sg:nom:m1:imperf:aff', [], []),                                 # perf (jak rażony piorunem)
    ('rażonego', 'razić', 'ppas:sg:acc:m1:imperf:aff', [], []),
    ('ręku', 'ręka', 'subst:sg:loc:m3', ['nazwa_pospolita'], ['anat.']),                      # ręce
    ('rękoma', 'ręka', 'subst:pl:inst:f', ['nazwa_pospolita'], ['anat.']),                    # rękami
    ('rówien', 'równy', 'adj:sg:nom:m1:pos', [], []),                                         # równy
    ('rynsztoku', 'rynsztok', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                    # rynsztoka
    ('rzeknąć', 'rzec:Vp', 'inf:perf', [], []),                                               # rzec
    ('rządu', 'rząd:Sm3~ądu', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                    # rosnąć do rzędu czegoś
    ('rzędów', 'rząd:Sm3~ędu', 'subst:pl:gen:m3', ['nazwa_pospolita'], []),                   # objąć ster rządów
    ('rzędy', 'rząd:Sm3~ędu', 'subst:pl:acc:m3', ['nazwa_pospolita'], []),                    # objąć rządy
    ('sierpa', 'sierp', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                          # sierpu
    ('skomli', 'skomleć', 'fin:sg:ter:imperf', [], []),                                       # skomle
    ('sondażów', 'sondaż', 'subst:pl:gen:m3', ['nazwa_pospolita'], []),                       # sondaży
    ('steka', 'stek:Sm2.m3', 'subst:sg:acc:m2', ['nazwa_pospolita'], []),                     # wysmażyć stek
    ('strach', 'strach:Sm2', 'subst:sg:nom:m2', ['nazwa_pospolita'], []),                     # m3 (strach obleciał)
    ('stracha', 'strach:Sm2', 'subst:sg:gen:m2', ['nazwa_pospolita'], []),                    # napędzić stracha/strachu, ale umrzeć ze strachu
    ('strachu', 'strach:Sm2', 'subst:sg:loc:m2', ['nazwa_pospolita'], []),                    # m3
    ('syfon', 'syfon:Sm3', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                       # dać syfona
    ('szampan', 'szampan', 'subst:sg:nom:m2', ['nazwa_pospolita'], []),                       # m3
    ('szampana', 'szampan', 'subst:sg:gen:m2', ['nazwa_pospolita'], []),
    ('szatan', 'szatan:Sm1.m2', 'subst:sg:nom:m2', ['nazwa_pospolita'], []),                  # m1
    ('szatanem', 'szatan:Sm1.m2', 'subst:sg:inst:m2', ['nazwa_pospolita'], []),               # m1
    ('szczy', 'szczać', 'fin:sg:ter:imperf', [], ['pot.']),                                   # szcza
    ('szeląga', 'szeląg', 'subst:sg:gen:m2', ['nazwa_pospolita'], []),                        # m3
    ('szmerglu', 'szmergiel', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                    # szmergla
    ('śmiecie', 'śmieć:Sm2.m3', 'subst:pl:acc:m3', ['nazwa_pospolita'], []),                      # śmieci
    ('ukląkł', 'uklęknąć', 'praet:sg:m1:perf', [], []),                                       # uklęknął
    ('usty', 'usta', 'subst:pl:inst:n:pt', ['nazwa_pospolita'], ['przest.']),                 # ustami
    ('walkowera', 'walkower', 'subst:sg:acc:m2', ['nazwa_pospolita'], []),                    # m3
    ('woła', 'wół', 'subst:sg:acc:m2', ['nazwa_pospolita'], []),                              # wołu
    ('woru', 'wór', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                              # wora
    ('wykonywa', 'wykonywać', 'fin:sg:ter:imperf', [], []),                                   # wykonuje
    ('ziaja', 'ziajać', 'fin:sg:ter:imperf', [], []),                                         # ziaje
    ('zeprzała', 'zeprzeć:Vp~zeję', 'praet:sg:f:perf', [], ['rzad.']),                        # sparła
    ('zeprzał', 'zeprzeć:Vp~zeję', 'praet:sg:m1:perf', [], ['rzad.']),
    ('zeprzało', 'zeprzeć:Vp~zeję', 'praet:sg:n:perf', [], ['rzad.']),
    ('zjednywa', 'zjednywać', 'fin:sg:ter:imperf', [], []),                                   # zjednuje
    ('zwierzę', 'zwierzę', 'subst:sg:nom:n:ncol', ['nazwa_pospolita'], []),                   # col
    ('zwierzę', 'zwierzę', 'subst:sg:acc:n:ncol', ['nazwa_pospolita'], []),
    ('zwierzęcia', 'zwierzę', 'subst:sg:gen:n:ncol', ['nazwa_pospolita'], []),
    ('zwierzęciem', 'zwierzę', 'subst:sg:inst:n:ncol', ['nazwa_pospolita'], []),
    ('zwierzęciu', 'zwierzę', 'subst:sg:dat:n:ncol', ['nazwa_pospolita'], []),
    ('zwierzęciu', 'zwierzę', 'subst:sg:loc:n:ncol', ['nazwa_pospolita'], []),
    ('zwierzęta', 'zwierzę', 'subst:pl:nom:n:ncol', ['nazwa_pospolita'], []),
    ('zżarła', 'zeżreć', 'praet:sg:f:perf', [], []),                                          # zeżarła
    ('zżarł', 'zeżreć', 'praet:sg:m1:perf', [], []),
    ('zżarł', 'zeżreć', 'praet:sg:m3:perf', [], []),
    ('żłobu', 'żłób:Sm3', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                        # dopchać się do żłoba
    ('żurnalów', 'żurnal', 'subst:pl:gen:m3', ['nazwa_pospolita'], []),                       # żurnali
    ('żywcem', 'żywiec:Sm2', 'subst:sg:inst:m2', ['nazwa_pospolita'], []),                    # m3
    ('swe', 'swój', 'adj:sg:acc:n:pos', [], []),                                # dostać za swoje
    ('swym', 'swój', 'adj:sg:loc:n:pos', [], []),                               # obstawać przy swoim
    ('swojego', 'swój', 'adj:sg:gen:n:pos', [], []),                            # dopiąć swego
    ('swe', 'swój', 'adj:pl:acc:f:pos', [], []),                                # swoje in adjp(agr)
    ('swe', 'swój', 'adj:pl:acc:m3:pos', [], []),
    ('swe', 'swój', 'adj:sg:nom:n:pos', [], []),
    ('swe', 'swój', 'adj:pl:acc:n:pos', [], []),
    ('swej', 'swój', 'adj:sg:gen:f:pos', [], []),                               # swojej
    ('swej', 'swój', 'adj:sg:loc:f:pos', [], []),
    ('swego', 'swój', 'adj:sg:acc:m1:pos', [], []),                             # swojego
    ('swego', 'swój', 'adj:sg:gen:m3:pos', [], []),
    ('swych', 'swój', 'adj:pl:gen:f:pos', [], []),                              # swoich
    ('swych', 'swój', 'adj:pl:loc:f:pos', [], []),
    ('swych', 'swój', 'adj:pl:gen:m3:pos', [], []),
    ('swych', 'swój', 'adj:pl:loc:m3:pos', [], []),
    ('swych', 'swój', 'adj:pl:loc:n:pos', [], []),
    ('swym', 'swój', 'adj:pl:dat:m3:pos', [], []),
    ('swym', 'swój', 'adj:sg:loc:m3:pos', [], []),                              # swoim
    ('swym', 'swój', 'adj:sg:inst:m3:pos', [], []),
    ('swym', 'swój', 'adj:pl:dat:n:pos', [], []),
    ('swym', 'swój', 'adj:sg:inst:n:pos', [], []),
    ('swymi', 'swój', 'adj:pl:inst:f:pos', [], []),                             # swoimi
    ('swymi', 'swój', 'adj:pl:inst:m3:pos', [], []),
    ('swymi', 'swój', 'adj:pl:inst:n:pos', [], []),
    ('swą', 'swój', 'adj:sg:acc:f:pos', [], []),                                # swoją
    ('swą', 'swój', 'adj:sg:inst:f:pos', [], []),
    ('mej', 'mój:A', 'adj:sg:gen:f:pos', [], []),                               # mojej
    ('mej', 'mój:A', 'adj:sg:dat:f:pos', [], []),
    ('mej', 'mój:A', 'adj:sg:loc:f:pos', [], []),
    ('memu', 'mój:A', 'adj:sg:dat:m3:pos', [], []),                             # mojemu
    ('mego', 'mój:A', 'adj:sg:acc:m2:pos', [], []),                             # mojego
    ('mego', 'mój:A', 'adj:sg:gen:m3:pos', [], []),
    ('mego', 'mój:A', 'adj:sg:gen:n:pos', [], []),
    ('mych', 'mój:A', 'adj:pl:loc:n:pos', [], []),                              # moich
    ('me', 'mój:A', 'adj:pl:nom:f:pos', [], []),
    ('me', 'mój:A', 'adj:pl:acc:f:pos', [], []),                                # moje
    ('me', 'mój:A', 'adj:pl:acc:m2:pos', [], []),
    ('me', 'mój:A', 'adj:pl:nom:m3:pos', [], []),
    ('me', 'mój:A', 'adj:pl:acc:m3:pos', [], []),
    ('me', 'mój:A', 'adj:sg:nom:n:pos', [], []),
    ('me', 'mój:A', 'adj:pl:nom:n:pos', [], []),
    ('me', 'mój:A', 'adj:sg:acc:n:pos', [], []),
    ('me', 'mój:A', 'adj:pl:acc:n:pos', [], []),
    ('ma', 'mój:A', 'adj:sg:nom:f:pos', [], []),                                # moja
    ('mą', 'mój:A', 'adj:sg:acc:f:pos', [], []),                                # moją
    ('mą', 'mój:A', 'adj:sg:inst:f:pos', [], []),
    ('mym', 'mój:A', 'adj:sg:loc:m3:pos', [], []),                              # moim
    ('mym', 'mój:A', 'adj:sg:inst:m3:pos', [], []),
    ('mym', 'mój:A', 'adj:pl:dat:n:pos', [], []),
    ('mym', 'mój:A', 'adj:sg:loc:n:pos', [], []),
    ('mym', 'mój:A', 'adj:sg:inst:n:pos', [], []),
    ('mymi', 'mój:A', 'adj:pl:inst:f:pos', [], []),                             # moimi
    ('mymi', 'mój:A', 'adj:pl:inst:m3:pos', [], []),
    ('mymi', 'mój:A', 'adj:pl:inst:n:pos', [], []),
    ('mych', 'mój:A', 'adj:pl:gen:f:pos', [], []),                              # moich
    ('mych', 'mój:A', 'adj:pl:loc:f:pos', [], []),
    ('mych', 'mój:A', 'adj:pl:gen:m3:pos', [], []),
    ('mych', 'mój:A', 'adj:pl:loc:m3:pos', [], []),
    ('mych', 'mój:A', 'adj:pl:gen:n:pos', [], []),
    ('twej', 'twój:A', 'adj:sg:gen:f:pos', [], []),                             # twojej
    ('twej', 'twój:A', 'adj:sg:loc:f:pos', [], []),
    ('twych', 'twój:A', 'adj:pl:gen:f:pos', [], []),                            # twoich
    ('twych', 'twój:A', 'adj:pl:loc:m3:pos', [], []),
    ('twych', 'twój:A', 'adj:pl:loc:n:pos', [], []),
    ('twą', 'twój:A', 'adj:sg:acc:f:pos', [], []),                              # twoją
    ('twą', 'twój:A', 'adj:sg:inst:f:pos', [], []),
    ('twe', 'twój:A', 'adj:pl:acc:m3:pos', [], []),                             # twoje
    ('twym', 'twój:A', 'adj:sg:loc:m3:pos', [], []),                            # twoim
    ('twym', 'twój:A', 'adj:sg:inst:m3:pos', [], []),
    ('twych', 'twój:A', 'adj:pl:loc:f:pos', [], []),                            # twoich
    ('wkląsł', 'wklęsnąć', 'praet:sg:m3:perf', [], []),                         # wklęsł
    ('wsze', 'wszystek', 'adj:pl:nom:f:pos', [], []),                           # wszystkie
    ('wsze', 'wszystek', 'adj:pl:acc:f:pos', [], []),
    ('wsze', 'wszystek', 'adj:pl:nom:m3:pos', [], []),
    ('wsze', 'wszystek', 'adj:pl:acc:m3:pos', [], []),
    ('wsze', 'wszystek', 'adj:pl:acc:n:pos', [], []),
    ('wszech', 'wszystek', 'adj:pl:gen:m1:pos', [], []),                        # wszystkich
    ('wszech', 'wszystek', 'adj:pl:loc:m3:pos', [], []),
    ('wszemi', 'wszystek', 'adj:pl:inst:m3:pos', [], []),                       # wszystkimi
    ('ziemniak', 'ziemniak', 'subst:sg:nom:m2', ['nazwa_pospolita'], []),       # m3
    ('zwierząt', 'zwierzę', 'subst:pl:gen:n:ncol', ['nazwa_pospolita'], []),    # col
)

KWAL_KILL_LIST = {'niepopr.', 'niezal.', 'pot.', 'slang', 'rzad.', 'daw.', 'przest.', 'podniosłe', 'gwar.', 'pogard.', 'char.', 'po_liczebniku', 'monet.', 'muz.',}

# don’t put posp/kwal in the key (lists are unhashable)
FORM_MAP = {
    ('gwintu', 'gwint', 'subst:sg:gen:m3') : ('gwinta', 'gwint', 'subst:sg:gen:m3', [], []), # nie ma w Morfeuszu (pić z gwinta)
}

OVERRIDE = {
    'hopel' : ('hopla', 'subst:sg:acc:m2'),
    'łupień' : ('łupnia', 'subst:sg:acc:m2'),
    # kropka nad „i”
    'i' :  ('„i”', 'subst:sg:inst:n'),
    'zamian' : ('zamian', 'subst:sg:acc:m3'),
    # chcemy tylko pred
    'słychać' : ('słychać', 'pred'),
}   

def filter_kwal(forms):
    return list(filter(lambda f: not any(KWAL_KILL_LIST.intersection(k.split(',')) for k in f[4]), forms))

def filter_ending(forms):
    if len(forms) != 2:
        return forms
    f1, f2 = sorted(forms)
    if set(f[2] for f in forms) == {'fin:sg:ter:imperf'}:
        if f1[0].endswith('ce') and f2[0].endswith('cze'):
            # drepce, drepcze -> drepcze
            return [f2]
        if f1[0].endswith('cze') and f2[0].endswith('ta'):
            # bełcze, bełta -> bełta
            return [f2]
        if f1[0].endswith('ra') and f2[0].endswith('rze'):
            # gdera, gderze -> gdera
            return [f1]
        if f1[0].endswith('cze') and f2[0].endswith('ka'):
            # gdacze, gdaka -> gdacze
            return [f1]
        if f1[0].endswith('ka') and f2[0].endswith('cze'):
            # klaska, klaszcze -> klaszcze
            return [f2]
    if set(f[2].split(':')[0] for f in forms) == {'praet'}:
        if 'lekł' in f1[0] and 'lokł' in f2[0]:
            # dowlekła, dowlokła -> dowlekła
            return [f1]
        if 'lekł' in f1[0] and 'lókł' in f2[0]:
            # dowlekł, dowlókł -> dowlekł
            return [f1]
        if 'nęł' in f1[0] and 'ł' in f2[0]:
            # oklapła, oklapnęła -> oklapła
            return [f2]
        if 'nął' in f1[0] and 'ł' in f2[0]:
            # oklapł, oklapnął -> oklapł
            return [f2]
    return forms

def filter_by_feature(feature, forms):
    if feature:
        return list(filter(lambda f: feature in f[2], forms))
    else:
        return forms

def select_form(lemma, feats):
    if lemma == 'poprzysiąc':
        lemma = 'poprzysięgnąć'
    if lemma == 'sprząc':
        lemma = 'sprzęgnąć'
    if lemma == 'zaprząc':
        lemma = 'zaprzęgnąć'
    if lemma in OVERRIDE:
        return OVERRIDE[lemma]
    if lemma == 'odmaterializować':
        assert('praet' in feats and 'sg' in feats)
        if 'm1' in feats:
            return ('odmaterializował', 'praet:sg:m1:perf')
        if 'n' in feats:
            return ('odmaterializowało', 'praet:sg:n:perf')
    # forms: list of tuples in format: ('herb', 'herb', 'subst:sg:nom.acc:m3', ['nazwa_pospolita'], [])
    # split the tags for filtering
    forms = [FORM_MAP.get(tuple(f[:3]), f) for f in morfeusz.generate(lemma)]
    forms = [(orth, base, tag.split(':'), posp, kwal) for orth, base, tag, posp, kwal in forms]
    for feat in feats:
        # single feature: just filter
        if type(feat) == str:
            forms = filter_by_feature(feat, forms)
        # priority list of features: filter by first that yields non-empty result
        else:
            forms2 = []
            for ft in feat:
                forms2 = filter_by_feature(ft, forms)
                if forms2:
                    break
            forms = forms2
    # join the tags back
    forms = [(orth, base, ':'.join(tag), posp, kwal) for orth, base, tag, posp, kwal in forms]
    selected_forms = list(filter(lambda f: f[1] not in LEMMA_KILL_LIST and f not in FORM_KILL_LIST, forms))
    if len(selected_forms) > 1:
        filtered_forms = filter_kwal(selected_forms)
        if filtered_forms:
            selected_forms = filtered_forms
    if len(selected_forms) > 1:
        filtered_forms = filter_ending(selected_forms)
        if filtered_forms:
            selected_forms = filtered_forms
    selected_orth_tags = set((f[0], f[2]) for f in selected_forms)
    if len(selected_orth_tags) != 1:
        #print('----------', lemma, feats)
        raise MorphologyError(str(selected_forms))
    return selected_orth_tags.pop()