#!/bin/bash

declare -r SCRIPT="`basename $0`"
declare -r EMPTY_MD5SUM="`echo -n | md5sum | cut -d ' ' -f1`"

function usage()
{
  cat << EOF
Syntax: $SCRIPT [options] file
Options:
  -v|--version <new-version> new version
  -u|--updated               update UPDATE field
  -m|--md5                   download and update MD5 field
  -c|--cache <directory>     use alternative directory for source tarballs
  -s|--save                  rename the file and save the generated contents
  file                       DETAILS-style file to read, including path
EOF
}

function args() {
  let i=0
  while [ $# -gt 0 ]; do
    case $1 in
      -v|--version)
	NEW_VERSION="$2"
	debug "$SCRIPT" "Version: $NEW_VERSION"
	let i+=2
	shift 2
	;;
      -u|--updated)
	NEW_UPDATED=`date +%Y%m%d`
	debug "$SCRIPT" "Updated: $NEW_UPDATED"
	let i+=1
	shift 1
	;;
      -m|--md5)
	NEW_MD5="yes"
	debug "$SCRIPT" "New MD5: $NEW_MD5"
	let i+=1
	shift 1
	;;
      -c|--cache)
	SOURCE_CACHE="$2"
	debug "$SCRIPT" "Cache: $SOURCE_CACHE"
	let i+=2
	shift 2
	;;
      -s|--save)
	RENAME_AND_SAVE='on'
	let i+=1
	shift 1
	;;
      -h|--help)
	usage
	false
	return
	;;
      *)
	if [ -z "$DETAILS" ]; then
	  DETAILS="$1"
	else
	  debug "$SCRIPT" "$1: too many DETAILS files specified."
	  false
	  return
	fi
	let i+=1
	shift
	;;
    esac
  done

  if ! ( [[ "$NEW_VERSION" ]] || [[ "$NEW_UPDATED" ]] || [[ "$NEW_MD5" ]] ) ; then
    debug "$SCRIPT" "Nothing to update."
    usage
    false
    return
  fi

  if [ -z "$DETAILS" ] || ! [ -x "$DETAILS" ]; then
    debug "$SCRIPT" "${DETAILS:-<DETAILS>}: file not specified or invalid"
    false
    return
  fi
}

uncompress_to_stdout() {
  case "$2" in
    bzip2)     bzip2  -cdf "$1"           >&1 ;;
    gzip)      gzip   -cdf "$1"           >&1 ;;
    compress*) gzip   -cdf "$1"           >&1 ;;
    Zip)       cat         "$1"           >&1 ;;
    RPM)       rpmunpack < "$1" | gzip -d >&1 ;;
    tar)       cat         "$1"           >&1 ;;
    *)
      false
      ;;
  esac
}

unset NEW_VERSION
unset NEW_UPDATED
unset NEW_MD5
unset DETAILS
#DEBUG=${DEBUG:-/dev/stderr}

. /etc/sorcery/config
args "$@" || exit

debug "$SCRIPT" "$DETAILS: Running current file..."
. "$DETAILS" >/dev/null 2>&1

SED=sed
[[ $NEW_VERSION ]] && SED="$SED -e s/^\([[:blank:]]*VERSION=\).*$/\1"$NEW_VERSION"/"
[[ $NEW_UPDATED ]] && SED="$SED -e s/^\([[:blank:]]*UPDATED=\).*$/\1"$NEW_UPDATED"/"
#[[ $NEW_MD5 ]] && SED="$SED -e s/^\([[:blank:]]*MD5[0]=\).*$/\1\""$NEW_MD5"\"/"

debug "$SCRIPT" "$SED"

if echo "$SED" | grep -q '[[:blank:]]-e[[:blank:]]'; then
  NEW_DETAILS=`$SED $DETAILS`
else
  NEW_DETAILS=`cat $DETAILS`
fi

debug "$SCRIPT" "Checking for VERSION..."
EQ_COL=`echo "$NEW_DETAILS" | head -n 1 | awk -F '=' '{ print length($1) ;}'`
if ! echo "$NEW_DETAILS" | grep -q "[[:blank:]]*VERSION=" ; then
  debug "$SCRIPT" "Appending VERSION"
  let NUM_SPACES=$EQ_COL-8
  
  NEW_DETAILS="$NEW_DETAILS"$'\n'
  for (( i=0 ; i<$NUM_SPACES; i++ )) ; do
    NEW_DETAILS="$NEW_DETAILS "
  done
  NEW_DETAILS="${NEW_DETAILS}VERSION=$NEW_VERSION"
  
fi

debug "$SCRIPT" "Checking for UPDATED..."
if ! echo "$NEW_DETAILS" | grep -q "[[:blank:]]*UPDATED=" ; then
  debug "$SCRIPT" "Appending UPDATED"
  let NUM_SPACES=$EQ_COL-8
  
  NEW_DETAILS="$NEW_DETAILS"$'\n'
  for (( i=0 ; i<$NUM_SPACES ; i++ )) ; do
    NEW_DETAILS="$NEW_DETAILS "
  done
  NEW_DETAILS="${NEW_DETAILS}UPDATED=$NEW_UPDATED"
  
fi

debug "$SCRIPT" "Evaluating the new DETAILS..."
eval "$NEW_DETAILS" >/dev/null 2>&1

URL="${SOURCE_URL[0]}"
TARGET_PATH="$SOURCE_CACHE/$SOURCE"
debug "$SCRIPT" "$URL: Downloading..."
if ! [ -e "$TARGET_PATH" ]; then
  PROBE="$SOURCE_CACHE/UNLINKME.$$.$RANDOM"
  if ! touch "$PROBE" >/dev/null 2>&1; then
    echo "# $SCRIPT: $SOURCE_CACHE: Write access refused, cancelled downloading $SOURCE" 1>&2
  else
    rm "$PROBE"
    dl_source "$SOURCE" "$URL" >/dev/null 2>&1
  fi
fi

#
# It is quite difficult to determine if `uncompress' failed or succeeded
# because we pipe it into `md5sum' and loose the status.
# But, it produces a <null> output in case of no file or something like
# this, so we simply check for the MD5 sum of an zero-byte sequence.
#
debug "$SCRIPT" "Calculating MD5 hash value..."
COMPRESSOR=`guess_compressor "$TARGET_PATH"`
NEW_MD5=`uncompress_to_stdout "$TARGET_PATH" "$COMPRESSOR" | md5sum | cut -d ' ' -f1`
if [ "$NEW_MD5" = "$EMPTY_MD5SUM" ]; then
  unset NEW_MD5
  debug "$SCRIPT" "WARNING: Unable to determine the type of compressor"
  debug "$SCRIPT" "WARNING: Can't calculate the MD5 hash"
fi

NEW_DETAILS=`echo "$NEW_DETAILS" | sed -e "s#^\\([[:blank:]]*MD5\\[0\\]=\\).*\\$#\\1'${NEW_MD5}'#"`

debug "$SCRIPT" "Checking for MD5[0]..."
if [ ${#NEW_MD5} -eq 32 ] && ! echo "$NEW_DETAILS" | grep -q "[[:blank:]]*MD5\[0\]="; then
  let NUM_SPACES=$EQ_COL-6
  
  NEW_DETAILS="$NEW_DETAILS"$'\n'
  for (( i=0 ; i<$NUM_SPACES ; i++ )) ; do
    NEW_DETAILS="$NEW_DETAILS "
  done
  NEW_DETAILS="${NEW_DETAILS}MD5[0]='$NEW_MD5'"
  
fi

if [ "$RENAME_AND_SAVE" != 'on' ]; then
  echo "$NEW_DETAILS"
else
  OLDNAME="${DETAILS}-`date +%Y%m%d%H%M`"
  echo "$SCRIPT: $DETAILS: Renaming to $OLDNAME..." 1>&2
  #
  # Using `cp' we save permissions and executable bit
  #
  if cp -f "$DETAILS" "$OLDNAME"; then
    echo "$SCRIPT: $DETAILS: Saving new file" 1>&2
    echo "$NEW_DETAILS" > "$DETAILS"
  fi
fi
debug "$SCRIPT" "Done."
