# Python-ohjelma, joka luo sanalistoja Kotuksen alkuperäisen CSV-sanalistan ja
# yhdyssanatiedoston mukaan

import sys

# luettavat tiedostot (on oltava ennestään olemassa)
CSV_FILE       = "nykysuomensanalista2024.txt"
COMPOUNDS_FILE = "compounds.txt"

# kirjoitettavat tiedostot (ylikirjoitetaan, jos ovat jo olemassa)
PLAINTEXT_FILE        = "plaintext.txt"
STRIPPED_FILE         = "stripped.txt"
STRIPPED_REVERSE_FILE = "stripped-reverse.txt"
SINGLES_FILE          = "singles.txt"
SINGLES_REVERSE_FILE  = "singles-reverse.txt"
FINALS_FILE           = "finals.txt"
NONFINALS_FILE        = "nonfinals.txt"

def read_lines(filename):
    # generoi UTF-8-tekstitiedoston rivit ilman rivinvaihtoja
    try:
        with open(filename, "rt", encoding="utf8") as handle:
            handle.seek(0)
            for line in handle:
                yield line.rstrip("\n")
    except UnicodeDecodeError:
        sys.exit(f"Tiedosto {filename} ei ole UTF-8-muodossa.")
    except OSError:
        sys.exit(f"Virhe luettaessa tiedostoa {filename}")

def write_lines(lines, filename):
    # kirjoita rivit UTF-8-tekstitiedostoon
    try:
        with open(filename, "wt", encoding="utf8") as handle:
            handle.seek(0)
            for line in lines:
                print(line, file=handle)
    except OSError:
        sys.exit(f"Virhe kirjoitettaessa tiedostoa {filename}")
    print(f"Kirjoitettu {len(lines)} rivi(ä) tiedostoon {filename}")

def finnish_sort(words):
    # lajittele sanalista suomalaisittain
    words = sorted(words)
    words.sort(key=lambda w:
        "".join(c for c in w.lower() if c.isalpha())
        .replace("à", "a")
        .replace("á", "a")
        .replace("â", "a")
        .replace("è", "e")
        .replace("é", "e")
        .replace("ê", "e")
        .replace("î", "i")
        .replace("ñ", "n")
        .replace("ô", "o")
        .replace("õ", "o")
        .replace("š", "s")
        .replace("û", "u")
        .replace("w", "v")
        .replace("ž", "z")
        .replace("å", "ã")  # "ã" on välittömästi ennen "ä":tä Unicodessa
    )
    return words

def finnish_reverse_sort(words):
    # lajittele sanalista suomalaisittain lopusta alkuun;
    # kirjaimet y, ä ja ö samanarvoisina kuin u, a ja o
    words = sorted(words, key=lambda w: w[::-1])
    words.sort(key=lambda w:
        "".join(c for c in w.lower() if c.isalpha())[::-1]
        .replace("à", "a")
        .replace("á", "a")
        .replace("â", "a")
        .replace("ä", "a")
        .replace("è", "e")
        .replace("é", "e")
        .replace("ê", "e")
        .replace("î", "i")
        .replace("ñ", "n")
        .replace("ô", "o")
        .replace("õ", "o")
        .replace("ö", "o")
        .replace("š", "s")
        .replace("û", "u")
        .replace("w", "v")
        .replace("y", "u")
        .replace("ž", "z")
    )
    return words

def write_plaintext():
    # kirjoita alkuperäinen sanalista puhtaana tekstinä
    words = []
    for (i, line) in enumerate(read_lines(CSV_FILE)):
        if i > 0:
            line = line.rstrip("\n")
            parts = line.split("\t")
            if len(parts) != 4:
                sys.exit(f"Virheellinen rivi CSV-tiedostossa: {line}")
            words.append(parts[0])
    write_lines(words, PLAINTEXT_FILE)

def write_stripped():
    # kirjoita sanalista ilman väliviivoja alussa tai lopussa;
    # U+2011 = non-breaking hyphen
    words = set(w.strip("-\u2011") for w in read_lines(PLAINTEXT_FILE))
    words = finnish_sort(words)
    write_lines(words, STRIPPED_FILE)

def write_stripped_reverse():
    # kirjoita sanalista ilman väliviivoja alussa tai lopussa, takaperin
    # aakkostettuna;
    # U+2011 = non-breaking hyphen
    words = set(w.strip("-\u2011") for w in read_lines(PLAINTEXT_FILE))
    words = finnish_reverse_sort(words)
    write_lines(words, STRIPPED_REVERSE_FILE)

def write_singles():
    # kirjoita ei-yhdyssanat
    words = set(read_lines(STRIPPED_FILE))
    words.difference_update(
        w.replace("_", "") for w in read_lines(COMPOUNDS_FILE)
    )
    words = finnish_sort(words)
    write_lines(words, SINGLES_FILE)

def write_singles_reverse():
    # kirjoita ei-yhdyssanat takaperin aakkostettuna
    words = set(read_lines(STRIPPED_FILE))
    words.difference_update(
        w.replace("_", "") for w in read_lines(COMPOUNDS_FILE)
    )
    words = finnish_reverse_sort(words)
    write_lines(words, SINGLES_REVERSE_FILE)

def write_finals():
    # kirjoita yhdyssanojen viimeiset sanat, ei kuitenkaan yksinään esiintyviä
    words = set(w.split("_")[-1] for w in read_lines(COMPOUNDS_FILE))
    words.difference_update(read_lines(STRIPPED_FILE))
    words = finnish_sort(words)
    write_lines(words, FINALS_FILE)

def write_nonfinals():
    # kirjoita yhdyssanojen ei-viimeiset sanat, ei kuitenkaan yhdyssanojen
    # viimeisiä sanoja eikä yksinään esiintyviä sanoja;
    # U+2011 = non-breaking hyphen
    words = set()
    for line in read_lines(COMPOUNDS_FILE):
        words.update(p.rstrip("-\u2011 ") for p in line.split("_")[:-1])
    words.difference_update(
        w.split("_")[-1] for w in read_lines(COMPOUNDS_FILE)
    )
    words.difference_update(read_lines(STRIPPED_FILE))
    words = finnish_sort(words)
    write_lines(words, NONFINALS_FILE)

def main():
    write_plaintext()
    write_stripped()
    write_stripped_reverse()
    write_singles()
    write_singles_reverse()
    write_finals()
    write_nonfinals()

main()
