#!/bin/sh

#
# rickdate.sh v.1K34E
#
# Convert a date string to the Rickdate expression of that date.
# An explanation of Rickdate: http://yak.net/kablooey/RickDate.html
#
# Usage:
#
#     rickdate.sh "<date-string>" ["<format-string>"]
#
# Both strings should be quoted.
#
# GNU date understands most date strings without the aid of a format
# string, but BSD date does not.
#
# On BSD, a format string must be provided.  The default for this
# program is "%A, %B %e, %Y" (accepting a string like "Tuesday, January
# 1, 2019").  If you need to convert a date string in a different
# format, provide its format string as the second parameter.  See the
# strftime(3) manpage for format details.
#
# If you need a 3- or 4-character Rickdate string, pipe the output
# through cut(1) like so:
#
#     rickdate.sh "<date-string>" | cut -c 3-5  # 3-character string
#     rickdate.sh "<date-string>" | cut -c 2-5  # 4-character string
#
# Between the years 1296 and 46,655, a full Rickdate string is always
# five characters long.
#

#
# Begin License (FreeBSD 2-Clause/Simplified BSD License).
# 
# Copyright 2019 Ariel Millennium Thornton.  All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# 
# 1.  Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
# 
# 2.  Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in
#     the documentation and/or other materials provided with the
#     distribution.
# 
# THIS SOFTWARE IS PROVIDED BY ARIEL MILLENNIUM THORNTON ''AS-IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ARIEL MILLENNIUM THORNTON
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# 
# The views and conclusions contained in the software and documentation
# are those of the authors and should not be interpreted as representing
# official policies, either expressed or implied, of Ariel Millennium
# Thornton.
# 
# End License (FreeBSD 2-Clause/Simplified BSD License).
#


to36() {
  # Provided a base-10 expression of a base 36 digit, return a single
  # digit with the uppercase letters A-Z filling in positions 10-35.
  case $1 in
    00) printf "0" ;; 12) printf "C" ;; 24) printf "O" ;;
    01) printf "1" ;; 13) printf "D" ;; 25) printf "P" ;;
    02) printf "2" ;; 14) printf "E" ;; 26) printf "Q" ;;
    03) printf "3" ;; 15) printf "F" ;; 27) printf "R" ;;
    04) printf "4" ;; 16) printf "G" ;; 28) printf "S" ;;
    05) printf "5" ;; 17) printf "H" ;; 29) printf "T" ;;
    06) printf "6" ;; 18) printf "I" ;; 30) printf "U" ;;
    07) printf "7" ;; 19) printf "J" ;; 31) printf "V" ;;
    08) printf "8" ;; 20) printf "K" ;; 32) printf "W" ;;
    09) printf "9" ;; 21) printf "L" ;; 33) printf "X" ;;
    10) printf "A" ;; 22) printf "M" ;; 34) printf "Y" ;;
    11) printf "B" ;; 23) printf "N" ;; 35) printf "Z" ;;
  esac
}

from10to36() {
  # Provided an arbitrary base 10 number, convert it to a base 36
  # number.
  printf "%s\n" "obase=36; $1" | \
  bc | \
  tr ' ' '\n' | \
  while read digit
    do
      to36 "${digit}"
    done
  #
}

# Grab date string (and format string if given) from command line
datestr="$1"
datefmt="$2"
if [ -z "${datestr}" ]
  then
    echo "Error: no date string was given." >&2
    echo "Usage: $0 \"<date string>\" [\"<date format string>\"]" >&2
    exit 1
  fi

# Set IFS: we need a space field separator
IFS=$' \t\n'

# Detect if date is GNU Date or BSD Date, and turn date string into
# YYYY-MM-DD format
ver=`date --version 2>/dev/null`
if [ -z "${ver}" ]
  then
    # BSD Date
    if [ -z "${datefmt}" ]
      then
        datefmt="%A, %B %e, %Y"
        fi
      #
    ymd=`date -j -f "${datefmt}" "${datestr}" "+%F" 2>/dev/null`
  else
    # GNU Date
    ymd=`date --date="${datestr}" --iso-8601 2>/dev/null`
  fi

if [ -z "${ymd}" ]
  then
    echo "Error: date string could not be turned into Y-M-D format." >&2
    echo "Usage: $0 \"<date string>\" [\"<date format string>\"]" >&2
    exit 1
  fi

# Turn YYYY-MM-DD string into Rickdate format
yr=${ymd%%-*}   # match {[YYYY]-MM-DD}
md=${ymd#*-}    # match {YYYY-[MM-DD]}
mo=${md%-*}     # match YYYY-{[MM]-DD}
da=${md#*-}     # match YYYY-{MM-[DD]}
# Translate each decimal number to a base 36 number
yrr=`from10to36 ${yr}`
mor=`from10to36 ${mo}`
dar=`from10to36 ${da}`
# A Rickdate string is the three base-36 numbers run together
rickdate="${yrr}${mor}${dar}"

# Print the Rickdate string
if [ -z "${rickdate}" ]
  then
    echo "Error: unable to turn date string into rickdate." >&2
    exit 1
  else
    echo "${rickdate}"
  fi

exit 0

