#!python
import os
import re
import argparse

TANGLE_CMD = "tangle:"
TANGLE_REGEX = "tangle:+([^\s]+)"
BLOCK_REGEX = "~{4}|`{3}"
BLOCK_REGEX_START = "^(~{4}|`{3})"


def __get_args():
    parser = argparse.ArgumentParser(description="Tangle code blocks from Markdown file.")
    parser.add_argument("filename", type=str, help="path to Markdown file")
    parser.add_argument("-v", "--verbose", action='store_true', help="show output")
    parser.add_argument("-f", "--force", action='store_true', help="force overwrite of files")
    parser.add_argument("-s", "--separator", type=str, help="separator for tangle destinations (default=',')", default=",")
    return parser.parse_args()


def __contains_code_block_separators(line):
    line = line.lstrip(' ')
    tangle = re.search(BLOCK_REGEX_START, line)
    starts_with_separator = tangle is not None

    tangle = re.findall(BLOCK_REGEX, line)
    only_one_separator = len(tangle) == 1

    return starts_with_separator and only_one_separator


def __get_save_locations(line, separator):
    tangle = re.search(TANGLE_REGEX, line)

    if tangle is None:
        return None

    match = tangle.group(0)
    locations = match.replace(TANGLE_CMD, '')
    return locations.split(separator)


def __add_to_code_blocks(code_blocks, locations, line):
    for location in locations:
        code_blocks[location] = code_blocks.get(location, "") + line


def __map_md_to_code_blocks(filename, separator):
    md_file = open(filename, "r")
    lines = md_file.readlines()
    locations = None
    code_blocks = {}

    for line in lines:
        if __contains_code_block_separators(line):
            locations = __get_save_locations(line, separator)
        elif locations is not None:
            __add_to_code_blocks(code_blocks, locations, line)

    md_file.close()
    return code_blocks


def __create_destination(dir_name):
    os.makedirs(dir_name, exist_ok=True)


def __get_input(filename):
    return input(f"'{filename}' already exists. Overwrite? (Y/n) ")


def __print_out(key, value):
    print(f"{key:50} {len(value.splitlines())} lines")


def __save_to_file(code_blocks, verbose=False, force=False):
    for key, value in code_blocks.items():
        key = os.path.expanduser(key)
        dir_name = os.path.dirname(key)
        if dir_name is not "":
            __create_destination(dir_name)

        if os.path.isfile(key) and not force:
            overwrite = __get_input(key)
            if overwrite != "" and overwrite.lower() != "y":
                continue

        with open(key, "w") as f:
            f.write(value)
            f.close()

        if verbose:
            __print_out(key, value)


if __name__ == "__main__":
    args = __get_args()
    blocks = __map_md_to_code_blocks(args.filename, args.separator)
    __save_to_file(blocks, args.verbose, args.force)
