#!/bin/bash

PATSH_REPO=".patches"
PATSH_NAME="patsh"

function check_if_unchanged {
   unset -v LATEST_DIFF
   for file in "${PATSH_REPO}/${1}"-*.diff; do
       [[ "$file" -nt "${LATEST_DIFF}" ]] && LATEST_DIFF="$file"
   done
   if [ "$LATEST_DIFF" != "" ]; then
       patch -i "${LATEST_DIFF}" -o - "${PATSH_REPO}/${1}" 2> /dev/null | cmp - "${1}" > /dev/null
   else
       cmp "${PATSH_REPO}/${1}" "${1}" > /dev/null
   fi
}

function showhelp {
   cat <<EOF
${PATSH_NAME} -- dead simple patch/version control system

Usage:
   patsh [options] command [files...]

Options:
 -h        show this help
 -f        enforce commit if no changes

Commands:
 init      initialize stash area
 add       start tracking file changes
 save      store changes done to file
 restore   undo changes and rewind to last version
 diff      show changes between working copy and last version
 list      show stored versions
EOF
   exit 0
}

while [[ "$1" == -* ]]; do
   case "$1" in
       -f|--force)
           printf "${PATSH_NAME}: not implemented yet\n"
           ;;
       -h|--help)
           showhelp
           ;;
   esac
   shift
done

case "$1" in
   init)
       mkdir "${PATSH_REPO}" && \
       printf "${PATSH_NAME}: stash initialized\n"
       ;;
   add|a)
       while [ -e "$2" ]; do

       if [ ! -e "${PATSH_REPO}/$2" ]; then
           cp "$2" "${PATSH_REPO}/" && \
           printf "${PATSH_NAME}: tracked file: ${2}\n"
       else
           printf "${PATSH_NAME}: file already tracked\npat.sh: use ${0} save ${2} to commit changes\n"
       fi

       shift
       done
       ;;
   list|ls)
       while [ -e "$2" ]; do

       if [ ! -e "${PATSH_REPO}/$2" ]; then
           printf "${PATSH_NAME}: file not tracked\npat.sh: use ${0} add ${2} to track file\n"
           exit 0
       fi
       printf "${PATSH_NAME}: ${2}: saved patches\n"
       for file in "${PATSH_REPO}/${2}"-*.diff ; do
           basename "${file}"
       done | sort

       shift
       done
       ;;
   save|ci)
       while [ -e "$2" ]; do

       if [ ! -e "${PATSH_REPO}/$2" ]; then
           printf "${PATSH_NAME}: file ${2} not tracked\n"
       elif check_if_unchanged "$2"; then
           printf "${PATSH_NAME}: file ${2} not changed\n"
       else
           LATEST_DIFF="${PATSH_REPO}/$2-$(date +%s).diff"
           diff -u "${PATSH_REPO}/$2" "$2" > "${LATEST_DIFF}"
           printf "${PATSH_NAME}: changes written to %s\n" "${LATEST_DIFF}"
       fi

       shift
       done
       ;;
   restore|co)
       while [ -e "$2" ]; do

       unset -v LATEST_DIFF
       if [ ! -e "${PATSH_REPO}/$2" ]; then
           printf "${PATSH_NAME}: file ${2} not tracked\n"
           exit 0
       fi
       cp "${PATSH_REPO}/${2}" "${2}"
       for file in "${PATSH_REPO}/${2}"-*.diff; do
           [[ "$file" -nt "${LATEST_DIFF}" ]] && LATEST_DIFF="$file"
       done
       if [ "$LATEST_DIFF" != "" ]; then
           patch "${2}" < "${LATEST_DIFF}" > /dev/null
           printf "${PATSH_NAME}: reset to ${LATEST_DIFF}\n"
       else
           printf "${PATSH_NAME}: reset to original version\n"
       fi

       shift
       done
       ;;
   diff)
       while [ -e "$2" ]; do

       unset -v LATEST_DIFF
       printf "${PATSH_NAME}: ${2} working copy changes\n"
       for file in "${PATSH_REPO}/${2}"-*.diff; do
           [[ "$file" -nt "${LATEST_DIFF}" ]] && LATEST_DIFF="$file"
       done
       if [ "$LATEST_DIFF" != "" ]; then
           patch -i "${LATEST_DIFF}" -o - "${PATSH_REPO}/${2}" 2> /dev/null | diff --color=always - "${2}"
       else
           diff --color=always "${PATSH_REPO}/${2}" "${2}"
       fi

       shift
       done
       ;;
   *)
       if [ "$1" == "" ]; then showhelp; fi
       printf "${PATSH_NAME}: unknown operation: ${1}\n"
       ;;
esac