#!/bin/env python3

"""
This file is partly based on the following two examples:

 - https://github.com/aroberge/ideas/blob/master/ideas/examples/french.py
 - https://stackoverflow.com/a/43573798
"""


import sys
import os
import token_utils
import importlib
import code
from importlib.abc import MetaPathFinder, Loader
from importlib.util import spec_from_file_location

py_to_nl = {
    "and" : "en",
    "as" : "als",
    "assert" : "eis",
    "async" : "async",
    "await" : "wachtop",
    "break" : "stop",
    "case" : "geval",
    "class" : "klasse",
    "continue": "doorgaan",
    "def": "def",
    "del": "verwijder",
    "if": "indien",
    "elif": "andien",
    "else": "anders",
    "except": "behalve",
    "False": "Onwaar",
    "finally": "uiteindelijk",
    "for": "voor",
    "from": "van",
    "global": "globaal",
    "import": "importeer",
    "in": "in",
    "is": "is",
    "lambda": "lambda",
    "match": "vergelijk",
    "None": "Niets",
    "nonlocal": "nietlokaal",
    "not": "niet",
    "or": "of",
    "pass": "pas",
    "raise": "hef",
    "return": "retour",
    "True": "Waar",
    "try": "probeer",
    "type": "type",
    "while": "zolang",
    "with": "met",
    "yield": "lever",
}

nl_to_py = {nl_kwd: py_kwd for py_kwd, nl_kwd in py_to_nl.items()}


def translate_token(token, translations):
    try:
        token.string = translations[token.string]
    except KeyError:
        pass

    return token


def translate_source(source, translations = nl_to_py):
    source_tokens = token_utils.tokenize(source)
    translated_tokens = [translate_token(token, translations) for token in source_tokens]
    return token_utils.untokenize(translated_tokens)
    

class PynlMetaPathFinder(MetaPathFinder):
    def find_spec(self, fullname, path, target=None):
        if path is None or path == "":
            path = [os.getcwd()] # top level import -- 
        if "." in fullname:
            *parents, name = fullname.split(".")
        else:
            name = fullname
        for entry in path:
            if os.path.isdir(os.path.join(entry, name)):
                # this module has child modules
                filename = os.path.join(entry, name, "__init__.pynl")
                submodule_locations = [os.path.join(entry, name)]
            else:
                filename = os.path.join(entry, name + ".pynl")
                submodule_locations = None
            if not os.path.exists(filename):
                continue

            return spec_from_file_location(fullname, filename, loader=PynlLoader(filename),
                submodule_search_locations=submodule_locations)

        return None # we don't know how to import this

class PynlLoader(Loader):
    def __init__(self, filename):
        self.filename = filename

    def create_module(self, spec):
        return None # use default module creation semantics

    def exec_module(self, module):
        with open(self.filename) as f:
            source = f.read()

        translated = translate_source(source, translations=nl_to_py)

        exec(translated, vars(module))


def exec_main(location, args):
    with open(location) as f:
        source = f.read()

    translated = translate_source(source, translations=nl_to_py)
    exec(translated, {'argv_external': [location] + args, '__name__': '__main__'})


def main():
    sys.meta_path.insert(0, PynlMetaPathFinder())

    # clear any caches
    sys.path_importer_cache.clear()
    importlib.invalidate_caches()

    try:
        # inject external arguments into the script
        if argv_external == []:
            sys.argv = sys.argv[:1] # Remove arguments from sys.argv besides filename
        else:
            for idx, x in enumerate(argv_external):
                sys.argv[idx] = x
    except NameError:
        pass
    
    try:
        location = sys.argv[1]
        exec_main(location, sys.argv[2:])
    except IndexError:
        # Also geen files start dan maar de pythonl shell
        shell = code.InteractiveConsole(locals=globals())
        native_compile = shell.compile

        def compile(code, file, lines):
            code = translate_source(code)
            return native_compile(code,file,lines)

        shell.compile = compile
        shell.interact(banner=f"Pythonl (0.1.0) interactive shell {sys.version}")
    
if __name__ == '__main__':
    main()
