#!/usr/bin/env sh
# shows due entries of bibtex file passed in
# HACK: brittle! will break on various bibfile abnormities (even just on due date w/o priority)
# FIXME: reimplementation with real library needed
#

OPTIND=1 # Reset in case getopts has been used previously in the shell.
fields="due|priority|\bauthor\b|\btitle\b"
filterby="due"
file="${BIBFILE}"
until=""

show_help() {
  printf "%s\n" \
    "" \
    " bib-due       Show due readings from bibtex file." \
    "" \
    " Usage: bib-due [-hv] -i input.bib -r 'due|priority|\bauthor|\btitle' -l 'due' -u '2020-05-12'" \
    "" \
    " Options:" \
    "" \
    "     -i [bibtex-file]                    Input bibtex file to scrape and get items from." \
    "" \
    "     -r [fields]                         Field values to read in file." \
    "" \
    "     -l [filter]                         Field to use as filter entity." \
    "                                         This field is required for the scraper to pick entries up." \
    "" \
    "     help    | -h | --help               Print out this help." \
    "" \
    " Invoked without arguments, bib-due will scrape the file defined in BIBFILE environment variable, " \
    " filtering entries with the 'due' field, and getting the values for 'due', 'priority', 'author', " \
    " and 'title' fields. It will then print the entries to stdout." \
    "" \
    " Example output line:" \
    "" \
    ' 2020-06-25 (1): Sergei Gerasymchuk -- “Ze” time in Ukraine (Gerasymchuk2019) ' \
    ""
}

filter_until() {
  # filter for dates, with line numbers
  filtered=$(echo "$entries" | grep -noE '[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}')

  # redirect entries to fifo pipe
  mkfifo filteredentries
  finish() {
    rm filteredentries
  }
  trap finish EXIT
  echo "$filtered" >filteredentries &

  # find first date past until filter
  lastline=""
  while IFS= read -r line; do
    cond=$(printf '%s' "$line" | cut -d: -f2)
    cond=$(date -d "$cond" +%s)
    if [ "$cond" -gt "$until" ]; then
      lastline=$(printf '%s' "$line" | cut -d: -f1)
      break
    fi
  done <filteredentries

  # special cases all in filter, or none in filter
  if [ -z "$lastline" ]; then
    return
  elif [ "$lastline" -eq 1 ]; then
    entries=""
  # filter
  else
    # remove lines below found
    lastprinted="$((lastline - 1))"
    entries=$(echo "$entries" | sed -n "1,${lastprinted}p;${lastline}q")
  fi
}

filter_priority() {
  priority="$1"
  # filter for dates, with line numbers
  # filtered=$(echo "$entries" | grep -noE '[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}')
  filtered=""
  while [ "$priority" -gt 0 ]; do
    current=$(echo "$entries" | grep -E "\($priority\)")

    # append found to filtered entries
    filtered=$(printf "%s\n%s" "$filtered" "$current")

    # go to next 'higher' priority
    priority="$((priority - 1))"
  done
  # sort them chronologically again, remove empty lines
  entries="$(echo "$filtered" | sed -e '/^$/d' | sort)"
}

main() {
  if [ -z "$file" ]; then
    echo "Requires a bibtex file as argument."
    exit 1
  fi

  # filter all entries for those containing filterby field (default: due)
  # retain values of all fields mentioned in fields variable
  entries=$(grep -E "^@|$fields" "$file" | awk 1 ORS=' ' | sed -E 's/@\w+\{/\n/g' | grep "$filterby" | tail -n +2 | sed -E 's/(,\s+(\w+)\s+=\s+|,\s*$)/\t/g' | awk -F'\t' '{ print $4 "\t" $5 "\t" $2 "\t" $3 "\t" $1 }')

  # prettify and sort the entries for display (remove {}, order by date,prio,author,title)
  entries=$(echo "$entries" | awk -F'\t' '{ gsub(/{/,""); gsub(/}/,""); gsub(/prio/,"",$2) } { print $1 " (" $2 "): " $3 " -- " $4 " (" $5 ")"}' | sort)

  if [ -n "$until" ]; then
    filter_until
  fi
  if [ -n "$priority" ]; then
    filter_priority "$priority"
  fi

  echo "$entries"
}

while getopts "h?i:u:r:l:p:" opt; do
  case "$opt" in
  h | \?)
    show_help
    exit 0
    ;;
    # v)  verbose=1
    # ;;
  r)
    fields="$OPTARG"
    ;;
  l)
    filterby="$OPTARG"
    ;;
  i)
    file="$OPTARG"
    ;;
  u)
    until="$(date -d "$OPTARG" +%s)"
    ;;
  p)
    priority="$OPTARG"
    ;;
  esac
done
shift $((OPTIND - 1))

[ "${1:-}" = "--" ] && shift

main "$@"
