#!/bin/sh
declare -r MY_NAME=$(basename "$0") &&
declare -r MY_DIRECTORY=${0%\/$MY_NAME} &&

# standard PEAR packages included with the PHP distribution as of PHP 5.0.5
declare -ar PEAR_STANDARD=(Archive_Tar Console_Getopt HTML_Template_IT Net_UserAgent_Detect PEAR XML_RPC) &&

function say() {
  echo "$MY_NAME: $*"
}

# filter out a PEAR package by name if necessary
# $1 - PEAR package name (not spell name)
# $2 - reported PEAR package version
function is_allowed_pear_package() {
  # used to also filter out standard packages here

  # allow any package with sensible name and version
  [[ -n "$1" ]] && [[ -n "$2" ]] && [[ "$2" != '-n/a-' ]]
}

# convert input to lower case
function tolower() {
  tr '[:upper:]' '[:lower:]'
}

# extracts version from a DETAILS file; pass the path inside
function get_version_from_details() {
  gawk -F '=' '/VERSION=/ { print $2 }' "$1"
}

# extracts PEAR package name from a DETAILS file; pass the path inside
function get_pear_package_from_details() {
  gawk -F '=' '/PEAR_PACKAGE=/ { print $2 }' "$1"
}

#extract spell name from DETAILS
function get_spell_from_details() {
  gawk -F '=' '/SPELL=/ { print $2 }' "$1"
}

# convert PEAR package information into partial DETAILS file
# $1 - PEAR package name (not spell name)
# $2 - reported PEAR package version
function info_to_details() {
  # sometimes output of `pear remote-info' doesn't have version reported in `pear remote-list'
  pear remote-info "$1" \
    | gawk -f "$MY_DIRECTORY/pear_info_to_details" \
    | sed "s|VERSION=\$|\0$2|g"
}

# create DEPENDS file based on the package information
function info_to_depends() {
  # TODO get dependencies from PEAR and put them here
  echo 'depends  PHP'
}

# replaces spell's file with the new ones, mostly the same except for DETAILS and DEPENDS
# $1 - PEAR package name (not spell name)
# $2 - reported PEAR package version
function create_spell_for_package() {
  local SPELL=$(echo "PEAR-$1" | tolower) &&
  local DIR="$MY_DIRECTORY/$SPELL" &&
  local BLD="$DIR/BUILD" &&
  local DEP="$DIR/DEPENDS" &&
  local DET="$DIR/DETAILS" &&
  local INS="$DIR/INSTALL" &&
  local PBD="$DIR/PRE_BUILD" &&

  say "Creating/updating spell '$SPELL' in directory '$DIR'..." &&
  mkdir -p "$DIR" &&
  # create DETAILS script
  info_to_details "$1" "$2" > "$DET" &&
  # create DEPENDS script
  if ! [[ -x "$DEP" ]]; then
    info_to_depends "$1" > "$DEP"
  fi &&
  # add calls to common code
  echo 'true' > "$BLD" &&
  echo 'source  $SECTION_DIRECTORY/PEAR_PRE_BUILD' > "$PBD" &&
  echo 'source  $SECTION_DIRECTORY/PEAR_INSTALL' > "$INS" &&
  # mark as executable
  chmod +x "$BLD" "$DEP" "$DET" "$INS" "$PBD"
}

## usage: update_spell_for_package
# $1 - PEAR package name (not spell name)
# $2 - reported PEAR package version
function update_spell_for_package() {
  local SPELL=$(echo "PEAR-$1" | tolower) &&
  local DIR="$MY_DIRECTORY/$SPELL" &&
  local DET="$DIR/DETAILS" &&
  local VER='none' &&

  if [[ -x "$DET" ]]; then
    VER=$(get_version_from_details "$DET")
  fi &&
  if [[ "$2" != "$VER" ]]; then
    say "New/upgraded package '$1' version '$2' will be packaged as '$SPELL'..." &&
    create_spell_for_package "$1" "$2"
  fi
}

# walk through remote packages and update each
function update_packages() {
  local INDEX=0 &&
  local LINE= &&

  pear remote-list | while read LINE; do
    # skip first three lines
    if [[ $((++INDEX)) -lt 4 ]]; then
      continue
    fi &&
    # determine package name and version
    local PKG="${LINE%% *}" &&
    local VER="${LINE##* }" &&
    # filter package by any other criteria
    if ! is_allowed_pear_package "$PKG" "$VER"; then
      say "Skipping package '${PKG:-nameless}', version '${VER:-unknown}'..." &&
      continue
    fi &&
    # create or update package
    update_spell_for_package "$PKG" "$VER"
  done
}

## usage update_checksum <1:DETAILS path>
function update_details_checksum() {
  declare -r HASH_ALG=sha512 &&

  local SPELL=$(get_spell_from_details "$1") &&
  local PKG=$(get_pear_package_from_details "$1") &&
  local VER=$(get_version_from_details "$1") &&
  local FILE="/var/spool/sorcery/$PKG-$VER.tgz" &&

  [[ -n "$PKG" ]] &&
  [[ -n "$VER" ]] &&
  if ! [[ -r "$FILE" ]]; then
    summon "$SPELL"
  fi &&
  [[ -r "$FILE" ]] &&
  local SUM=$(openssl dgst "-$HASH_ALG" "$FILE" | cut -d ' ' -f 2) &&

  local T="$1-$$-$RANDOM" &&
  cp "$1" "$T" &&
  sed -e "s|\\(SOURCE_HASH\\)=.*|\\1='$HASH_ALG:$SUM'|" "$T" > "$1" &&
  rm "$T" &&
  say "Updated checksum in '$1'..."
}

# walk DETAILS files and update the checksums
function update_checksums() {
  find "$MY_DIRECTORY" -type f -and -path '*/pear-*/DETAILS' | while read LINE; do
    update_details_checksum "$LINE"
  done
}

function main() {
  if [[ $# == 2 ]]; then # two options
    update_spell_for_package "$1" "$2" &&
    scribe reindex &&
    update_details_checksum "$MY_DIRECTORY/PEAR-$1/DETAILS"
  elif [[ $# == 0 ]]; then # no options
    say 'Updating ALL packages...' &&
    update_packages &&
    scribe reindex &&
    update_checksums
  else
    say 'ERROR: Invalid number of options, must be no options or <package> <version>'
  fi
}

say 'PEAR to SMGL (Package to Spell) Translation Script' &&

[[ -z "$MY_DIRECTORY" ]] && (
  say "Couldn't determine the base directory..." &&
  exit 1
)
say "Base directory is '$MY_DIRECTORY'..."

if [[ "$UID" == 0 ]]; then
  main $*
else
  say 'Enter the root password, please'
  su - -c "DISPLAY=$DISPLAY PATH=$PATH $0 $*"
fi
