#!/usr/bin/python3
import functools
import re
from typing import List, Tuple

import itertools

GET_VARS = re.compile(r'VAR(_INPUT|_OUTPUT)? *(?P<v>[^ ]+) *: *.* *END_VAR')


def get_vars(string: str) -> List[str]:
    matches = GET_VARS.finditer(string)
    return [m.group('v').replace('$',r'\$') for m in matches]


def prefix_vars(string: str, prefix: str, variables: List[str]) -> str:
    findre = re.compile(r'(?<=[ ()\f\t\n])(%s)(?=[.,() \t\f\n;])' % '|'.join(variables))

    # prefixer = lambda m: prefix + m.group()
    def prefixer(m):
        print(m.group())
        return " %s%s " % (prefix, m.group().strip())

    return findre.sub(prefixer, string)

def split_decl_impl(string : str):
    # delete first and last line ({END_}FUNCTION BLOCK)
    string = string.replace("END_FUNCTION_BLOCK", "")
    string = re.sub(r'FUNCTION_BLOCK \w+', '', string)
    return string .split("// impl")


def prepare(string, prefix="_"):
    v = get_vars(string)
    n = prefix_vars(string, prefix, v)
    return n

from itertools import starmap


def product_program(programs : Tuple[str],
                    prefixes : Tuple[str]) -> str:
    comment = "\n\n//"+ '-' * 80 + "\n\n"

    pp = starmap(prepare, zip(programs, prefixes))
    spp = list(map(split_decl_impl, pp))
    decls = (a[0] for a in spp)
    impls = (a[1] for a in spp)

    return """PROGRAM product \n %s %s \n END_PROGRAM""" % \
        (comment.join(decls), comment.join(impls))





if __name__ == '__main__':
    with open("exp_if_5/Preamble.st") as fh:
        preamble = fh.read()

    with open("exp_if_5/SelfComp_5.st", 'w') as out:
        with open("exp_if_5/Code_5.st") as fh:
            code13 = fh.read()
            out.write(preamble)
            out.write("\n\n\n")
            out.write(product_program((code13,code13), ("a_", "b_")))

    with open("exp_if/Preamble.st") as fh:
        preamble = fh.read()

    with open("exp_if/SelfComp_13.st", 'w') as out:
        with open("exp_if/Code_13.st") as fh:
            code13 = fh.read()
            out.write(preamble)
            out.write("\n\n\n")
            out.write(product_program((code13,code13), ("a_", "b_")))

    with open("exp_rvdv/Preamble.st") as fh:
        preamble = fh.read()

    with open("exp_rvdv/Product_35.st", 'w') as out:
        with open("exp_rvdv/Code_3.st") as fh:
            code3 = fh.read()

        with open("exp_rvdv/Code_5.st") as fh:
            code5 = fh.read()

        out.write(preamble)
        out.write("\n\n\n")
        out.write(product_program((code3, code5), ("_old__", "_new__")))
