#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Copyright 2019 Harri Pitkänen (hatapitk@iki.fi)
# Program for producing and comparing CONLL-U formatted data.
# This program requires Python and Python module of libvoikko from
# libvoikko 3.0 or later.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

import sys
from libvoikko import Voikko
from conllu import parse
from collections import OrderedDict

class Difference:
    def __init__(self, attr_name, left, right):
        self.attr_name = attr_name
        self.left = left
        self.right = right

    def __repr__(self):
        return "Attr: {}, {} <-> {}".format(self.attr_name, self.left, self.right)

def get_differences(left, right):
    diffs = []
    for attr in ["form", "lemma"]:
        if left[attr] != right[attr]:
            diffs.append(Difference(attr, left[attr], right[attr]))
    feats_l = left["feats"]
    feats_r = right["feats"]
    if feats_l is not None and feats_r is not None:
        for k_l, v_l in feats_l.items():
            if k_l in feats_r and feats_r[k_l] != v_l:
                diffs.append(Difference(k_l, v_l, feats_r[k_l]))
    return diffs

def map_or_self(m, key):
    if key in m:
        return m[key]
    return key

def map_feats(voikko_analysis):
    feats = OrderedDict()
    if "NUMBER" in voikko_analysis:
        feats["Number"] = map_or_self({"singular":"Sing", "plural":"Plur"}, voikko_analysis["NUMBER"])
    if "SIJAMUOTO" in voikko_analysis:
        feats["Case"] = map_or_self({"nimento":"Nom", "omanto":"Gen", "osanto":"Par",
                                     "sisaolento":"Ine", "sisaeronto":"Ela", "sisatulento":"Ill",
                                     "ulkoolento":"Ade", "ulkoeronto":"Abl", "ulkotulento":"All",
                                     "olento":"Ess", "tulento":"Tra", "seuranto":"Com",
                                     "kohdanto":"Acc", "keinonto":"Ins", "vajanto":"Abe"}, voikko_analysis["SIJAMUOTO"])
    if "POSSESSIVE" in voikko_analysis:
        feats["Person[psor]"] = map_or_self({"1s":"1", "2s":"2", "1p":"1", "2p":"2"}, voikko_analysis["POSSESSIVE"])
        feats["Number[psor]"] = map_or_self({"1s":"Sing", "2s":"Sing", "1p":"Plur", "2p":"Plur"}, voikko_analysis["POSSESSIVE"])
    if "COMPARISON" in voikko_analysis:
        feats["Degree"] = map_or_self({"positive":"Pos", "comparative":"Cmp", "superlative":"Sup"}, voikko_analysis["COMPARISON"])
    if "PERSON" in voikko_analysis:
        feats["Person"] = map_or_self({}, voikko_analysis["PERSON"])
    if "TENSE" in voikko_analysis:
        feats["Tense"] = map_or_self({"present_simple":"Pres", "past_imperfective":"Past"}, voikko_analysis["TENSE"])
    if "MOOD" in voikko_analysis:
        voikko_mood = voikko_analysis["MOOD"]
        feats["Mood"] = map_or_self({"indicative":"Ind", "conditional":"Cnd", "potential":"Pot",
                                     "imperative":"Imp"}, voikko_mood)
        if voikko_mood == "A-infinitive":
            feats["VerbForm"] = "Inf"
            feats["InfForm"] = "1"
        if voikko_mood == "E-infinitive":
            feats["VerbForm"] = "Inf"
            feats["InfForm"] = "2"
        if voikko_mood == "MINEN-infinitive":
            feats["Derivation"] = "Minen"
        if voikko_mood == "MA-infinitive":
            pass #TODO
        if voikko_mood == "MAINEN-infinitive":
            pass #TODO
    if "FOCUS" in voikko_analysis:
        feats["Clitic"] = map_or_self({"kin":"Kin", "kaan":"Kaan"}, voikko_analysis["FOCUS"])
    if "KYSYMYSLIITE" in voikko_analysis:
        feats["Clitic"] = "Ko"
    if "PARTICIPLE" in voikko_analysis:
        feats["VerbForm"] = "Part"
        feats["PartForm"] = map_or_self({"present_active":"Pres", "past_active":"Past", "agent":"Agt",
                                         "present_passive":"Pres", "past_passive":"Past"}, voikko_analysis["PARTICIPLE"])
        feats["Voice"] = map_or_self({"present_active":"Act", "past_active":"Act", "agent":"Act",
                                      "present_passive":"Pass", "past_passive":"Pass"}, voikko_analysis["PARTICIPLE"])
    if len(feats) > 0:
        return feats
    return None

def to_conllu(form, voikko_analysis):
    result = OrderedDict()
    result["form"] = form
    result["lemma"] = voikko_analysis["BASEFORM"]
    result["feats"] = map_feats(voikko_analysis)
    return result

if "--help" in sys.argv:
    print("Usage:")
    print(sys.argv[0], "TODO")
    sys.exit(0)

language = "fi"

voikko = Voikko(language)

for tokens in parse(sys.stdin.read()):
    for token in tokens:
        if "form" not in token:
            continue
        word_form = token["form"]
        analysis_list = voikko.analyze(word_form)
        if len(analysis_list) != 1:
            continue
        left = token
        right = to_conllu(word_form, analysis_list[0])
        diffs = get_differences(left, right)
        if len(diffs) > 0:
            for diff in diffs:
                print(word_form, diff)

voikko.terminate()
