#!/usr/bin/env python

from __future__ import print_function

import os


def strip_file(filename, write, report):
    # .readlines() retains \n chars, while .read().splitlines() does not.
    # Assuming that whitespace errors will be few, we will thus only need
    # to re-add \n to a few right-stripped lines. The hit flag will keep us
    # from unnecessarily re-writing files with no changes.

    # newline="" keeps current line endings
    with open(filename, newline="") as f:
        lines = f.readlines()
    hit = False
    cr = False
    extra = 0
    for index, line in enumerate(lines):
        if line.endswith(" \n"):
            if report:
                print("%s, line %s" % (filename, index + 1))
            if write:
                lines[index] = line.rstrip() + "\n"
                hit = True
        if line.endswith("\r\n"):
            if report and not cr:
                print("%s, line %s (crlf now silent)" % (filename, index + 1))
                cr = True
            if write:
                lines[index] = line.rstrip() + "\n"
                hit = True

    # correct no newline at eof
    if lines and not lines[-1].endswith("\n"):
        lines[-1] += "\n"
        if report:
            print("%s, no newline at eof" % filename)
        if write:
            hit = True

    # correct multiple newlines at eof
    while len(lines) > 1 and lines[-1] == "\n" and lines[-2].endswith("\n"):
        if write:
            hit = True
        lines.pop()
        extra += 1

    if extra > 0 and report:
        print("%s, %d extra newlines at eof" % (filename, extra))

    if write and hit:
        # newline="" leaves line endings unchanged
        with open(filename, "w", newline="") as f:
            f.writelines(lines)


def go(path, write, report):
    allowed_ext = [
        ".cpp",
        ".cc",
        ".h",
        ".py",
        ".rst",
    ]
    for root, dirs, files in os.walk(path):
        for b in [".git"]:
            if b in dirs:
                dirs.remove(b)
        for file in files:
            if os.path.splitext(file)[1] not in allowed_ext:
                continue
            filename = os.path.join(root, file)
            strip_file(filename, write, report)


def main():
    from optparse import OptionParser
    p = OptionParser("usage: %prog [options] filename")
    p.add_option("-d", "--dry", action="store_true", dest="dry",
                 help="Do not modify files.")
    p.add_option("-v", "--verbose", action="store_true", dest="verbose",
                 help="Report all changes.")
    p.add_option("-r", "--recursive", action="store_true", dest="recursive",
                 help="Recursively correct all files in a directory.")
    options, args = p.parse_args()
    if options.dry:
        options.verbose = True
    if len(args) == 1:
        if options.recursive:
            go(args[0], not options.dry, options.verbose)
        else:
            strip_file(args[0], not options.dry, options.verbose)
    else:
        p.print_help()

if __name__ == "__main__":
    main()
