#!/bin/bash

getlatestapk() {
  # This functions finds the latest available version for the given architeture.
  aaptcmd="$3"
  sourceapk=""
  highversion=""
  tempapks=( )
  OLDIFS="$IFS"
  IFS="
" # We set IFS to newline here so that filenames containing spaces are
  # handled correctly in the for-loops below.

  local LZ_DECOMPRESS_CMD="false"
  local LZ_DECOMPRESS_ARG=""
  if command -v lunzip > /dev/null; then
    LZ_DECOMPRESS_CMD="lunzip"
  elif command -v lzip > /dev/null; then
    LZ_DECOMPRESS_CMD="lzip"
    LZ_DECOMPRESS_ARG="--decompress"
  fi;

  # decompress apks
  # some apks are lz compressed to work around github file-size limits.
  for foundapklz in $(find "$1" -iname '*.apk.lz'); do
    $LZ_DECOMPRESS_CMD $LZ_DECOMPRESS_ARG --keep "$foundapklz" || echo "Warning: lz decompress command failed for $foundapklz" >&2
  done

  # sed copies filename to the beginning, to compare version, and later we remove it with cut
  for foundapk in $(find "$1" -iname '*.apk' | sed 's!.*/\(.*\)!\1/&!' | sort -r -t/ -k1,1 -n | cut -d/ -f2-); do
    # Get package version name
    apkprops="$("$aaptcmd" dump badging "$foundapk" 2> /dev/null)"
    apkversion="$(echo "$apkprops" | awk -F="'" '/versionName=/ {print $4}' | sed "s/'.*//g")"
    # Get invariant version name.
    # We first remove evrything after the first space.
    apkversion="$(printf "$apkversion" | cut -d ' ' -f 1)"
    # Then, we remove everything after the fourth dot.
    apkversionparts=$(echo "$apkversion" | tr '.' '\n')
    j=0
    apkversion=""
    
    for part in ${apkversionparts[@]}; do
      if [ $j -ge 4 ]; then
        break;
      else
        if [ $j -ge 1 ]; then
          apkversion+="."
        fi
        apkversion+="$part"
        ((j++))
      fi
    done
    
    if [ -z "$highversion" ]; then
      # Take note of the highest version.
      highversion="$apkversion"
    elif [ "$highversion" != "$apkversion" ]; then
      # Skip lower versions.
      break;
    fi
    # Add package to list.
    tempapks+=("$foundapk")
  done
  
  if [ ${#tempapks[@]} -ge 2 ]; then
    # See if there is a package for this dpi or a nodpi package.
    for foundapk in ${tempapks[@]}; do
      dpipath="$(dirname "$foundapk")"
      dpi="$(basename "$dpipath")"
      if [[ "$dpi" = "nodpi" || "$dpi" = "$2" ]]; then
        sourceapk="$foundapk"
        break;
      fi
      
      if [ "$2" != "nodpi" ]; then
        # Check if the package dpi is a range and if the device falls between that range
        lodpi=${dpi%%-*}
        hidpi=${dpi##*-}
        if [[ "$lodpi" != "$dpi" && "$lodpi" -le "$2" && "$hidpi" -ge "$2" ]]; then
          sourceapk="$foundapk"
          break;
        fi
      fi
    done
    
    # If the device is set to nodpi, we take the highest dpi available. This should be the first one on the list.
    if [[ -z "$sourceapk" && "$2" = "nodpi" ]]; then
      sourceapk="$tempapks"
    fi
    
    # Take the lowest dpi above the device dpi or the highest dpi under the device dpi.
    if [ -z "$sourceapk" ]; then
      for foundapk in ${tempapks[@]}; do
        dpipath="$(dirname "$foundapk")"
        dpi="$(basename "$dpipath")"
        # If this is a range, we already know the device is either over or under that range.
        # Therefore, we can safely take any value.
        dpi=${dpi%%-*}
        if [ "$dpi" -ge "$2" ]; then
          sourceapk="$foundapk"
        else
          # If we havn't found a higher dpi, we take the first (highest) lower dpi.
          if [ -z "$sourceapk" ]; then
            sourceapk="$foundapk"
          fi
          break;
        fi
      done
    fi
  elif [ ${#tempapks[@]} -ge 1 ]; then
    # If theres only one apk, take that one.
    sourceapk="$tempapks"
  fi
  
  IFS="$OLDIFS"
  if [ -z "$sourceapk" ]; then
    echo "WARNING: No APK found compatible with API level $API for package $PACKAGE_NAME on $ARCH" >&2
    return 1 #error
  fi
  
  #$sourceapk has the useful return value
  return 0 #return that it was a success
}

getconformapk() {
  # This functions finds the latest available version for the given architeture and dpi. IF the chosen dpi is not available, nodpi will be selected.
  sourceapk=""
  OLDIFS="$IFS"
  IFS="
" # We set IFS to newline here so that spaces can survive the for loop
  # sed copies filename to the beginning, to compare version, and later we remove it with cut
  for foundapk in $(find "$1" -iname '*.apk' | sed 's!.*/\(.*\)!\1/&!' | sort -r -t/ -k1,1 -n | cut -d/ -f2-); do
    founddpipath="$(dirname "$foundapk")"
    dpi="$(basename "$founddpipath")"
    lodpi=${dpi%%-*}
    hidpi=${dpi##*-}
    if [[ "$dpi" = "nodpi" || "$dpi" = "$2"
       || ( "$2" != "nodpi" && "$lodpi" != "$dpi" && "$lodpi" -le "$2" && "$hidpi" -ge "$2" ) ]]; then
        sourceapk="$foundapk"
        break;
    fi
  done
  
  IFS="$OLDIFS"
  if [ -z "$sourceapk" ]; then
    echo "WARNING: No APK found compatible with API level $API for package $PACKAGE_NAME on $ARCH and dpi $2" >&2
    return 1 #error
  fi
  #$sourceapk has the useful return value
  return 0 #return that it was a success
}

getapk()
{
  if [ "$3" = false ]; then
    aaptcmd="$4"
    if hash "$aaptcmd" 2> /dev/null; then
      getlatestapk "$1" "$2" "$aaptcmd"
    else
      echo "ERROR: aapt not found. Unable to detect latest package." >&2
      return 1
    fi
  else
    getconformapk "$1" "$2"
  fi
  
  return $?
}

getappapidir() {
  # Check if app directory exists.
  if [ ! -d "$1/$2/"*"app/$3" ]; then
    return 1 # Package does not exist for this arch.
  fi

  # Try to find the largest API which is greater or
  # equal to what is needed.
  api=0
  for apidir in "$1/$2/"*"app/$3/"*; do
    currentApi="$(basename "$apidir")"
    if [ "$currentApi" -le "$4" ] && [ "$currentApi" -ge "$api" ]; then
      api="$currentApi"
    fi
  done

  # Have we found anything?
  if [ "$api" -gt 0 ]; then
    appapidir="$(echo "$1/$2/"*"app/$3/$api")"
    return 0
  fi

  echo "WARNING: No APK found compatible with API level $4 for package $3 on $2" >&2
  return 1
}

getdpivalue() {
case "$1" in
"xxxhdpi")
dpivalue="640";
    ;;
"xxhdpi")
dpivalue="480";
    ;;
"xhdpi")
dpivalue="320";
    ;;
"hdpi")
dpivalue="240";
    ;;
"mdpi")
dpivalue="160";
    ;;
"ldpi")
dpivalue="120";
    ;;
*)
return 1;
    ;;
esac

return 0;
}

SOURCES="$1"
API="$2"
DPI="$3"
PACKAGE_NAME="$4"
ARCH="$5"
FORCE_DPI="$6"
AAPT_CMD="$7"

if ! getappapidir "$SOURCES" "$ARCH" "$PACKAGE_NAME" "$API"; then
  exit 1
fi

if getdpivalue "$DPI"; then
  if getapk "$appapidir" "$dpivalue" "$FORCE_DPI" "$AAPT_CMD"; then
    echo "$sourceapk"
  else
    exit 1
  fi
elif getapk "$appapidir" "nodpi" "$FORCE_DPI" "$AAPT_CMD"; then
  echo "$sourceapk"
else
  exit 1
fi
