#!/bin/bash
#
# Author: Francesca Ferrari
# Program name: zipo
# Date: 05/17/2012
#
# To run: zipo [-b] [-w] [-a] [-h] FILENAME
# zipo tests 4 different compressors (bzip gzip2 zip xz)
# with no time constraint applied (best compression rate 
# option usedi for the testing).
# zipo outputs: 
# -b: name(s) of the best compressor(s)
# -w: name(s) of the worst compressor(s)
# -a: a table with the reduction rate for all 4 of them
# -h: help
#

help_zipo()
{ 
  local prog=$(basename $0)
  echo "$prog [-b] [-w] [-a] [-h] FILENAME" 
}

fatal() 
{
  local prog=$(basename $0)
  echo -e "$prog: ERROR: $*" >&2
  help_zipo >&2
  exit 1
}

filesize() 
{
  local size=$(ls -l "$1" | tr -s ' ' | cut -d' ' -f5)
  echo "$size"
}


compressor()
{
   local gz_ratio="$1"
   local bz2_ratio="$2"
   local zip_ratio="$3"
   local xz_ratio="$4"
   local best="$5"
   local comparison=
   local reverse_list=
   
   if [ "$best" = true ]; then
     comparison=-ge
     reverse_list=r
   else
     comparison=-le
   fi

   sorted_comp=$( (echo "$gz_ratio" gzip; echo "$bz2_ratio" bzip; 
                   echo "$zip_ratio" zip; echo "$xz_ratio" xz ) | 
		   sort -n$reverse_list )
   ratio_def=$( echo "$sorted_comp" | head -n 1 | cut -d' ' -f1 )
   while read -r line; do
     comp=$( echo "$line" | cut -d' ' -f2 )
     ratio=$( echo "$line" | cut -d' ' -f1 )
     if [ "$ratio" $comparison "$ratio_def" ]; then
       echo -n "$comp "
     else
       break
     fi
     ratio_def="$ratio"
   done <<< "$sorted_comp"
   echo
}

# Input validation and command line parsing

[ $# -eq 0 ] && fatal "Missing arguments"

b_flag=false
w_flag=false
a_flag=false

while [ $# -gt 0 ]; do
  case "$1" in
  -h) help_zipo
      exit 0;;
  -b) b_flag=true;;
  -w) w_flag=true;;
  -a) a_flag=true;;
  -*) fatal "illegal option '$1'";;
  *)  break;;
  esac
  shift
done

[ $# -eq 0 ] && fatal "No filename supplied"
[ $# -gt 1 ] && fatal "Too many filenames supplied"

# end input validation and command line parsing

fname="$1"
fsize=$( filesize "$1")

tmp_dir=$(mktemp -d /tmp/$$zipo)

gz_file="$tmp_dir"/"$fname".gz
bz2_file="$tmp_dir"/"$fname".bz2
zip_file="$tmp_dir"/"$fname".zip 
xz_file="$tmp_dir"/"$fname".xz

gzip -c9 "$fname" > "$gz_file"
bzip2 -c9 "$fname" > "$bz2_file"
zip -r "$zip_file" "$fname" > /dev/null
xz -c9 "$fname" > "$xz_file"

gz_size=$(filesize "$gz_file")
bz2_size=$(filesize "$bz2_file")
zip_size=$(filesize "$zip_file")
xz_size=$(filesize "$xz_file")

gz_ratio=$(( 100 - (gz_size * 100 / fsize) ))
bz2_ratio=$(( 100 - (bz2_size * 100 / fsize) ))
zip_ratio=$(( 100 - (zip_size * 100 / fsize) ))
xz_ratio=$(( 100 - (xz_size * 100 / fsize) ))

best=

if [ "$b_flag" = true ]; then
  echo -n "Best compressor: "
  best=true
  compressor "$gz_ratio" "$bz2_ratio" "$zip_ratio" "$xz_ratio" $best
fi


if [ "$w_flag" = true ]; then
  echo -n "Worst compressor: "
  best=false
  compressor "$gz_ratio" "$bz2_ratio" "$zip_ratio" "$xz_ratio" $best
fi

if [  "$a_flag" = true ]; then
  echo   "COMPRESSOR | REDUCTION RATE % "
 (printf "  gzip            %2d\n" "$gz_ratio"; 
  printf "  bzip            %2d\n" "$bz2_ratio"; 
  printf "  zip             %2d\n" "$zip_ratio"
  printf "  xz              %2d\n" "$xz_ratio") | sort -k2n
fi

rm -r $tmp_dir

exit 0
