#!/usr/bin/env python
from __future__ import print_function, unicode_literals

import argparse
import os
import re
import sys


DESCRIPTION = """\
Migrate arbitrary `.go` sources from the pre-v2.0.0 API for StringSlice and
IntSlice types, optionally writing the changes back to file.
"""
SLICE_TYPE_RE = re.compile(
    '&cli\\.(?P<type>IntSlice|StringSlice){(?P<args>[^}]*)}',
    flags=re.DOTALL
)


def main(sysargs=sys.argv[:]):
    parser = argparse.ArgumentParser(
        description=DESCRIPTION,
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('basedir', nargs='?', metavar='BASEDIR',
        type=os.path.abspath, default=os.getcwd())
    parser.add_argument('-w', '--write', help='write changes back to file',
        action='store_true', default=False)

    args = parser.parse_args(sysargs[1:])

    for filepath in _find_candidate_files(args.basedir):
        updated_source = _update_source(filepath)
        if args.write:
            print('Updating {!r}'.format(filepath))

            with open(filepath, 'w') as outfile:
                outfile.write(updated_source)
        else:
            print('// -> Updated {!r}'.format(filepath))
            print(updated_source)

    return 0


def _update_source(filepath):
    with open(filepath) as infile:
        source = infile.read()
        return SLICE_TYPE_RE.sub(_slice_type_repl, source)


def _slice_type_repl(match):
    return 'cli.New{}({})'.format(
        match.groupdict()['type'], match.groupdict()['args']
    )


def _find_candidate_files(basedir):
    for curdir, dirs, files in os.walk(basedir):
        for i, dirname in enumerate(dirs[:]):
            if dirname.startswith('.'):
                dirs.pop(i)

        for filename in files:
            if not filename.endswith('.go'):
                continue

            filepath = os.path.join(curdir, filename)
            if not os.access(filepath, os.R_OK | os.W_OK):
                continue

            yield filepath


if __name__ == '__main__':
    sys.exit(main())