#!/bin/sh
#
# Script to make entering and progressing "todo" items easier.
#
# The issues are contained in a todo.db file, as a sequence of lines of
# tab-separated fields:
#
#   - username (of user who created the entry)
#   - priority (a number)
#   - one-line description
#   - reference (preferrably a URL)
#   - owned by
#   - raised on (date)
#   - resolved on (date)
#   - comments
#   - resolution (describe what was done)
#

ISSUES=`dirname $0`/../DOC/todo.db
HTML=`dirname $0`/../DOC/todo.srb
DATEFRM="+%d %b %Y"
ARCH=`uname`
PAGER=${PAGER:-more}
WHO=`whoami`


pr ()
{
  if [ $ARCH = "Linux" ]; then
    echo -e "$*"
  else
    echo "$*"
  fi
}

prn ()
{
  if [ $ARCH = "Linux" ]; then
    echo -e "$*\c"
  else
    echo "$*\c"
  fi
}

quick_help ()
{
  pr
  pr "\tThis program updates todo.db and todo.srb"
  pr
  pr "\tTo see the issues (plain text):    todo -l"
  pr "\tTo see the issues (HTML table):    todo -g"
  pr "\tTo see the unresolved issues:      todo -t"
  pr "\tTo enter a new issue:              todo -a [reference [description]]"
  pr "\tTo add a comment to an issue:      todo -c [number [comment]]"
  pr "\tTo assign an issue to somebody:    todo -o [number [name]]"
  pr "\tTo release ownership of an issue:  todo +o [number]"
  pr "\tTo raise the priority of an issue: todo +1 [number]"
  pr "\tTo lower the priority of an issue: todo -1 [number]"
  pr "\tTo resolve an issue:               todo -r [number [resolution-text]]"
  pr "\tTo be prompted for all arguments:  todo"
  pr "\tTo get quick help:                 todo -?"
  pr
  pr "\tYou'll be prompted for all missing arguments"
  pr
}

print_issue ()
{
     pr "Number          : $i"
     pr "Priority        : $prio"
     pr "Description     : $desc"
     pr "Reference       : $ref"
     pr "Owner           : $own"
     pr "Archived on     : $date1"
     pr "Resolved on     : $date2"
     pr "Comments        : $comment"
     pr "Resolution      : $res"
     pr
}

list_issues ()
{
  (
    IFS='	'
    i=0
    while read who prio desc ref own date1 date2 comment res; do
      i=`expr $i + 1`
      print_issue
    done
  ) < $ISSUES
}

list_unresolved ()
{
  (
    IFS='	'
    i=0
    while read who prio desc ref own date1 date2 comment res; do
      i=`expr $i + 1`
      if [ "$res" = "-" ]; then print_issue; fi
    done
  ) < $ISSUES
}


list_issue ()
{
  if [ -z "$num" ]; then
    prn "Number: "
    read num
  fi
  case "$num" in
    [0-9] | [0-9][0-9] | [0-9][0-9][0-9] | [0-9][0-9][0-9][0-9]) ;;
    *) pr "Error: not a valid issue number: $num" >&2; return 2;;
  esac
  (
    IFS='	'
    i=0
    while read who prio desc ref own date1 date2 comment res1; do
      i=`expr $i + 1`
      if [ "$i" = "$num" ]; then
	print_issue
        exit 0
      fi
    done < $ISSUES
  )
}

generate_html ()
{
  echo "<table cellpadding=0 cellspacing=0 border=0>"
  echo "<tr style='color:#44a'><th align=left>&nbsp;prio <th>#"
  echo "  <th align=left>&nbsp;Owner"
  echo "  <th align=left>&nbsp;Entered <th align=left>&nbsp;Resolved"
  echo "<tr><td colspan=5>&nbsp;"
  (
    IFS='	'
    i=0
    while read who prio desc ref own date1 date2 comment res; do
      i=`expr $i + 1`
      echo "<tr valign=center bgcolor='#ffffbb'><!-- $who -->"
      prn "  <td style='background:#44a'>&nbsp;<span style='color:red'>"
      j=0;
      while [ $j -lt "$prio" ]; do
	prn "*"
	j=`expr $j + 1`
      done
      echo "</span>"
      echo "  <td align=right style='background:#44a'><strong style='color:white;font-size:larger'>$i</strong>&nbsp;"
      echo "  <td>&nbsp;$own"
      echo "  <td>&nbsp;$date1"
      echo "  <td>&nbsp;$date2"
      echo "<tr valign=baseline>"
      echo "  <th colspan=2 align=right>Description:&nbsp;<td colspan=3>$desc"
      echo "<tr valign=baseline>"
      prn "  <th colspan=2 align=right>Reference:&nbsp;<td colspan=3>"
      case "$ref" in
	http:* | ftp:*) echo "<a href='$ref'>here</a>";;
	*) echo "$ref";;
      esac
      echo "<tr valign=baseline>"
      echo "  <th colspan=2 align=right>Comment:&nbsp;<td colspan=3>$comment"
      echo "<tr valign=baseline>"
      echo "  <th colspan=2 align=right>Resolution:&nbsp;<td colspan=3>$res"
    done <$ISSUES
  )
  echo "</table>"
  set -- `ls -l $ISSUES`
  echo "<p>Last update: "`ls -l $ISSUES | cut -c 42-48`\
   " (HTML version generated: "`date "$DATEFRM"`")"
  return
}

add_issue ()
{
  if [ -z "$ref" ]; then
    prn "Reference (URL): "
    read ref
  fi
  if [ -z "$desc" ]; then
    prn "Description: "
    read desc
  fi
  ref=`echo $ref | tr "&	" "  "`
  desc=`echo $desc | tr "&	" "  "`
  date=`date "$DATEFRM"`
  cp $ISSUES $ISSUES.bak
  (
    cat $ISSUES.bak
    pr "$WHO	0	$desc	$ref	-	$date	-	-	-"
  ) >$ISSUES
}

resolve_issue ()
{
  if [ -z "$num" ]; then
    prn "Number: "
    read num
  fi
  case "$num" in
    [0-9] | [0-9][0-9] | [0-9][0-9][0-9] | [0-9][0-9][0-9][0-9]) ;;
    *) pr "Error: not a valid issue number: $num" >&2; return 2;;
  esac
  if [ -z "$res" ]; then
    prn "Resolution: "
    read res
  fi
  res=`echo $res | tr "&	" "  "`
  date=`date "$DATEFRM"`
  cp $ISSUES $ISSUES.bak
  (
    IFS='	'
    i=0
    while read who prio desc ref own date1 date2 comment res1; do
      i=`expr $i + 1`
      if [ "$i" != "$num" ]; then
	pr "$who	$prio	$desc	$ref	$own	$date1	$date2	$comment	$res1"
      elif [ "$res1" = "-" ]; then
	pr "$who	$prio	$desc	$ref	$own	$date1	$date	$comment	$res"
      else
	pr "$who	$prio	$desc	$ref	$own	$date1	$date2	$comment	$res1"
	pr "Error: Issue was already resolved. Not changed." >&2
      fi
    done < $ISSUES.bak >$ISSUES
  )
}

add_comment ()
{
  if [ -z "$num" ]; then
    prn "Number: "
    read num
  fi
  case "$num" in
    [0-9] | [0-9][0-9] | [0-9][0-9][0-9] | [0-9][0-9][0-9][0-9]) ;;
    *) pr "Error: not a valid issue number: $num" >&2; return 2;;
  esac
  if [ -z "$comment" ]; then
    prn "Comment: "
    read comment
  fi
  comment=`echo $comment | tr "&	" "  "`
  date=`date "$DATEFRM"`
  cp $ISSUES $ISSUES.bak
  (
    IFS='	'
    i=0
    while read who prio desc ref own date1 date2 comment1 res; do
      i=`expr $i + 1`
      if [ "$i" = "$num" ]; then
	if [ "$comment1" = "-" ]; then comment1=; fi
	pr "$who	$prio	$desc	$ref	$own	$date1	$date2	$comment1 $comment ($date).	$res"
      else
	pr "$who	$prio	$desc	$ref	$own	$date1	$date2	$comment1	$res"
      fi
    done < $ISSUES.bak >$ISSUES
  )
}

add_owner ()
{
  if [ -z "$num" ]; then
    prn "Number: "
    read num
  fi
  case "$num" in
    [0-9] | [0-9][0-9] | [0-9][0-9][0-9] | [0-9][0-9][0-9][0-9]) ;;
    *) pr "Error: not a valid issue number: $num" >&2; return 2;;
  esac
  if [ -z "$own" ]; then
    prn "Owner: "
    read own
  fi
  own=`echo $own | tr "&	" "  "`
  cp $ISSUES $ISSUES.bak
  (
    IFS='	'
    i=0
    while read who prio desc ref own1 date1 date2 comment res; do
      i=`expr $i + 1`
      if [ "$i" = "$num" ]; then
	pr "$who	$prio	$desc	$ref	$own	$date1	$date2	$comment	$res"
      else
	pr "$who	$prio	$desc	$ref	$own1	$date1	$date2	$comment	$res"
      fi
    done < $ISSUES.bak >$ISSUES
  )
}

remove_owner ()
{
  if [ -z "$num" ]; then
    prn "Number: "
    read num
  fi
  case "$num" in
    [0-9] | [0-9][0-9] | [0-9][0-9][0-9] | [0-9][0-9][0-9][0-9]) ;;
    *) pr "Error: not a valid issue number: $num" >&2; return 2;;
  esac
  cp $ISSUES $ISSUES.bak
  (
    IFS='	'
    i=0
    while read who prio desc ref own1 date1 date2 comment res; do
      i=`expr $i + 1`
      if [ "$i" = "$num" ]; then
	pr "$who	$prio	$desc	$ref	-	$date1	$date2	$comment	$res"
      else
	pr "$who	$prio	$desc	$ref	$own1	$date1	$date2	$comment	$res"
      fi
    done < $ISSUES.bak >$ISSUES
  )
}

inc_prio ()
{
  if [ -z "$num" ]; then
    prn "Number: "
    read num
  fi
  case "$num" in
    [0-9] | [0-9][0-9] | [0-9][0-9][0-9] | [0-9][0-9][0-9][0-9]) ;;
    *) pr "Error: not a valid issue number: $num" >&2; return 2;;
  esac
  cp $ISSUES $ISSUES.bak
  (
    IFS='	'
    i=0
    while read who prio desc ref own1 date1 date2 comment res; do
      i=`expr $i + 1`
      if [ "$i" = "$num" ]; then
	prio=`expr $prio + 1`
	pr "$who	$prio	$desc	$ref	$own1	$date1	$date2	$comment	$res"
      else
	pr "$who	$prio	$desc	$ref	$own1	$date1	$date2	$comment	$res"
      fi
    done < $ISSUES.bak >$ISSUES
  )
}

dec_prio ()
{
  if [ -z "$num" ]; then
    prn "Number: "
    read num
  fi
  case "$num" in
    [0-9] | [0-9][0-9] | [0-9][0-9][0-9] | [0-9][0-9][0-9][0-9]) ;;
    *) pr "Error: not a valid issue number: $num" >&2; return 2;;
  esac
  cp $ISSUES $ISSUES.bak
  (
    IFS='	'
    i=0
    while read who prio desc ref own1 date1 date2 comment res; do
      i=`expr $i + 1`
      if [ "$i" = "$num" ]; then
	prio=`expr $prio - 1`
	pr "$who	$prio	$desc	$ref	$own1	$date1	$date2	$comment	$res"
      else
	pr "$who	$prio	$desc	$ref	$own1	$date1	$date2	$comment	$res"
      fi
    done < $ISSUES.bak >$ISSUES
  )
}

interactive ()
{
  while [ "$reply" != 'q' ]; do
    reply=
    pr
    pr "Choose one of:"
    while [ "$reply" = "" ]; do
      pr "	l	list the issues"
      pr "	i	list a specific issue"
      pr "	t	list only unresolved issues"
      pr "	a	add an issue"
      pr "	c	add a comment to an issue"
      pr "	o	assign an owner to an issue"
      pr "	+	raise the priority of an issue"
      pr "	-	lower the priority of an issue"
      pr "	r	mark an issue as resolved"
      pr "	q	quit"
      prn "? "
      read reply
      case "$reply" in
	l) list_issues | $PAGER;;
	i) num=; list_issue ;;
	a) ref=; desc=; add_issue;;
	c) num=; comment=; add_comment;;
	o) num=; own=; add_owner;;
	+) num=; inc_prio;;
	-) num=; dec_prio;;
	r) num=; res=; resolve_issue;;
	t) list_unresolved | $PAGER;;
	q) ;;
	*) pr "Not understood, please try again"; reply=;;
      esac
    done
  done
}  

if [ ! -f $ISSUES ]; then
  touch $ISSUES
fi
if [ $# = 0 ]; then
  interactive
else
  case "$1" in
    -l) list_issues;;
    -i) num=$2; shift 2; list_issue;;
    -a) ref=$2; shift 2; desc="$*"; add_issue;;
    -c) num=$2; shift 2; comment="$*"; add_comment;;
    -o) num=$2; shift 2; own="$*"; add_owner;;
    +o) num=$2; remove_owner;;
    +1) num=$2; inc_prio;;
    -1) num=$2; dec_prio;;
    -r) num=$2; shift 2; res="$*"; resolve_issue;;
    -g) generate_html;;
    -t) list_unresolved;;
    -?) quick_help;;
    *) quick_help; exit 1;;
  esac
fi

