#!/usr/bin/python
#
# Replace string in dolfin files
#
#     dolfinreplace s0 s1 [-sv]
#
# Example:
#
#     dolfinreplace foo bar
#
# Johan Hake, 2008-19-09
#
# Modified by Anders Logg 2008, 2014

from os import path
import glob

# File post fixes to look in
post_fixes = [".h", ".cpp", ".i", ".tex", ".py", ".rst"]

# Primitive exclusion of some directories
exclude_patterns = ["build.", "local."]

# Global variables
count         = 0
changed_files = 0
report_lines = []
dolfin_root   = path.abspath(path.join(path.dirname(path.abspath(__file__)),
                                       path.pardir, path.pardir))

# Output strings
post_fix_string = ", ".join( "'%s'"%s for s in post_fixes)

start_str = """Replacing '%s' with '%s' in all %s files..."""

report_str = """
%d occurences replaced in %d files:

%s
%s"""

def replace(args, dirname, filenames):
    """ Replace replaces[0] with replaces[1]

    In all fnames with post fixes in 'post_fixes' replace replaces[0] with replaces[1]
    """
    global count, report_lines, changed_files
    (s0, s1), options = args

    _filenames = filenames[:]
    for f in _filenames:
        for exclude in exclude_patterns:
            if exclude in f:
                filenames.remove(f)

    for filename in glob.glob(path.join(dirname, options.pattern)):
        if path.splitext(filename)[1] in post_fixes:
            fullpath_filename = path.join(dirname,filename)
            f = open(fullpath_filename, "r")
            if options.verbose:
                changed_lines = []
                lines = f.readlines()
                num_changed = 0
                for i, line in enumerate(lines):
                    num = line.count(s0)
                    if num>0:
                        num_changed += num
                        changed_lines.append(" "*8+line.replace(s0,\
                                             "\033[4m%s\033[0;0m"%s0).strip())
                        lines[i] = line.replace(s0, s1)
                count += num_changed
                output = "".join(lines)
            else:
                input = f.read()
                num_changed = input.count(s0)
                count += num_changed
                output = input.replace(s0, s1)

            f.close()

            if not options.simulate and num_changed > 0:
                f = open(fullpath_filename, "w")
                f.write(output)
                f.close()

            if num_changed > 0:
                changed_files += 1
                report_lines.append(" "*4+fullpath_filename)
                if options.verbose:
                    report_lines.extend(changed_lines)
                    report_lines.append("")

def options_parser():
    import optparse
    usage ="""Usage: %prog [options] arg1 arg2

Replaces string 'arg1' with 'arg2' in files in the present directory tree.

For options, see dolfinreplace --help."""

    parser = optparse.OptionParser(usage=usage)
    parser.add_option("-s", "--simulate", help="simulate the replacement",
                      action="store_true", dest="simulate", default=False)
    parser.add_option("-p", "--pattern", help="a glob compatible pattern "
                      "for which files should be looked into. "\
                      "[default: '%default']", action="store",\
                      dest="pattern", default="*")
    parser.add_option("-v", "--verbose", help="verbosely print each line that"\
                      " includes the searched pattern.", action="store_true", \
                      dest="verbose", default=False)
    return parser

def main():
    parser = options_parser()
    options, args = parser.parse_args()

    if len(args) != 2:
        parser.error("incorrect number of arguments")

    s0, s1 = args[0].replace("\\", ""), args[1].replace("\\", "")

    print start_str%(s0,s1,post_fix_string)

    # Do it!
    path.walk(dolfin_root, replace, ((s0, s1), options))
    if count > 0:
        if options.simulate:
            simulate_str = "\nSimulating, no replacement done..."
        else:
            simulate_str = ""

        if report_lines[-1]:
            report_lines.pop(-1)

        print report_str % (count, changed_files, "\n".\
                            join(report_lines), simulate_str)
    else:
        print "Done\n\nNo occurens of '%s' found"%args[0]

if __name__ == "__main__":
    main()
