"""
Klasa do obslugi rzutowania plWN -> PWN -> SUMO
Przechowuje informacje o:
 * synsecie Slowosieci - typ npsemrel.wn.synset
 * synsecie Princeton - typ npsemrel.wn.synset
 * pojeciu SUMO - typ npsemrel.sumo.sumo
 * typie relacji Slowosiec->Princeton
 * typie relacji Princeton->SUMO
Bazujac na tych oraz dodatkowcy informacjach (takich jak wielka litera 
w lemacie synsetu Slowosieci) dokonuje rzutowania synsetu Slowosieci 
na pojecie SUMO"""

class PlwnPwnSumoMap:
    # plWN->PWN rel
    SYNONYMY = 'syn_pa'
    HYPERONYMY = 'hiper_pa'
    HYPONYMY = 'hipo_pa'
    SYNONYMY_MR = 'synmr_pa'
    SYNONYMY_CZ = 'syncz_pa'
    MERONYMY_CZ = 'mero:cz_pa'
    MERONYMY_EL = 'mero:el_pa'
    MERONYMY_MAT = 'mero:mat_pa'
    HOLONYMY_CZ = 'holo:cz_pa'
    HOLONYMY_EL = 'holo:el_pa'
    HOLONYMY_MAT = 'holo:mat_pa'
    # PWN->SUMO rel    
    EQUIVALENT = 'equivalent'
    INSTANCE_OF = 'instance_of'
    SUBSUMED = 'subsumed'
    # manually relation
    MANUALLY = 'R'
    CANNOT_SET = "?"
    # cech - 4, czc - 5, czuj - 9, zwz - 26, pos - 18, sys - 46
    SUBSUMED_DOMAINS = [4, 5, 9, 26, 18, 46]

    def __init__(self, plWN_synset, PWN_synset, SUMO_conc):
        # info o synsecie plWN, npsemrel.wn.synset
        self._plWN_synset = plWN_synset
        # info o synsecie PWN, npsemrel.wn.synset
        self._PWN_synset = PWN_synset
        # pojecie SUMO, npsemrel.sumo.sumo
        self._SUMO_conc = SUMO_conc
        # relacja plWN -> PWN
        self._plWN_PWN_rel_id = None
        self._plWN_PWN_rel_str = None
        # relacja PWN -> SUMO
        self._PWN_SUMO_rel_id = None
        self._PWN_SUMO_rel_str = None
        self._PWN_SUMO_rel_str_shortcut = None
    
    def plwn_synset(self):
        return self._plWN_synset

    def pwn_synset(self):
        return self._PWN_synset

    def sumo_concept(self):
        return self._SUMO_conc

    def plwn_pwn_rel_str(self):
        return self._plWN_PWN_rel_str
    
    def pwn_sumo_rel_str(self):
        return self._PWN_SUMO_rel_str
    
    def pwn_sumo_rel_shortuct_str(self):
        return self._PWN_SUMO_rel_str_shortcut

    def resolve_plwn_SUMO_rel(self):
        """Based on the interlingual mapping (between plwn and pwn) 
        and based on the pwn-sumo mapping runs rules to map plwn to 
        sumo. Set of mapping rules is available on gdoc... 
        try to ask Pawel Kedzia about it ;)"""
        return self.__run_rules()

    def __run_rules(self):
        """Runs whole set of rules. Execute 'private' methods and returns 
        string-like relations between plwn synset and SUMO concept"""
        res = self.__run_first_step_rules()
        
        if res == self.MANUALLY:
            res = self.__run_second_step_rules()
        
        if res == self.MANUALLY:
            res = self.__run_third_step_rules()

        return res
    
    def __run_first_step_rules(self):
        """First step of mappings. All rules are shown on gdoc"""
        if self.plwn_pwn_rel_str() == self.SYNONYMY:
            return self.__run_isynonymy_rules()
        elif self.plwn_pwn_rel_str() == self.HYPONYMY:
            return self.__run_ihyponymy_rules()
        elif self.plwn_pwn_rel_str() == self.SYNONYMY_MR:
            return self.__run_isynonymy_mr_rules()
        elif self.plwn_pwn_rel_str() == self.HYPERONYMY:
            return self.__run_ihyperonymy_rules()
        elif self.plwn_pwn_rel_str() == self.SYNONYMY_CZ:
            return self.__run_ipartsynonymy_rules()
        elif self.plwn_pwn_rel_str() == self.MERONYMY_CZ:
            return self.__run_ipartmeronymy_rules()
        elif self.plwn_pwn_rel_str() == self.MERONYMY_EL:
            return self.__run_imeronymyel_rules()
        elif self.plwn_pwn_rel_str() == self.MERONYMY_MAT:
            return self.__run_imeronymymat_rules()
        elif self.plwn_pwn_rel_str() == self.HOLONYMY_CZ:
            return self.__run_iholonymypart_rules()
        elif self.plwn_pwn_rel_str() == self.HOLONYMY_EL:
            return self.__run_iholonymyel_rules()
        elif self.plwn_pwn_rel_str() == self.HOLONYMY_MAT:
            return self.__run_iholonymymat_rules()
        else:
            import sys
            print >> sys.stderr, "WARNING: Interlingual relation: ", \
                            self.plwn_pwn_rel_str(), \
                            " is not handled by mapper! Relation cannot be proposed!"
            return self.CANNOT_SET

    def __run_second_step_rules(self):
        """These rules are run when the relation from first step is MANUALLY
           This is limitated into parent methods"""
        irels = [self.HYPERONYMY, 
                 self.MERONYMY_CZ, 
                 self.SYNONYMY_CZ]
        scpts = [
            'Human', 'Female', 'Banker', 'FamilyGroup', 
            'Group', 'Male', 'Maid', 'Position', 'Woman']

        if self.plwn_pwn_rel_str() in irels:
            if self.__is_domain_in(['os']):
                if self.__is_sumo_concept_in(scpts):
                    return self.SUBSUMED
        return self.MANUALLY
    
    def __run_third_step_rules(self):
        """These rules are run when the relation from first or second 
           step is MANUALLY. This is limitated into parent methods"""
        mrels = [self.INSTANCE_OF, 
                 self.EQUIVALENT]
        if self.plwn_pwn_rel_str() == self.MERONYMY_CZ:
            if self.__is_domain_in(['msc']) and self.__is_en_domain_in(['msc']):
                if self.__is_sumo_concept_in(['LandArea']):
                    if self.pwn_sumo_rel_str() == self.INSTANCE_OF:
                        if self.__lemma_starts_big():
                            return self.INSTANCE_OF
                        else:
                            return self.SUBSUMED
        elif self.plwn_pwn_rel_str() != self.HYPONYMY:
            if self.__is_domain_in(['msc']) and self.__is_en_domain_in(['msc']):
                if self.__is_sumo_concept_in(['City']):
                    if self.pwn_sumo_rel_str() in mrels:
                        return self.INSTANCE_OF
        return self.MANUALLY
        
    
    def __run_isynonymy_rules(self):
        """Rules runs when isynonymy"""
        if self.plwn_pwn_rel_str() == self.SYNONYMY:
            if self.pwn_sumo_rel_str() == self.EQUIVALENT:
                return self.EQUIVALENT
            elif self.pwn_sumo_rel_str() == self.INSTANCE_OF:
                return self.INSTANCE_OF
            elif self.pwn_sumo_rel_str() == self.SUBSUMED:
                return self.SUBSUMED

    def __run_ihyponymy_rules(self):
        """Rules runs when ihyponymy"""
        if self.plwn_pwn_rel_str() == self.HYPONYMY:
            if self.pwn_sumo_rel_str() == self.EQUIVALENT:
                if self.__is_domain_in(['msc']) and \
                    self.__is_en_domain_in(['msc']) and \
                    self.__is_sumo_concept_in(['City']) and \
                    self.__lemma_starts_big():
                    return self.INSTANCE_OF
                else:
                    return self.SUBSUMED
            elif self.pwn_sumo_rel_str() == self.INSTANCE_OF:
                if self.__is_domain_in(['prc']):
                    return self.MANUALLY
                else:
                    return self.INSTANCE_OF
            elif self.pwn_sumo_rel_str() == self.SUBSUMED:
                if self.__is_domain_in(['msc']) and \
                    self.__is_en_domain_in(['grp']) and \
                    self.__is_sumo_concept_in(['Nation']):
                    return self.MANUALLY
                elif self.__is_domain_in(['msc']) and \
                    self.__is_en_domain_in(['msc']) and \
                    self.__is_sumo_concept_in(['City']) and \
                    self.__lemma_starts_big():
                    return self.INSTANCE_OF
                else:
                    return self.SUBSUMED
            # at the end, runs metarules...
            return self.__run_metarules()

    def __run_isynonymy_mr_rules(self):
        """Rules runs when isynonymy mr"""
        if self.plwn_pwn_rel_str() == self.SYNONYMY_MR:
            if self.pwn_sumo_rel_str() == self.EQUIVALENT:
                if self.__is_domain_in(['msc']) and \
                    self.__is_en_domain_in(['grp']) and \
                    self.__is_sumo_concept_in(['Nation']):
                    return self.MANUALLY
                else:
                    return self.EQUIVALENT
            elif self.pwn_sumo_rel_str() == self.INSTANCE_OF:
                return self.INSTANCE_OF
            elif self.pwn_sumo_rel_str() == self.SUBSUMED:
                return self.SUBSUMED
            # at the end, runs metarules...
            return self.__run_metarules()

    def __run_ihyperonymy_rules(self):
        """Rules runs when ihyperonymy"""
        # R1
        if self.plwn_pwn_rel_str() == self.HYPERONYMY:
            if self.pwn_sumo_rel_str() == self.EQUIVALENT:
                if self.__is_domain_in(
                        [ 'czas', 'sbst', 'os', 'cech', 'czc', 'czuj', 'czy', 
                            'grp', 'il', 'jedz', 'por', 'sbst', 'zdarz', 'zwz']):
                    return self.SUBSUMED
                elif self.__is_domain_in(['wytw']) and \
                    not self.__is_sumo_concept_in(['AIM9']):
                    return self.SUBSUMED
                elif self.__is_domain_in(['msc']):
                    if self.__is_en_domain_in(['grp', 'msc']) and \
                        self.__is_sumo_concept_in(['Nation']):
                            return self.MANUALLY
                    else:
                        if not self.__lemma_starts_big():
                            return self.SUBSUMED
                        else:
                            return self.INSTANCE_OF
                elif self.__is_domain_in(['rz']):
                    return self.INSTANCE_OF
                # LP6 + LP7 z gdoca:
                return self.MANUALLY
            # R2
            elif self.pwn_sumo_rel_str() == self.INSTANCE_OF:
                if self.__is_domain_in(['il', 'msc']):
                    if self.__is_domain_in(['msc']) and \
                        self.__is_en_domain_in(['msc']) and \
                        self.__is_sumo_concept_in(['City']):
                        if self.__lemma_starts_big():
                            return self.INSTANCE_OF
                        else:
                            return self.SUBSUMED
                    else:
                        return self.SUBSUMED
                elif self.__is_domain_in(['os']):
                    if self.__lemma_starts_big() and self.__is_sumo_concept_in(['EthnicGroup']):
                        return self.INSTANCE_OF
                    elif not self.__lemma_starts_big() and \
                        self.__is_sumo_concept_in(['EthnicGroup', 'GeographicArea']):
                        return self.SUBSUMED
                    elif self.__is_sumo_concept_in(['GeographicArea']):
                        return self.MANUALLY
                elif self.__is_domain_in(['pos', 'wytw', 'zw']):
                    return self.SUBSUMED
                elif self.__is_domain_in(['umy']):
                    return self.INSTANCE_OF
                elif self.__is_domain_in(['rz']):
                    return self.MANUALLY
                return self.MANUALLY
            # R3
            elif self.pwn_sumo_rel_str() == self.SUBSUMED:
                if self.__is_domain_in(
                        ['cech', 'czas', 'czc', 'czuj', 'grp', 'il', 'jedz', 
                            'msc', 'pos', 'prc', 'rz', 'sbst', 'sys', 'umy', 
                            'wytw', 'zdarz', 'zj', 'zw', 'zwz']):
                    if self.__is_domain_in(['msc']) and \
                        self.__is_en_domain_in(['grp', 'msc']) and \
                        self.__is_sumo_concept_in(['Nation']):
                        return self.MANUALLY
                    elif self.__is_domain_in(['msc']) and \
                        self.__is_en_domain_in(['msc']) and \
                        self.__is_sumo_concept_in(['City']):
                        if self.__lemma_starts_big():
                            return self.INSTANCE_OF
                        else:
                            return self.SUBSUMED
                    else:
                        return self.SUBSUMED
                elif self.__is_domain_in(['czy']):
                    return self.INSTANCE_OF
                elif self.__is_domain_in(['os']):
                    if self.__lemma_starts_big():
                        if self.__is_sumo_concept_in(['EthnicGroup', 'believes']):
                            return self.INSTANCE_OF
                        else:
                            return self.SUBSUMED
                elif self.__is_domain_in(['por']):
                    if not self.__is_sumo_concept_in(['Song']):
                        return self.SUBSUMED
                    else:
                        return self.MANUALLY
                elif self.__is_domain_in(['rsl', 'st']):
                    return self.MANUALLY
            # at the end, runs metarules...
            return self.__run_metarules()

    def __run_ipartsynonymy_rules(self):
        """Rules runs when i partial synonymy"""
        if self.plwn_pwn_rel_str() == self.SYNONYMY_CZ:
            # R4
            if self.pwn_sumo_rel_str() == self.EQUIVALENT:
                if self.__is_domain_in(['czc', 'grp', 'jedz', 'msc', 'por', 'pos', 'rsl', 
                            'rz', 'sbst', 'umy', 'wytw', 'zdarz', 'zj', 'zwz']):
                        return self.SUBSUMED
                if self.__is_domain_in(['os']):
                    if not self.__lemma_starts_big():
                        return self.SUBSUMED
                    else:
                        return self.MANUALLY
                return self.MANUALLY
            # R5
            elif self.pwn_sumo_rel_str() == self.INSTANCE_OF:
                if self.__is_domain_in(['grp', 'msc']):
                    return self.SUBSUMED
                elif self.__is_domain_in(['os', 'umy']):
                    return self.INSTANCE_OF
            # R6
            elif self.pwn_sumo_rel_str() == self.SUBSUMED:
                if self.__is_domain_in(
                        ['cech', 'czc', 'grp', 'jedz', 'msc', 'por', 
                            'pos', 'prc', 'rz', 'sbst', 'st', 'umy', 
                            'wytw', 'zdarz', 'zj', 'zw', 'zwz']):
                    return self.SUBSUMED
                elif self.__is_domain_in(['cel', 'il']):
                    return self.MANUALLY
                elif self.__is_domain_in(['czas']):
                    if self.__lemma_starts_big():
                        return self.INSTANCE_OF
                    else:
                        return self.SUBSUMED
                elif self.__is_domain_in(['czy']):
                    return self.INSTANCE_OF
                elif self.__is_domain_in(['os']):
                    if not self.__lemma_starts_big():
                        return self.SUBSUMED
                    else:
                        if self.__is_sumo_concept_in(['EthnicGroup', 'ReligiousOrganization', 'Agent']):
                            return self.INSTANCE_OF
                return self.MANUALLY
            # at the end, runs metarules...
            return self.__run_metarules()

    def __run_ipartmeronymy_rules(self):
        """Rules runs when ipartial meronymy"""
        if self.plwn_pwn_rel_str() == self.MERONYMY_CZ:
            # R7
            if self.pwn_sumo_rel_str() == self.EQUIVALENT:
                if self.__lemma_starts_big():
                    if self.__is_domain_in(['msc']) and self.__is_en_domain_in(['rz']):
                        return self.INSTANCE_OF
                    elif self.__is_domain_in(['zwz']) and self.__is_en_domain_in(['msc']):
                        return self.INSTANCE_OF
                    else:
                        # LP 29.4/29.2
                        return self.MANUALLY
                else:
                    if self.__is_domain_in(['czas', 'grp', 'jedz', 'prc']):
                        # LP 30
                        return self.INSTANCE_OF
                    elif self.__is_domain_in(['umy']) and self.__is_sumo_concept_in(['History']):
                        return self.INSTANCE_OF
                    else:
                        # LP 30.1
                        return self.MANUALLY
            # R8
            elif self.pwn_sumo_rel_str() == self.INSTANCE_OF:
                # LP31 LP32 LP33
                if self.__is_domain_in(['msc', 'zwz']):
                    return self.MANUALLY
                elif self.__is_domain_in(['rsl', 'czas']):
                    return self.SUBSUMED
                elif self.__is_domain_in(['il']):
                    return self.INSTANCE_OF
                elif self.__is_domain_in(['umy']) and self.__is_sumo_concept_in(['FieldOfStudy']):
                    return self.INSTANCE_OF
            # R9
            elif self.pwn_sumo_rel_str() == self.SUBSUMED:
                # LP34 LP35
                if self.__is_domain_in(['msc', 'czc', 'wytw', 'grp', 'jedz', 
                                        'ksz', 'os', 'por', 'sys', 'sbst', 
                                        'zdarz', 'zj']):
                    return self.MANUALLY
                elif self.__is_domain_in(['rsl', 'prc', 'pos', 'zw']):
                    return self.SUBSUMED
                elif self.__is_domain_in(['umy']) and self.__is_sumo_concept_in(['Theology']):
                    return self.INSTANCE_OF
            # at the end, runs metarules...
            return self.__run_metarules()


    def __run_imeronymyel_rules(self):
        """Rules runs when ielement meronymy"""
        if self.plwn_pwn_rel_str() == self.MERONYMY_EL:
            # R10
            # LP36 LP36.2 LP36.3
            if self.pwn_sumo_rel_str() == self.EQUIVALENT:
                return self.MANUALLY
            # R11
            elif self.pwn_sumo_rel_str() == self.INSTANCE_OF:
                # LP37 LP38
                return self.MANUALLY
            # R12
            elif self.pwn_sumo_rel_str() == self.SUBSUMED:
                if self.__is_domain_in(['czc', 'jedz', 'os', 'wytw']):
                    return self.MANUALLY
                elif self.__is_domain_in(['rsl', 'rz', 'zw']):
                    return self.SUBSUMED
                else:
                    return self.MANUALLY
            # at the end, runs metarules...
            return self.__run_metarules()

    def __run_imeronymymat_rules(self):
        """Rules runs when imaterial meronymy"""
        if self.plwn_pwn_rel_str() == self.MERONYMY_MAT:
            # R13
            if self.pwn_sumo_rel_str() == self.EQUIVALENT:
                return self.INSTANCE_OF
            # R14
            elif self.pwn_sumo_rel_str() == self.SUBSUMED:
                return self.INSTANCE_OF

    def __run_iholonymypart_rules(self):
        if self.plwn_pwn_rel_str() == self.HOLONYMY_CZ:
            # R15
            if self.pwn_sumo_rel_str() == self.EQUIVALENT:
                return self.MANUALLY
            # R16
            elif self.pwn_sumo_rel_str() == self.INSTANCE_OF:
                # LP44 LP45
                return self.INSTANCE_OF
            # R17
            elif self.pwn_sumo_rel_str() == self.SUBSUMED:
                # LP46 LP48
                if self.__is_domain_in(['czc', 'il', 'msc', 'rsl', 'sys', 'wytw', 'zwz',
                    'czy', 'grp', 'por', 'rz', 'sbst', 'zdarz', 'zw']):
                    return self.MANUALLY
                elif self.__is_domain_in(['umy']):
                    return self.INSTANCE_OF
                elif self.__is_domain_in(['zj']) and \
                     self.__is_en_domain_in(['st']) and \
                     self.__is_sumo_concept_in(['DiseaseOrSyndrome']):
                    return self.SUBSUMED
            # at the end, runs metarules...
            return self.__run_metarules()

    def __run_iholonymyel_rules(self):
        """Rules runs when iholonymy of element"""
        if self.plwn_pwn_rel_str() == self.HOLONYMY_EL:
            # R18
            if self.pwn_sumo_rel_str() == self.EQUIVALENT:
                return self.MANUALLY
            # R19
            elif self.pwn_sumo_rel_str() == self.INSTANCE_OF:
                return self.INSTANCE_OF
            # R20
            elif self.pwn_sumo_rel_str() == self.SUBSUMED:
                if self.__is_domain_in(['cech', 'czc', 'jedz', 'rsl', 'st', 'wytw']):
                    return self.MANUALLY
                elif self.__is_domain_in(['zj']) and \
                     self.__is_en_domain_in(['st']) and \
                     self.__is_sumo_concept_in(['DiseaseOrSyndrome']):
                    return self.SUBSUMED
                else:
                    return self.MANUALLY
            # at the end, runs metarules...
            return self.__run_metarules()

    def __run_iholonymymat_rules(self):
        """Rules runs when i holonymy of material"""
        if self.plwn_pwn_rel_str() == self.HOLONYMY_MAT:
            # R21
            if self.pwn_sumo_rel_str() == self.EQUIVALENT:
                pass
                # return self.SUBSUMED
            elif self.pwn_sumo_rel_str() == self.INSTANCE_OF:
                pass
                # return self.MANUALLY
            # R22
            elif self.pwn_sumo_rel_str() == self.SUBSUMED:
                # LP53 LP54
                return self.MANUALLY
            # at the end, runs metarules...
            return self.__run_metarules()

    def __run_metarules(self):
        """ Metarules:
        jezeli synset plwn posiada jedna z dziedzin: 
        cech - 4, czc - 5, czuj - 9, zwz - 26, pos - 18, sys - 46"""
        if int(self.plwn_synset().syn_domain()) in self.SUBSUMED_DOMAINS:
            return self.SUBSUMED
        return self.MANUALLY


    def __is_domain_in(self, d_l):
        return self.plwn_synset().syn_domain_str() in d_l
    
    def __is_en_domain_in(self, d_l):
        return self.pwn_synset().syn_domain_str() in d_l

    def __is_sumo_concept_in(self, c_l):
        return self.sumo_concept().concept_name in c_l

    def __lemma_starts_big(self):
        return self.plwn_synset().syn_str()[0].upper() == \
                self.plwn_synset().syn_str()[0]
