import logging

import morfeusz2

from entries.phrase_descriptions.descriptions import make_phraseologisms

from importer.Phrase import Case, Preposition, Modification, Words, NP, LexNP, PrepNP, LexPrepNP, AdjP, LexAdjP, PActP, LexPActP, Compar, LexCompar, Fixed
from importer.Position import Position
from importer.Global import get_current_entry

class RealisationDescriptionError(Exception):
    pass

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

SYNSET_KILL_LIST = (
    5564, # forma skupienia substancji-1 (miksować na masę/pianę/sok/.../formę skupienia substancji
    24299, # kopytny-1 kopytowiec-1 (w: potratować)
    87011, # wyrywanie-1 (w: wyplenić, upierdliwe gerundium, bierzemy herbicyd-1 środek chwastobójczy-1)
    102594, # GERUNDIUM-1
)

UNIT_KILL_LIST = (
    ('członek', '3'),                                     # część ciała-1
    ('pani', '2'),                                        # kobieta-1
    ('pan', '2'),                                         # mężczyzna-1
    ('rodzaj', '1'), ('twarz', '3'),                      # wersja-1
    ('rzeczownik własny', '1'),                           # nazwa własna-1
    ('środek lokomocji', '1',),                           # środek transportu-1
    ('ojciec', '3',),                                     # autor-1, twórca-1
    ('dyscyplina sportu', '1'),                           # dyscyplina sportowa-1
    ('siedzenie', '7'),                                   # pupa-1 itd.
    ('jednostka odległości', '1'),                        # jednostka długości
    ('przyrząd sportowy', '1'),                           # sprzęt sportowy
    ('środek spożywczy', '1'),                            # produkt spożywczy
    ('płód', '3'),                                        # wytwór umysłu-1
    ('działanie prawne', '1'),                            # czynność prawna
    ('CO2', '1'), ('ditlenek węgla', '1'),                # dwutlenek węgla-1
    ('forma fizyczna', '1'), ('sprawność fizyczna', '1'), # kondycja fizyczna
    ('surowiec energetyczny', '1'),                       # paliwo kopalne
    ('C', '6'), ('°C', '1'), ('celsjusz', '1'),           # stopień Celsjusza
    ('akt', '4'),                                         # ceremoniał-1, obrządek-1, ...
    ('uniemożliwianie', '1'),                             # udaremnianie-1
    ('zły czyn', '1'),                                    # zły uczynek
    ('dzieło literackie', '1'),                           # utwór literacki
    ('profesor nadzwyczajny', '1'),                       # profesor zwyczajny
    ('nauka', '1'), ('dziedzina wiedzy', '1'),            # dyscyplina naukowa
    ('ciąg wydarzeń', '1'),                               # ciąg zdarzeń
    ('zaburzenie', '1'), ('naruszenie', '2'),
    ('przekroczenie', '3'), ('złamanie', '2'),            # uchybienie-1 wykroczenie-1  
    ('agent gospodarczy', '1'),
    ('jednostka gospodarcza', '1'),                       # podmiot gospodarczy
    ('obróbka termiczna', '1'),                           # obróbka cieplna
    ('praca', '6'),                                       # dzieło-2
    ('pojazd kolejowy', '1'),                             # pojazd szynowy-1
    ('aromaty', '1'),                                     # wonności-1
    ('pojazd kosmiczny', '1'),                            # statek kosmiczny-1
    ('splot wydarzeń', '1'),                              # zbieg okoliczności
    ('raz', '2'),                                         # cios-1, uderzenie-10
    ('zainteresowanie', '2'), ('inklinacja', '2'),        # przychylność-2 sympatia-1
)

SYNSET2LEMMA = {
    #człowiek-1, istota ludzka-1, jednostka-2, osoba-1
    6047 : 'LUDZIE',
    # TODO? heurystyka: wszystkie lu > 2(3?) słów -> przejdź do hiponimu/hiperonimu?
    # człowiek ze względu na pełnioną funkcję-1
    6822 : 'LUDZIE',
    # człowiek ze względu na swoje zajęcie-1
    6797 : 'LUDZIE',
    # człowiek ze względu na relacje społeczne-1
    6775 : 'LUDZIE',
    # człowiek o określonej narodowości, przynależności państwowej-1
    20542 : 'LUDZIE',
    # człowiek charakteryzowany ze względu na kwalifikacje-1
    6779 : 'LUDZIE',
    # człowiek, który coś robi-1
    241977 : 'LUDZIE',
    # miejsce ze względu na przeznaczenie-1
    25121 : 'MIEJSCE',
    # miejsce wyróżniające się z całości obiektu-1
    105470 : 'MIEJSCE',
    # rzecz oceniana negatywnie-1
    26983 : 'ALL',
    # rzecz oceniana pozytywnie-1
    31937 : 'ALL',
    # własność komunikatu, wypowiedzi-1
    39190 : 'ALL',
    # zbiór obiektów - kolekcja elementów-1
    103163 : 'ALL',
    # doświadczenie negatywnego uczucia-1
    97278 : 'ALL',
    # GERUNDIUM OD CZASOWNIKA DYNAMICZNEGO (AKCJA)-1
    102592 : 'ALL',
}

SYNSET_MAP = {
    # przeważnie sensowniejsze są hiponimy
    # człowiek płci żeńskiej-1 -> kobieta-1
    225273 : 129,
    # człowiek, który wykonuje czynności religijne-1 -> kapłan-1
    239405 : 683,
    # człowiek płci męskiej-1 -> mężczyzna-1
    225272 : 6709,
    # pracownik służby zdrowia-1 -> doktor-1 lek.-1 lekarz-1
    6379 : 597,
    # człowiek ukarany-1 -> skazaniec-1 skazany-1
    41644 : 7909,
    # placówka służby zdrowia-1 -> lecznica-2 przychodnia-1
    4821 : 8858,
    # pojazd nawodny lub podwodny-1 -> statek-1
    225184 : 7354,
    # pojazd o przeznaczeniu wojskowym-1 -> pojazd wojskowy-1
    227639 : 225095,
    # narzędzie do łowienia-1 -> wędka-1>
    42387 : 14273,
    # urządzenie wspomagające proces liczenia-1 -> liczydło-1
    237614 : 17750,
    # zdarzenie oceniane negatywnie-1 -> cios-2 dramat-3 nieszczęście-1 tragedia-1 zguba-1
    27419 : 1911,
    # czynność o charakterze sakralnym-1 -> akt-4 ceremoniał-1 obrządek-1 obrzęd-1 ryt-2 rytuał-1
    105440 : 6566,
    # zrobienie czegoś niezgodnego z prawem lub z normami społecznymi-1 -> naruszenie-2 przekroczenie-3 uchybienie-1 wykroczenie-1 zaburzenie-1 złamanie-2
    99630 : 99214,
    # instrument dęty blaszany-1 -> róg-5 waltornia-1
    233727 : 25206,
    # jednostka miary kąta-1 -> deg-1 stopień-6 °-1
    41774 : 41779,
    # czynność o charakterze fizjologicznym-1 -> czynność-1
    # (tutaj hiponimy się nie nadają: respiracja-1, plozja-1>
    105442 : 10765,
    # zamachowiec-samobójca-1 -> zamachowiec-1
    80502 : 18234,
    # gracz w karty-1 -> gracz-1>
    59620 : 969,
    # sztuczne źródło światła-1 -> światło-10 źródło światła-1>
    227275 : 5519,
    # czytnik kodu paskowego-1 skaner do kodów kreskowych-1 -> czytnik-1
    237869 : 13600,
    # środek transportu publicznego-1 -> środek lokomocji-1 środek transportu-1
    228654 : 8674,
    # sposób poruszania się-1 -> sposób-1>
    238882 : 8194,
    # właściwość zdarzenia, sytuacji-1 -> atrybut-1 cecha-1 przymiot-1 własność-2 właściwość-1
    5479 : 323,
    # cecha żywego organizmu-1 -> cecha-1
    36346 : 323,
    # echa uwarunkowana kulturowo-1 -> cecha-1
    249629 : 323,
    # zawodnik w drużynie-1 -> zawodnik-1
    234138 : 4286,
    # metryczna jednostka masy-1 -> jednostka masy-1
    231263 : 7946,
    # część garderoby-1 element garderoby-1 element ubioru-1 sztuka odzieży-1 -> strój-1 ubiór-1 ubranie-3
    # meronimia
    227081 : 3289,
    # żywienie do kogoś pozytywnych uczuć-1 -> inklinacja-2 przychylność-2 sympatia-1 zainteresowanie-2
    # zupełnie niepowiązany synset, żywienie... jest z hierarchii GERUNDIUM
    81622 : 3367,
}

LEMMA_KILLLIST = ('odzieża',)

def get_interps(word, lemma=None, tag_constraints=None):
    interps = set()
    for i, j, (orth, base, tag, p, k) in morfeusz.analyse(word):
        tag_elems = set(tag.split(':'))
        base = base.split(':')[0]
        if base not in LEMMA_KILLLIST and (not lemma or base == lemma) and (not tag_constraints or tag_elems.issuperset(tag_constraints)):
            interps.add((base, tag))
    return interps

def get_adj_lemma(word):
    interps = get_interps(word, tag_constraints=['adj'])
    lemmata = set(lemma for lemma, tag in interps)
    degrees = set(tag.split(':')[4] for lemma, tag in interps)
    assert(len(lemmata) == 1)
    assert(len(degrees) == 1)
    return lemmata.pop(), degrees.pop()

def get_pact_lemma(word):
    interps = get_interps(word, tag_constraints=['pact'])
    lemmata = set(lemma for lemma, tag in interps)
    assert(len(lemmata) == 1)
    return lemmata.pop()

def get_subst_lemma(word, case):
    if (word, case) == ('zbrodni', 'gen'):
        # nie: zbrodzień
        return 'zbrodnia', 'sg'
    interps = get_interps(word, tag_constraints=['subst', case])
    lemmata = set(lemma for lemma, tag in interps)
    nums = set(tag.split(':')[1] for lemma, tag in interps)
    try:
        assert(len(lemmata) == 1)
    except:
        print(word, case, interps)
        raise
    # TODO? heurystyka dla liczby, np. ‹sztuka *odzieży*›
    return lemmata.pop(), 'sg' if 'sg' in nums else 'pl'

def adj2adv(lemma):
    if lemma.endswith('ny'):
        return lemma[:-1] + 'ie'
    1/0

'''
def get_degree(word):
    interps = morfeusz.analyse(word)
    adj_tags = [interp[2][2] for interp in interps if interp[2][2].startswith('adj:')]
    degrees = set(tag.split(':')[4] for tag in adj_tags)
    assert(len(degrees) == 1)
    return degrees.pop()
'''

'''
def get_num(word, case):
    interps = morfeusz.analyse(word)
    subst_tags = [interp[2][2] for interp in interps if interp[2][2].startswith('subst:')]
    nums = set(tag.split(':')[1] for tag in subst_tags if case in tag)
    # TODO heuristic
    return 'sg' if 'sg' in nums else 'pl'
'''

GERUNDS = {
    'przyrządzanie', 'szarpnięcie',
}

GENDER = {
    'braterstwo'    : 'n',
    'DNA'           : 'n',
    'narzeczeństwo' : 'n',
    
    'burda'    : 'f',
    'nuda'     : 'f',
    'pasza'    : 'f',
    'przekora' : 'f',
    'reżyser'  : 'f', # grl pwr!
    'sędzia'   : 'f',
    'włóczęga' : 'f',
    
    'aspirant'     : 'm1',
    'bojownik'     : 'm1',
    'champion'     : 'm1',
    'członek'      : 'm1', # członek rodziny
    'faworyt'      : 'm1',
    'gad'          : 'm1',
    'głąb'         : 'm1',
    'idol'         : 'm1',
    'informator'   : 'm1',
    'inicjator'    : 'm1',
    'mediator'     : 'm1',
    'orzeł'        : 'm1',
    'pilot'        : 'm1',
    'poseł'        : 'm1',
    'pośrednik'    : 'm1',
    'prekursor'    : 'm1',
    'profesor'     : 'm1',
    'przewodnik'   : 'm1',
    'reprezentant' : 'm1',
    'śpiewak'      : 'm1',
    'tchórz'       : 'm1',
    'tłumacz'      : 'm1',
    'zbieg'        : 'm1',
    
    'blues'       : 'm2', # czuje bluesa
    'całus'       : 'm2',
    'całusek'     : 'm2',
    'czort'       : 'm2',
    'diabeł'      : 'm2',
    'drapieżnik'  : 'm2',
    'fioł'        : 'm2',
    'grzyb'       : 'm2',
    'guz'         : 'm2',
    'kaduk'       : 'm2',
    'kogut'       : 'm2',
    'konik'       : 'm2',
    'kopniak'     : 'm2',
    'kosz'        : 'm2',
    'kot'         : 'm2',
    'koziołek'    : 'm2',
    'lód'         : 'm2',
    'Oscar'       : 'm2',
    'pająk'       : 'm2',
    'papieros'    : 'm2',
    # pies aportujący, nie pałujący
    'pies'        : 'm2',
    'pion'        : 'm2', # szachowy
    'samiec'      : 'm2',
    'ssak'        : 'm2',
    'świr'        : 'm2', # dostać świra
    'wąż'         : 'm2',
    'zając'       : 'm2',
    'ziemniak'    : 'm2',
    
    'dobry' : 'm3',
    
    'antytalent'   : 'm3',
    'aparat'       : 'm3',
    'asfalt'       : 'm3',
    'bas'          : 'm3',
    'bełkot'       : 'm3',
    'beton'        : 'm3',
    'bis'          : 'm3',
    'blog'         : 'm3',
    'bodziec'      : 'm3',
    'bruderszaft'  : 'm3',
    'but'          : 'm3',
    'bzik'         : 'm3',
    'cep'          : 'm3',
    'chichot'      : 'm3',
    'czubek'       : 'm3',
    'drapak'       : 'm3',
    'drut'         : 'm3',
    'dzień'        : 'm3', # nie f
    'dół'          : 'm3',
    'e-mail'       : 'm3',
    'fart'         : 'm3',
    'fenomen'      : 'm3',
    'figiel'       : 'm3',
    'flak'         : 'm3',
    'flis'         : 'm3',
    'galop'        : 'm3',
    'gnat'         : 'm3',
    'grill'        : 'm3',
    'grzmot'       : 'm3',
    'ideał'        : 'm3',
    'klawisz'      : 'm3',
    'klops'        : 'm3',
    'kołek'        : 'm3',
    'kozioł'       : 'm3',
    'Księżyc'      : 'm3',
    'kuksaniec'    : 'm3',
    'kurek'        : 'm3',
    'lek'          : 'm3',
    'licencjat'    : 'm3',
    'link'         : 'm3',
    'łeb'          : 'm3',
    'marsz'        : 'm3',
    'mat'          : 'm3',
    'mejl'         : 'm3',
    'metal'        : 'm3',
    'mikser'       : 'm3',
    'minus'        : 'm3',
    'młot'         : 'm3',
    'model'        : 'm3',
    'news'         : 'm3',
    'odpowiednik'  : 'm3',
    'operator'     : 'm3',
    'palec'        : 'm3',
    'paluch'       : 'm3',
    'pas'          : 'm3',
    'plaster'      : 'm3',
    'plus'         : 'm3',
    'pomruk'       : 'm3',
    'popłoch'      : 'm3',
    'post'         : 'm3',
    'powód'        : 'm3',
    'rapsod'       : 'm3',
    'ryj'          : 'm3',
    'Rzym'         : 'm3',
    'sen'          : 'm3',
    'skręt'        : 'm3',
    'smród'        : 'm3',
    'sport'        : 'm3',
    'stop'         : 'm3',
    'strach'       : 'm3',
    'sygnalizator' : 'm3',
    'szampan'      : 'm3',
    'talent'       : 'm3',
    'wist'         : 'm3',
    'walkower'     : 'm3',
    'wał'          : 'm3',
    'wyż'          : 'm3',
    'zajob'        : 'm3',
    'ząb'          : 'm3',
    'zwiastun'     : 'm3',
}

def get_gender(interps):
    # TODO?
    forms = set(form for form, tag in interps)
    if len(forms) == 1 and list(forms)[0] in GENDER:
        return GENDER[forms.pop()]
    genders = set(tag.split(':')[3] for form, tag in interps)
    try:
        assert(len(genders) == 1)
        return genders.pop()
    except:
        print(interps)

def get_simplified_tags(word):
    tags = set()
    for interp in morfeusz.analyse(word):
        tag = interp[2][2].split(':')
        pos = tag[0]
        if pos in ('subst', 'ger'):
            # POS + case
            tags.add('{}:{}'.format(tag[0], tag[2]))
        elif pos == 'prep':
            # POS + case
            tags.add('prep:{}'.format(tag[1]))
        else:
            tags.add(pos)
    return tags

def make_comprepnp(comprep, words, num, mod):
    dummy_id = None
    np = NP(Case('gen'), dummy_id)
    lexnp = LexNP(np, num, words, mod, dummy_id)
    phrases = set(make_phraseologisms(lexnp, None, None))
    assert(len(phrases) == 1)
    return ['{} {}'.format(comprep, phrases.pop())]

def make_compar(compar, words, num, mod, controller):
    dummy_id = None
    #if not controller:
    #    raise RealisationDescriptionError('no controller for {}'.format(compar))
    if controller:
        controller_case = controller.getCase()
    else:
        pos, lemma = get_current_entry()._pos, get_current_entry()._base
        if pos == 'verb':
            controller_case = 'nom' # najczęściej chyba nom lub acc, ale trzeba coś wybrać
        if pos == 'noun':
            controller_case = 'gen' # degradacja kogoś jako kogoś itp.
        if pos in ('adj', 'adv'):
            controller_case = 'nom' # analogiczny jak coś itp.
        logging.warning('{}: no controller for {}; assuming {}.'.format(lemma, compar, controller_case))
    np = NP(Case(controller_case), dummy_id)
    lexnp = LexNP(np, num, words, mod, dummy_id)
    return LexCompar(compar, [lexnp], dummy_id)
    
def make_adjp_mod(word):
    dummy_id = None
    adjp = AdjP(Case('agr'), dummy_id)
    lemma, degree = get_adj_lemma(word)
    words = Words('concat', 'xor', [lemma])
    lex_adjp = LexAdjP(adjp, 'agr', 'agr', degree, words, NATR, None)
    mod_position = Position(None, None, None, [lex_adjp], dummy_id)
    return Modification('ratr1', [mod_position])

def make_pactp_mod(word):
    dummy_id = None
    pactp = PActP(Case('agr'), dummy_id)
    lemma = get_pact_lemma(word)
    words = Words('concat', 'xor', [lemma])
    lex_pactp = LexPActP(pactp, 'agr', 'agr', 'aff', words, '', NATR, None)
    mod_position = Position(None, None, None, [lex_pactp], dummy_id)
    return Modification('ratr1', [mod_position])

def make_npgen_mod(word):
    dummy_id = None
    np = NP(Case('gen'), dummy_id)
    lemma, num = get_subst_lemma(word, 'gen')
    words = Words('concat', 'xor', [lemma])
    lex_np = LexNP(np, num, words, NATR, None)
    mod_position = Position(None, None, None, [lex_np], dummy_id)
    return Modification('ratr1', [mod_position])

def make_prepnp_mod(word, prep, case):
    dummy_id = None
    prepnp = PrepNP(Preposition(prep, Case(case)), dummy_id)
    lemma, num = get_subst_lemma(word, case)
    words = Words('concat', 'xor', [lemma])
    lex_prepnp = LexPrepNP(prepnp, num, words, NATR, None)
    mod_position = Position(None, None, None, [lex_prepnp], dummy_id)
    return Modification('ratr1', [mod_position])

def make_fixed_mod(text):
    dummy_id = None
    fixed = Fixed(None, text, dummy_id)
    mod_position = Position(None, None, None, [fixed], dummy_id)
    return Modification('ratr1', [mod_position])

NATR = Modification('natr', None)
JAKIS = make_adjp_mod('jakiś')

PREDEF2LEMMA = {
    'CECHA' : {
        'adjp' : ('jakiś', None, 'sg', 'adj', NATR),
        '_'    : ('cecha', 'f', 'sg', 'subst', JAKIS),
    },
    'CZAS' : {
        '_' : ('moment', 'm3', 'sg', 'subst', JAKIS),
    },
    'CZEMU' : {
        '_' : ('powód', 'm3', 'sg', 'subst', JAKIS),
    },
    'CZYNNOŚĆ' : {
        '_' : ('czynność', 'f', 'sg', 'subst', JAKIS),
    },
    'DOBRA' : {
        '_' : ('dobra', 'n', 'pl', 'subst', JAKIS),
    },
    'ILOŚĆ' : {
        '_' : ('ilość', 'f', 'sg', 'subst', JAKIS),
    },
    'ISTOTY' : {
        '_' : ('istota', 'f', 'sg', 'subst', JAKIS),
    },
    'JADŁO' : {
        '_' : ('pożywienie', 'n', 'sg', 'subst', JAKIS),
    },
    # Ela proponowała: sytuacja, ale wtedy mamy np. absolutorium za jakąś sytuację i wygląda dziwnie
    'KIEDY' : {
        '_' : ('czas', 'm3', 'sg', 'subst', JAKIS),
    },
    'KOMUNIKAT' : {
        '_' : ('komunikat', 'm3', 'sg', 'subst', JAKIS),
    },
    'KONCEPCJA' : {
        '_' : ('koncepcja', 'f', 'sg', 'subst', JAKIS),
    },
    'LUDZIE' : {
        'possp' : ('czyjś', None, 'sg', 'adj', NATR),
        '_'     : ('ktoś', 'm1', 'sg', 'subst', NATR),
    },
    'MIEJSCE' : {
        '_' : ('miejsce', 'n', 'sg', 'subst', JAKIS),
    },
    'OBIEKTY' : {
        '_' : ('obiekt', 'm3', 'sg', 'subst', JAKIS),
    },
    'OTOCZENIE' : {
        '_' : ('otoczenie', 'n', 'sg', 'subst', JAKIS),
    },
    # PODMIOTY -> LUDZIE
    #'PODMIOTY' : {
    #    'possp' : ('czyjś', 'sg', 'adj', NATR),
    #    '_'     : ('ktoś', 'sg', 'subst', NATR),
    #},
    'POŁOŻENIE' : {
        '_' : ('położenie', 'n', 'sg', 'subst', JAKIS),
    },
    'SYTUACJA' : {
        '_' : ('sytuacja', 'f', 'sg', 'subst', JAKIS),
    },
    'WYTWÓR' : {
        '_' : ('wytwór', 'm3', 'sg', 'subst', JAKIS),
    },
    'ALL' : {
        '_' : ('coś', 'n', 'sg', 'subst', NATR),
    }
}

PREDEFXP = {
    'caus' : {
        'LUDZIE' : 'z czyjegoś powodu',
        'ISTOTY' : 'z powodu jakiejś istoty',
        'ALL'    : 'z jakiegoś powodu',
    },
    'dest' : {
        'LUDZIE' : 'dla kogoś',
        'ALL' : 'w jakimś celu',
    },
    'mod' : {
        'ISTOTY' : 'w jakiś sposób',
        'ALL'    : 'w jakiś sposób',
    },
    'instr' : {
        'LUDZIE' : 'z czyjąś pomocą',
        'ISTOTY' : 'z pomocą jakiejś istoty',
        'ALL'    : 'za pomocą czegoś',
    },
    'abl' : {
        'LUDZIE' : 'od kogoś',
        'ISTOTY' : 'od jakiejś istoty',
        'ALL'    : 'skądś',
    },
    'adl' : {
        'LUDZIE'  : 'do kogoś',
        'ISTOTY'  : 'do jakiejś istoty',
        'MIEJSCE' : 'dokądś',
        'ALL'     : 'dokądś',
    },
    'locat' : {
        'LUDZIE'  : 'u kogoś',
        'ISTOTY'  : 'u jakiejś istoty',
        'MIEJSCE' : 'gdzieś',
        'ALL'     : 'gdzieś',
    },
    'perl' : {
        'LUDZIE' : 'po kimś', # „jak żebrak, jak bandyta czołgam się *pod nimi*” – to raczej nie powinno być xp(perl), tylko prepnp; ale coś muszę przypisać, więc „po kimś”, bo jeśli już, to coś/ktoś może przejść/chodzić po kimś...
        'ISTOTY' : 'po jakieś istocie',
        'ALL'    : 'którędyś',
    },
    'temp' : {
        'LUDZIE' : 'kiedyś', # np. bezprawie
        'ALL'    : 'kiedyś',
    },
    'dur' : {
        'ALL'    : 'przez jakiś czas',
    },
}