#!/usr/bin/env python3
"""
Script to capitalize comments of FORD tags.
"""


import os
import re
from argparse import ArgumentParser, RawTextHelpFormatter
import difflib


USAGE = """
Capitalizes comments of FORD tags in Fortran source code.

Unless you explicitly specify to overwrite the processed file, a new file with
suffix '.cap' is created, that contains the modified source code. Should such a
file already exist, the script exits with an appropriate error message.
"""

PATTERN_SEARCH = re.compile(r"\s*!>\s*[a-zA-Z]")
PATTERN_REPLACE = re.compile(r"\s*!>\s*[a-z]")


def main():
    """Main routine."""

    args = parse_cmdline_args()

    with open(args.infile, "r", encoding="utf8") as origfile:
        content = origfile.readlines()

    mod_content = get_capitalized_content(content)

    if args.dryrun:
        diff = difflib.unified_diff(content, mod_content, n=0)
        print(''.join(list(diff)))
    else:
        fname_out = args.infile if args.overwrite else args.infile + '.cap'
        with open(fname_out, "w", encoding="utf8") as convfile:
            convfile.write("".join(mod_content))


def parse_cmdline_args():
    """Parses command line arguments."""

    parser = ArgumentParser(
        description=USAGE, formatter_class=RawTextHelpFormatter)

    msg = "source file"
    parser.add_argument("infile", action="store", type=str, help=msg)

    msg = "overwrites processed source file"
    parser.add_argument("-o", "--overwrite", action="store_true",
                        default=False, dest="overwrite", help=msg)

    msg = "performs a dry run and prints diff to stdout"
    parser.add_argument("-d", "--dry-run", action="store_true",
                        default=False, dest="dryrun", help=msg)

    args = parser.parse_args()

    # check for argument collisions
    if args.overwrite and args.dryrun:
        raise ScriptError(
            'Collision of incompatible options. A dry run and ' + \
            'simultaneously requesting to overwrite does not make sense.')

    # check for existing file
    fname_cap = args.infile + '.cap'
    if not args.overwrite and not args.dryrun and os.path.exists(fname_cap):
        raise ScriptError(f"The file '{fname_cap}' already exists, exiting.")

    return args


def get_capitalized_content(content):
    """Capitalizes comments of FORD tags.

    Args:
        content: Original content

    Returns:
        mod_content: Modified content

    """

    def convert(match):
        """Workhorse routine to convert matches."""

        orig_str = match.group()
        mod_str = orig_str[:-1] + orig_str[-1].upper()
        return mod_str

    mod_content = content.copy()

    last_matched = False

    for iline, line in enumerate(content):
        if re.match(PATTERN_REPLACE, line):
            if last_matched:
                continue
            mod_content[iline] = re.sub(PATTERN_REPLACE, convert, line)
        last_matched = bool(re.match(PATTERN_SEARCH, line))

    return mod_content


class ScriptError(Exception):
    '''Exception thrown by this script.'''


if __name__ == "__main__":
    main()
