#!/usr/bin/env bash
# Desc: Prints days
# Depends: date (GNU Coreutils 8.32)
# Version: 0.0.1
# Ref/Attrib: [1] Template:This date in recent years https://en.wikipedia.org/wiki/Template:This_date_in_recent_years
#             [2] Removing leading zeros before passing a shell variable to another command https://stackoverflow.com/a/11130324

declare -g yearRange;  # range of years to consider

yell() { echo "$0: $*" >&2; }      #o Yell, Die, Try Three-Fingered Claw technique
die() { yell "$*"; exit 111; }     #o Ref/Attrib: https://stackoverflow.com/a/25515370
try() { "$@" || die "cannot $*"; } #o
vbm() {
    # Description: Prints verbose message ("vbm") to stderr if opVerbose is set to "true".
    # Usage: vbm "DEBUG :verbose message here"
    # Version 0.2.0
    # Input: arg1: string
    #        vars: opVerbose
    # Output: stderr
    # Depends: bash 5.1.16, GNU-coreutils 8.30 (echo, date)

    if [ "$opVerbose" = "true" ]; then
	functionTime="$(date --iso-8601=ns)"; # Save current time in nano seconds.
	echo "[$functionTime]:$0:""$*" 1>&2;  # Display argument text.
    fi

    # End function
    return 0; # Function finished.
} # Displays message if opVerbose true
showUsage() {
    # Desc: Display script usage information
    # Usage: showUsage
    # Version 0.0.2
    # Input: none
    # Output: stdout
    # Depends: GNU-coreutils 8.30 (cat)
    cat <<'EOF'
    USAGE:
        bk_this-date-in-recent-years.sh [ options ] [str day of month]

    OPTIONS:
        -h, --help
                Display help information.
        --version
                Display script version.
        -v, --verbose
                Display debugging info.
        -r, --iso-range
                Specify year range (iso-8601 period), e.g.
                "2010/2020". By default, most recent 10
                years are considered.
        --
                Indicate end of options.

    EXAMPLE:
      bk_this_date-in-recent-years.sh "05-11"
      bk_this_date-in-recent-years.sh -r "1990/2020" "05-11"
      bk_this_date-in-recent-years.sh -r "1990/2020" -- "05-11"
EOF
} # Display information on how to use this script.
processArgs() {
    # Desc: Processes arguments provided to script.
    # Usage: processArgs "$@"
    # Version: 1.0.0
    # Input: "$@"          (list of arguments provided to the function)
    #   yearRange            Iso date range to consider (e.g. "1999/2020").
    # Output: Sets following variables used by other functions:
    #   opVerbose            Indicates verbose mode enable status.  (ex: "true", "false")
    #   opIsoRange           Indicates that an iso-8601 date range is specified. (ex: "true", "false")
    #   yearRange            Iso date range to consider (e.g. "1999/2020").
    #   arrayPosArgs         Array of remaining positional argments
    # Depends:
    #   yell()           Displays messages to stderr.
    #   vbm()            Displays messsages to stderr if opVerbose set to "true".
    #   showUsage()      Displays usage information about parent script.
    #   showVersion()    Displays version about parent script.
    #   arrayPosArgs     Global array for storing non-option positional arguments (i.e. arguments following the `--` option).
    # External dependencies: bash (5.1.16), echo
    # Ref./Attrib.:
    #  [1]: Marco Aurelio (2014-05-08). "echo that outputs to stderr". https://stackoverflow.com/a/23550347
    #  [2]: "Handling positional parameters" (2018-05-12). https://wiki.bash-hackers.org/scripting/posparams
    
    # Initialize function
    vbm "DEBUG:processArgs function called."

    # Perform work
    while [ ! $# -eq 0 ]; do   # While number of arguments ($#) is not (!) equal to (-eq) zero (0).
	#yell "DEBUG:Starting processArgs while loop." # Debug stderr message. See [1].
        #yell "DEBUG:Provided arguments are:""$*"      # Debug stderr message. See [1].
	case "$1" in
	    -h | --help) showUsage; exit 1;; # Display usage.
	    --version) showVersion; exit 1;; # Show version
	    -v | --verbose) opVerbose="true"; vbm "DEBUG:Verbose mode enabled.";; # Enable verbose mode. See [1].
            -r | --iso-range)
                opIsoRange="true"; vbm "DEBUG:Accepting iso-8601 year range."; # Accept iso-8601 year range.
                shift;
                yearRange="$1";;
            --) # End of all options. See [2].
                shift;
                for arg in "$@"; do
                    vbm "DEBUG:adding to arrayPosArgs:$arg";
                    arrayPosArgs+=("$arg");
                done;
                break;;
            -*) showUsage; yell "ERROR: Unrecognized option."; exit 1;; # Display usage
            *) for arg in "$@"; do
                   vbm "DEBUG:adding to arrayPosArgs:$arg";
                   arrayPosArgs+=("$arg");
               done;
               break;;
	esac
	shift
    done
    
    # End function
    vbm "DEBUG:processArgs function ended."
    return  0; # Function finished.
} # Evaluate script options from positional arguments (ex: $1, $2, $3, etc.).
validatePosArgs() {
    # Input: arrayPosArgs  array with positional arguments
    #        opVerbose    bool indicates to vbm() to display verbose text
    #        opIsoRange   bool indicates to use a user-provided year range
    #        yearRange    str  iso-8601 year range provided by -r, --iso-range option
    
    # Validate year $range
    re='^[0-9]+/[0-9]+$'; # Simply check (int)/(int). Don't address Gregorian Calendar here.
    if [[ $opIsoRange == "true" && ! "$yearRange" =~ $re ]] ; then
        showUsage;
        yell "ERROR:Not a valid date range (e.g. 2010/2022):$yearRange";
        return 1;
    fi;
    return 0;
}; # Validate arguments
main() {
    # Input: arrayPosArgs  array with positional arguments
    #        opVerbose    bool indicates to vbm() to display verbose text
    #        opIsoRange   bool indicates to use a user-provided year range
    #        yearRange    str  iso-8601 year range provided by -r, --iso-range option
    # Output: stdout: dates with days of the week (newline delimited)
    # Depends: date (GNU Coreutils 8.32)
    # Depends: processArgs(), yell(), vbm(), showUsage(), showVersion(), validatePosArgs()
    local dom yc ymin ymax;

    # Check input
    processArgs "$@";
    if ! validatePosArgs; then
        die "FATAL:Invalid positional arguments:$(declare -p arrayPosArgs)";
    fi;

    # Define year range
    if [[ ! $opIsoRange == "true" ]]; then
        ## Default: Most recent 10 years
        yc="10";                 # count of years to consider
        ymax="$(date +%Y)";      # highest year to consider
        ymin="$((ymax - yc))"; # earliest year to consider
    else
        ## Provided via -r,--iso-range option
        ymin="$(echo "$yearRange" | cut -d'/' -f1)";
        ymin="$((10#$ymin))"; # strip leading zeroes. See [2]
        ymax="$(echo "$yearRange" | cut -d'/' -f2)"; # See [2]
        ymax="$((10#$ymax))"; # strip leading zeroes. See [2]
        yc="$((ymax - ymin + 1))";
    fi;
    # yell "DEBUG:ymin:$ymin";
    # yell "DEBUG:ymax:$ymax";
    # yell "DEBUG:yc  :$yc";

    # Check year range
    if ! [[ $(( ymax - ymin )) -ge 0 ]]; then die "FATAL:Invalid year range:$yearRange"; fi;
    
    # Print Output
    ## Get day of month (first positional argument)
    dom="${arrayPosArgs[0]}";
    for (( year = ymin; year <= ymax; year++ )); do
        dstr="$year-$dom";
        date +%Y-%m-%d\ %A --date="$dstr";
        # printf "DEBUG:dom :%s\n" "$dom";
        # printf "DEBUG:ymax:%s\n" "$ymax";
        # printf "DEBUG:ymin:%s\n" "$ymin";
        # printf "DEBUG:year:%s\n" "$year";
        # printf "DEBUG:dstr:%s\n" "$dstr";
    done;    
}; # main program

main "$@";



# Author: Steven Baltakatei Sandoval
# License: GPLv3+

# Ref/Attrib (depends)

    # date (GNU coreutils) 8.32
    # Copyright (C) 2020 Free Software Foundation, Inc.
    # License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
    # This is free software: you are free to change and redistribute it.
    # There is NO WARRANTY, to the extent permitted by law.

    # Written by David MacKenzie.
