#!/usr/pkg/bin/bash

opt_verbose=0
opt_recursive=0
arg_files=()

help_message() {
  echo "Usage: defrag [OPTION]... FILE...";
  echo "Defragmentize FILEs."
  echo
  echo "  -v, --verbose     explain what is being done"
  echo "  -r, --recursive   defrag directories recursively"
  echo "      --help        display this help and exit"
  echo "      --version     output version information and exit"
  echo
  echo "Report bugs to <oskar@osk.mine.nu>."
}

version_message() {
  echo "defrag (torrentutils) 0.3.0"
  echo "Written by Oskar Liljeblad."
  echo
  echo "Copyright (C) 2003 Oskar Liljeblad."
  echo "This is free software; see the source for copying conditions.  There is NO"
  echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
}

bad_args_exit() {
  echo "Try \``basename $0` --help' for more information."
  exit 1
}

# This is the heart of it all, a little paranoid about possible errors
defrag_file() {
  if [ -f "$1" -a ! -L "$1" ]; then
    for (( i=1; i < 100; i++)); do
      if [ ! -L "$1.$i" -a ! -e "$1.$i" ]; then
          [ "$opt_verbose" = 1 ] && echo "$1"
	  size1="`stat -c%s -- "$1"`"
	  if [ $? -ne 0 ]; then
	    echo >&2 "$1: stat failed, not defragging"
	    return
	  fi
          if ! cp -- "$1" "$1.$i"; then
	    echo >&2 "$1: copy failed, not defragging"
	    return
	  fi
	  size2="`stat -c%s -- "$1.$i"`"
	  if [ $? -ne 0 ]; then
	    echo >&2 "$1: stat failed, not defragging"
	    return
	  fi
          if [ ! -e "$1.$i" -o $size1 -ne $size2 ]; then
	    echo >&2 "$1: copy seem to have failed"
	    return
	  fi
          if ! mv -f -- "$1.$i" "$1"; then
	    echo >&2 "$1: move failed"
	    return
	  fi
        return
      fi
    done
  else
    echo >&2 "$1: Not a regular file"
  fi
}

recursive_scan() {
  if [ -d "$1" -a ! -L "$1" ]; then
    for a in "$1"/*; do
      recursive_scan "$a"
    done
  else
    defrag_file "$1"
  fi
}

more_opts=1
while [ $# -gt 0 ]; do
  if [ "$more_opts" -eq 1 -a "$1" = "--" ]; then
    more_opts=0
  elif [ "$more_opts" -eq 1 -a "${1:0:2}" = "--" ]; then
    case "${1:2:${#1}-2}" in
    verbose) opt_verbose=1 ;;
    recursive) opt_recursive=1 ;;
    help) help_message ; exit 0 ;;
    version) version_message; exit 0 ;;
    *) echo "`basename $0`: unrecognized option \`$1'" ; bad_args_exit ;;
    esac
  elif [ "$more_opts" -eq 1 -a "${1:0:1}" = "-" ]; then
    for ((i = 1; i < ${#1}; i++)); do
      case "${1:$i:1}" in
      v) opt_verbose=1 ;;
      r) opt_recursive=1 ;;
      *) echo "`basename $0`: unrecognized option \`-${1:$i:1}'" ; bad_args_exit ;;
      esac
    done
  else
    arg_files[${#arg_files[@]}]="$1"
  fi
  shift
done

if [ ${#arg_files[@]} -eq 0 ]; then
  echo "`basename $0`: missing file argument"
  bad_args_exit
fi

for ((c=0; c < ${#arg_files[@]}; c++)); do
  file="${arg_files[c]}"
  if [ ! -L "$file" -a ! -e "$file" ]; then
    echo >&2 "$file: No such file or directory"
  elif [ "$opt_recursive" -eq 1 ]; then
    if [ "$file" != "/" -a "${file:0-1:1}" = "/" ]; then
      file="${file:0:${#file}-1}"
    fi
    recursive_scan "$file"
  else
    defrag_file "$file"
  fi
done
