#!/usr/bin/env bash
# Desc: Rename files to remove common prefix
# Usage: triml.sh [FILE] ([FILE]…)
# Example: triml.sh ./*.txt
# Version: 0.0.1

yell() { echo "$0: $*" >&2; } # print script path and all args to stderr
die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status
must() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails
get_prefix() {
    # Desc: Iteratively identify common prefix
    # Input: "$@"  arguments
    # Output: stdout
    local prefix="$1"; # start with first arg
    shift; # don't compare first to first
    for arg in "$@"; do
        while [[ "$arg" != "$prefix"* ]]; do
            prefix="${prefix%?}"; # trim end of prefix if match
        done;
    done;
    printf "%s" "$prefix";
}; # Get common prefix of arguments
show_usage() {
    # Desc: Display script usage information
    # Usage: show_usage
    # Version 0.0.2
    # Input: none
    # Output: stdout
    # Depends: GNU-coreutils 8.30 (cat)
    cat <<'EOF'
    USAGE:
        triml.sh FILE [FILE…]

    OPTIONS:
        (none)

    EXAMPLE:
      triml.sh
      triml.sh ./*.txt
EOF
} # Display information on how to use this script.
prompt_continue() {
    # Desc: Prompt user to go approve/disapprove or list files to be moved.
    while true; do
        read -rp "Rename ${#args[@]} files? (y/N or l/list): " choice;
        case "${choice,,}" in
            y|yes)
                yell "STATUS:Renaming...";
                return 0;
                ;;
            l|list)
                for i in "${!args[@]}"; do
                    yell "Rename: ${args[i]} -> ${args_defront[i]}";
                done;
                ;;
            n|no)
                die "FATAL:Operation aborted.";
                ;;
            *)
                yell "Invalid option.";
        esac;
    done;
}; # prompt user to continue operation
main () {
    declare -a args args_defront;
    declare prefix;
    declare path_dir name_file name_file_new;
    
    # Check if no arguments are passed
    if [[ "$#" -le 0 ]]; then
        ## Act on working dir files
        mapfile -t args < <(find . -mindepth 1 -maxdepth 1 -type f);
    else
        ## Act on argument-specified file paths
        args=("$@");
    fi;

    # Check that all args are file paths
    for arg in "${args[@]}"; do
        if [[ ! -f "$arg" ]]; then
            show_usage;
            die "FATAL:Not a file:${arg}"; fi;
    done;
    
    # Get common prefix of all file basenames
    ## Assemble directory paths and file name arrays
    for i in "${!args[@]}"; do
        #args_path[i]="$(dirname "${args[i]}")";
        args_file[i]="$(basename "${args[i]}")";
    done;
    prefix="$(get_prefix "${args_file[@]}")";
    #declare -p args prefix; # debug
    if [[ "${#prefix}" -le 0 ]]; then
       #declare -p prefix; # debug
       die "FATAL:No file prefix found."; fi;

    # Assemble paths with defronted basenames
    for i in "${!args[@]}"; do
        path_dir="$(dirname "${args[i]}")";
        name_file="$(basename "${args[i]}")";
        name_file_new="${name_file#"${prefix}"}";
        args_defront[i]="${path_dir}/${name_file_new}";
    done;
    
    # Throw rename warning
    must prompt_continue;
    
    # Rename files to defront prefix
    for i in "${!args[@]}"; do
        if mv -n "${args[i]}" "${args_defront[i]}"; then
            yell "STATUS:Moved ${args[i]} to ${args_defront[i]}";
        else
            die "FATAL:Failed to move ${args[i]} to ${args_defront[i]}";
        fi;
    done;
};
main "$@";

# Author: Steven Baltakatei Sandoval
# License: GPLv3+
