#!/usr/bin/env python3

import fnmatch
import os
import sys
import xml.etree.ElementTree as ET

# STRINGTABLE VALIDATOR
# Author: mharis001
# ---------------------
# Verifies all stringtable.xml files in the project. Checks for:
#   - proper XML tree structure.
#   - English as first translation.
#   - no Original translation.
#   - duplicated entries and languages.


######## GLOBALS #########
PROJECT_NAME = "ACE"
##########################


def check_stringtable(filepath):
    try:
        tree = ET.parse(filepath)
    except:
        print("  ERROR: Failed to parse file.")
        return 1

    errors = 0

    # Verify that the root tag is Project and its name attribute is the project name
    root = tree.getroot()

    if root.tag != "Project":
        print("  ERROR: Invalid root tag '{}' found, must be 'Project'.".format(root.tag))
        errors += 1

    if root.get("name") != PROJECT_NAME:
        print("  ERROR: Invalid name attribute '{}' for Project tag, must be '{}'.".format(root.get("name"), PROJECT_NAME))
        errors += 1

    # Verify that the root has a Package tag and its name attribute matches the component's folder name
    package = root.find("Package")

    if package is None:
        print("  ERROR: Failed to find 'Package' tag under 'Project' tag.")
        errors += 1
    else:
        package_name = package.get("name")

        if package_name.islower():
            print("  ERROR: Package name attribute '{}' is all lowercase, should be in titlecase.".format(package_name))
            errors += 1

        if package_name.lower() != os.path.basename(os.path.dirname(filepath)):
            print("  ERROR: Package name attribute '{}' does not match the component folder name.".format(package_name))
            errors += 1

        # Get all keys contained in the stringtable
        keys = package.findall("Key")

        for container in package.findall("Container"):
            keys.extend(container.findall("Key"))

        key_ids = []
        key_prefix = "STR_{}_{}_".format(PROJECT_NAME, package_name)

        for key in keys:
            key_id = key.get("ID")

            # Verify that the key has a valid ID attribute
            if key_id is None:
                print("  ERROR: Key '{}' had no ID attribute.".format(key_id))
                errors += 1
            elif key_id.find(key_prefix) != 0:
                print("  ERROR: Key '{}' does not have a valid ID attribute, should be in format {}{{name}}.".format(key_id, key_prefix))
                errors += 1

            key_ids.append(key_id)

            # Verify language entries for the key, check that the key:
            #   - contains at least one translation
            #   - does not contain an Original translation
            #   - has English as the first listed translation
            #   - has only one entry for each language
            entries = list(key)

            if len(entries) == 0:
                print("  ERROR: Key '{}' has no translation entries.".format(key_id))
                errors += 1
            else:
                if not key.find("Original") is None:
                    print("  ERROR: Key '{}' has an Original translation, unnecessary with English as first.".format(key_id))
                    errors += 1

                if entries[0].tag != "English":
                    print("  ERROR: Key '{}' does not have its English translation listed first.".format(key_id))
                    errors += 1

                languages = list(map(lambda l: l.tag, entries))

                for language in set(languages):
                    count = languages.count(language)

                    if count > 1:
                        print("  ERROR: Key '{}' has {} {} translations.".format(key_id, count, language))
                        errors += 1

        # Verify that key IDs are unique
        for id in set(key_ids):
            count = key_ids.count(id)

            if count > 1:
                print("  ERROR: Key '{}' is defined {} times.".format(id, count))
                errors += 1

    return errors


def main():
    print("Validating Stringtables")
    print("-----------------------")

    # Allow running from root directory and tools directory
    root_dir = ".."
    if os.path.exists("addons"):
        root_dir = "."

    # Check all stringtable.xml files in the project directory
    stringtable_files = []

    for root, _, files in os.walk(root_dir):
        for file in fnmatch.filter(files, "stringtable.xml"):
            stringtable_files.append(os.path.join(root, file))

    stringtable_files.sort()

    bad_count = 0

    for filepath in stringtable_files:
        print("\nChecking {}:".format(os.path.relpath(filepath, root_dir)))

        errors = check_stringtable(filepath)

        if errors == 0:
            print("No errors found.")
        else:
            print("Found {} error(s).".format(errors))
            bad_count += 1

    print()

    if bad_count == 0:
        print("Stringtable Validation PASSED")
    else:
        print("Stringtable Validation FAILED")

    return bad_count


if __name__ == "__main__":
    sys.exit(main())