# vi: syntax=python:et:ts=4
from glob import glob
from subprocess import Popen, PIPE
import os, shutil
import re
from fnmatch import fnmatch
from os.path import join, relpath
Import("env")

def remove_pot_cdate(path):
    return "".join([line for line in open(path).readlines() if "POT-Creation-Date: " not in line])
def update_pot(target, source, env):
    pot = target[0].path
    new_pot = source[0].path
    if not os.path.exists(new_pot): return
    if remove_pot_cdate(new_pot) != remove_pot_cdate(pot):
        shutil.copy2(new_pot, pot)
        print(pot + " updated.")
    os.remove(new_pot)

#
# Gettext message catalog generation
#

textdomains = glob("wesnoth*")
po4a_domains = Split("wesnoth-manpages wesnoth-manual")
textdomains = [domain for domain in textdomains if os.path.isdir(domain) and os.path.exists(domain+"/"+domain+".pot")]
linguas = Split(open("LINGUAS").read())
intermediate_exts = {
    "cpp": "C++",
    "py": "Python",
}

if "pot-update" in COMMAND_LINE_TARGETS:
    from collections import defaultdict
    domain_sources = {ext: defaultdict(list) for ext in intermediate_exts}
    for root, dirs, files in os.walk("../src"):
        for file in files:
            if fnmatch(file, "*.[hc]pp"):
                match = re.search(r'^#define\s+GETTEXT_DOMAIN\s+"(wesnoth(?:-.*)?)"', Dir(root).File(file).get_contents().decode("utf-8"), re.MULTILINE)
                if match:
                    source_domain = match.group(1)
                else:
                    # Default to wesnoth textdomain
                    source_domain = "wesnoth"
                domain_sources["cpp"][source_domain].append(Dir(root).File(file).path)
    for root, dirs, files in os.walk("../data/tools"):
        for file in files:
            is_python = fnmatch(file, "*.py*")
            file_content = None
            if not is_python and not os.path.isdir(os.path.join(root, file)):
                file_content = Dir(root).File(file).get_contents()
                first_line = file_content.split(b"\n")[0]
                is_python = first_line[0:3] == b'^#!' and b'python' in first_line
            if is_python:
                if file_content is None:
                    file_content = Dir(root).File(file).get_contents()
                try:
                    match = re.search(r'^\s*_\s*=\s*gettext\.translation\(\s*([\'"])(wesnoth(?:-.*)?)\1', file_content.decode("utf-8"), re.MULTILINE)
                    if match:
                        source_domain = match.group(2)
                        domain_sources["py"][source_domain].append(Dir(root).File(file).path)
                    # In contrast to CPP, there is no default.
                except UnicodeDecodeError as ex:
                    pass
                finally:
                    file_content = None
                

    for domain in textdomains:
        pot = File(join(domain, domain + ".pot"))
        env.Precious(pot)
        NoClean(pot)
        env.Alias("pot-update", pot)
        if domain in po4a_domains:
            continue

        intermediate_files = []
        for ext, language in intermediate_exts.items():
            files_from = join("po", domain, "POTFILES_{}.in".format(ext.upper()))
            with open(relpath(files_from, "po"), "w") as potfiles:
                potfiles.writelines([line + "\n" for line in sorted(domain_sources[ext][domain])])
            file_list = [Dir("#").File(x) for x in domain_sources[ext][domain]]
            if file_list:
                target_path = env.Command(
                    join(domain, "{}.{}.pot".format(domain, ext)),
                    file_list,
                    """xgettext --force-po --default-domain={default_domain} --directory=. --add-comments=TRANSLATORS: \
                    --from-code=UTF-8 --language={language} --sort-by-file \
                    --keyword=_ --keyword=N_ --keyword=sgettext --keyword=vgettext --keyword=VGETTEXT \
                    --keyword=_n:1,2 --keyword=N_n:1,2 --keyword=sngettext:1,2 --keyword=vngettext:1,2 --keyword=VNGETTEXT:1,2 \
                    --files-from={files_from} --copyright-holder='Wesnoth development team' --msgid-bugs-address=https://bugs.wesnoth.org/ \
                    --output=- | sed s/charset=CHARSET/charset=UTF-8/ > $TARGET \
                    """.format(default_domain=domain, language=language, files_from=files_from)
                )
                intermediate_files.append(target_path)

        # wml/lua
        cfgs = []
        FINDCFG = join(domain, "FINDCFG")
        if os.path.exists(FINDCFG):
            cfgs = Split(Popen(["sh", join("po", FINDCFG)], stdout = PIPE, cwd = "..").communicate()[0].decode("utf-8"))
        cfgs = [File(x, Dir("..")) for x in cfgs]
        if cfgs:
            wml_pot = env.Command(
                join(domain, domain + ".wml.pot"),
                cfgs,
                "data/tools/wmlxgettext --force-po --directory=. --domain=%s $SOURCES -o $TARGET" % domain
                )
            intermediate_files.append(wml_pot)

        new_pot = str(pot) + ".new"

        env.Command(new_pot, intermediate_files,
                [
                    "msgcat --sort-by-file $SOURCES -o $TARGET",
                ] + list(map(Delete, intermediate_files))
            )
        env.Command(pot, new_pot, Action(update_pot))

    env.Alias("pot-update", "../translations", "python3 utils/po_stat.py --update-cfg --textdomains=wesnoth,wesnoth-editor,wesnoth-help,wesnoth-lib,wesnoth-multiplayer,wesnoth-tsg,wesnoth-units,wesnoth-anl")

if "update-po" in COMMAND_LINE_TARGETS or "pot-update" in COMMAND_LINE_TARGETS or "update-po4a" in COMMAND_LINE_TARGETS:
    for domain in textdomains:
        for lingua in linguas:
            update_po = env.MsgInitMerge(
                os.path.join(domain, lingua),
                os.path.join(domain, domain),
                MSGINIT_LINGUA = lingua
                )
            env.Precious(update_po)
            NoClean(update_po)

            env.Alias(lingua, [update_po, join("../translations", lingua)])
            if lingua in COMMAND_LINE_TARGETS:
                env.AlwaysBuild(update_po)

    env.Alias("update-po", [])

#
# Manual and man pages translation
#

if "update-po4a" in COMMAND_LINE_TARGETS or "pot-update" in COMMAND_LINE_TARGETS:
    env.Po4aUpdatePo("wesnoth-manual/wesnoth-manual.pot", "../doc/manual/manual.en.xml", PO4A_FORMAT = "docbook")
    for lingua in linguas:
        env.Po4aTranslate("../doc/manual/manual." + lingua + ".xml",
            ["../doc/manual/manual.en.xml", join("wesnoth-manual", lingua + ".po")],
            PO4A_CHARSET = "utf8", PO4A_FORMAT = "docbook")
    Alias("update-po4a", Alias("manual"))

    manpages = Split("wesnoth.6 wesnothd.6")
    env.Po4aUpdatePo("wesnoth-manpages/wesnoth-manpages.pot",
        [join("../doc/man", man) for man in manpages], PO4A_FORMAT = "man")
    for lingua in linguas:
        for man in manpages:
            env.Po4aTranslate(join("../doc/man", lingua, man),
            [join("../doc/man", man), join("wesnoth-manpages", lingua + ".po")],
            PO4A_CHARSET = "utf8", PO4A_FORMAT = "man")
    Alias("update-po4a", "../doc/man")

#
# If we have the right tool in place, create targets to invoke msgfmt to
# compile message catalogs to binary format at installation time.
# Without this step, the i18n support won't work.  Note, the actions
# this generates should fire only when installing data.
#
if env["nls"]:
    for domain in textdomains:
        for lingua in linguas:
            env.Msgfmt(
                join("../translations", lingua, "LC_MESSAGES", domain),
                join(domain, lingua)
                )
