#! /usr/bin/env python3

import argparse
import os
import errno
import re
import shutil
import sys


def copyFileOrDirectory(oldName, newName):
    """duplicate a file or directory
    """
    try:
        shutil.copytree(oldName, newName)
    except OSError as exc:
        if exc.errno == errno.ENOTDIR:
            shutil.copy(oldName, newName)
        else:
            raise # let the caller deal with any other exception


def findOldVersions(dir_, fname, extn):
    """returns the numbers of all previous verions of `fname` in `dir_`
    """
    result = []
    for dirMember in os.listdir(dir_):
        (fnameMember, extnMember) = os.path.splitext(dirMember)
        if fnameMember.startswith(fname) and extnMember == extn:
            matchObj = re.match(r'(.*)_(\d+)$', fnameMember)
            if matchObj and matchObj.group(1) == fname:
                result.append(int(matchObj.group(2)))
    return sorted(result)


def parseArguments():
    """parse the command line arguments
    """
    parser = argparse.ArgumentParser()
    parser.add_argument("filename", nargs='+',
            help='name(s) of files to version')
    parser.add_argument("-n", "--no-copy",
            dest='noCopy',
            action='store_true',
            help="rename, don't copy, the original version to the new version")
    parser.add_argument("--dry-run",
            dest='dryRun',
            action='store_true',
            help="print the operations (as shell commands), but don't do them")
    return parser.parse_args()


def main():
    args = parseArguments()
    for oldFname in args.filename:
        if not os.path.exists(oldFname):
            print(f"\"{oldFname}\" does not exist -- skipping", file=sys.stderr)
            continue
        (basePath, extn) = os.path.splitext(oldFname)
        baseDir = os.path.dirname(basePath)
        baseFname = os.path.basename(basePath)

        if baseDir == "":
            baseDir = os.path.curdir

        versions = findOldVersions(baseDir, baseFname, extn)
        # rename old versions in descending order
        for version in versions[::-1]:
            oldFname0 = "".join([basePath, f"_{version}", extn])
            newFname0 = "".join([basePath, f"_{version+1}", extn])
            if args.dryRun:
                print(f"mv {oldFname0} {newFname0}")
            else:
                os.rename(oldFname0, newFname0)

        newFname = "".join([basePath, "_1", extn])
        if args.noCopy:
            if args.dryRun:
                print(f"mv {oldFname} {newFname}")
            else:
                os.rename(oldFname, newFname)
        else:
            if args.dryRun:
                print(f"cp {oldFname} {newFname}")
            else:
                copyFileOrDirectory(oldFname, newFname)


main()
