_UNPACK_SUPPORTED=".tar$|.tgz$|.txz$|.tar.gz$|.tar.xz$|.zip$|.iso$|.rar$"

# Pack files into desired format.
# Usage: pack <TARGET.ext> [FILES]
pack()
{
  local IFS=$'\n'
  local output="${1}"
  local targets=("${@:2}")
  local format="${output##*.}"
  local name="${output%.*}"

  # report no output.
  if [[ "${output}" = "" ]]; then
    echo "Usage: pack <TARGET.ext> [FILES]"
    return 2
  fi

  # report no format.
  if [[ "${format}" = "" ]]; then
    echo "Could not determine output format."
    echo "Usage: pack <TARGET.ext> [FILES]"
    return 2
  fi

  # All targets by default.
  if [[ "${targets}" = "" ]]; then
    targets=($(ls))
  fi

  # process.
  case "${format}" in
    "tgz")
      _pack_tgz "${output}" "${targets[@]}"
      ;;
    "txz")
      _pack_txz "${output}" "${targets[@]}"
      ;;
    "tar")
      _pack_tar "${output}" "${targets[@]}"
      ;;
    "zip")
      _pack_zip "${output}" "${targets[@]}"
      ;;
    "gz")
      _pack_gz "${output}" "${targets[@]}"
      ;;
    "xz")
      _pack_xz "${output}" "${targets[@]}"
      ;;
    *)
      echo -e "${color_bred}${target}: Format not supported.${color_default}"
      return 1
      ;;
  esac

  # Show error.
  if [[ $? != 0 ]]; then
    echo -e "${color_bred}${target}: Failed.${color_default}"
  fi
}

# attempt to unpack everything.
# usage: unpack [FILES]
unpack()
{
  local IFS=$'\n'
  local targets=("${@}")
  local count=0
  local total=${#targets[@]}
  local failed=0

  # All targets by default.
  if [[ "${targets}" = "" ]]; then
    targets=($(ls | grep -E ${_UNPACK_SUPPORTED}))
    total=${#targets[@]}
  fi

  # process all files.
  for target in "${targets[@]}"; do
    # increment counter.
    ((count++))

    # prepare status.
    local status="[${count}/${total}] ${target}"

    # show status.
    echo -e "${status}"

    # unpack file type.
    local type="${target##*.}"

    [[ "${target}" =~ .tar.gz$ ]] && type="tar.gz"
    [[ "${target}" =~ .tar.xz$ ]] && type="tar.xz"

    # unpack content.
    case "${type,,}" in
      "zip")
        _unpack_zip "${target}"
        ;;
      "7z")
        _unpack_7z "${target}"
        ;;
      "tgz"|"tar.gz")
        _unpack_tgz "${target}"
        ;;
      "txz"|"tar.xz")
        _unpack_txz "${target}"
        ;;
      "tar")
        _unpack_tar "${target}"
        ;;
      "iso")
        _unpack_iso "${target}"
        ;;
      "rar")
        _unpack_rar "${target}"
        ;;
      "xz")
        _unpack_xz "${target}"
        ;;
      "gz")
        _unpack_gz "${target}"
        ;;
      *)
        echo -e "${color_bred}${target}: Format not supported.${color_default}"
        ((failed++))
        continue
        ;;
    esac

    # actions on error.
    if [[ $? != 0 ]]; then
      echo -e "${color_bred}${target}: Failed.${color_default}"
      ((failed++))
    fi
  done

  if [[ ${failed} != 0 ]]; then
    echo -e "${color_bred}Failed: ${failed}.${color_default}"
    false
  fi
}

_pack_zip()
{
  zip -9 -r "${@}"
}

_pack_tgz()
{
  tar -c "${@:2}" | pv -s $(du -csb "${@:2}" | sed -n -e '$p' | awk '{print $1}') | gzip -1 > "${1}"
}

_pack_txz()
{
  tar -c "${@:2}" | pv -s $(du -csb "${@:2}" | sed -n -e '$p' | awk '{print $1}') | xz -9e > "${1}"
}

_pack_tar()
{
  tar -c "${@:2}" | pv -s $(du -csb "${@:2}" | sed -n -e '$p' | awk '{print $1}') > "${1}"
}

_pack_gz()
{
  pv "${2}" | gzip -1 > "${1}"
}

_pack_xz()
{
  pv "${2}" | xz -9e > "${1}"
}

_unpack_zip()
{
  unzip "${1}"
}

_unpack_7z()
{
  7za x "${1}"
}

_unpack_tgz()
{
  pv "${1}" | gzip -d | tar -xf -
}

_unpack_txz()
{
  pv "${1}" | xz -d | tar -xf -
}

_unpack_tar()
{
  pv "${1}" | tar -xf -
}

_unpack_iso()
{
  7za x "${1}"
}

_unpack_rar()
{
  unrar x "${1}"
}

_unpack_gz()
{
  pv "${1}" | gzip -d > "${1%.gz}"
}

_unpack_xz()
{
  pv "${1}" | xz -d > "${1%.xz}"
}

# export functions.
export -f pack unpack _pack_tgz _pack_txz _pack_tar _pack_zip _unpack_zip _unpack_7z _unpack_tgz _unpack_txz _unpack_tar _unpack_iso _unpack_rar _pack_gz _pack_xz _unpack_gz _unpack_xz