#!/usr/bin/env bash

usage() {
  echo "usage:"
  echo "  $0 [--no-di] META-NAME|YAMLFILE"
  echo ""
  echo "options:"
  echo "  --no-di    disable desktop integration"
  exit 1
}

if [ $# -eq 0 ] || [ "x${!#}" = "x--no-di" ] ; then
  usage
fi
if [ $# -eq 2 ] && [ "x$1" != "x--no-di" ] ; then
  usage
fi

if [ "x$1" = "x--no-di" ] ; then
  ENABLE_DI="no"
else
  ENABLE_DI="yes"
fi

# Halt on errors
set -e
set -x

# Check dependencies
which wget >/dev/null 2>&1 || ( echo wget missing && exit 1 )
which grep >/dev/null 2>&1 || ( echo grep missing && exit 1 )
which sed >/dev/null 2>&1 || ( echo sed missing && exit 1 )
which cut >/dev/null 2>&1 || ( echo cut missing && exit 1 )
which dpkg-scanpackages  >/dev/null 2>&1 || ( echo dpkg-scanpackages missing && exit 1 )

# If the yaml file doesn't exist locally, get it from GitHub
if [ ! -f "${!#}" ] ; then
  YAMLFILE=/tmp/_recipe.yml
  rm -f "$YAMLFILE"
  wget -q "https://github.com/probonopd/AppImages/raw/master/recipes/meta/${!#}.yml" -O "$YAMLFILE"
else
  YAMLFILE="$(readlink -f "${!#}")"
fi

# Function to parse yaml
# https://gist.github.com/epiloque/8cf512c6d64641bde388
# based on https://gist.github.com/pkuczynski/8665367
parse_yaml() {
    local prefix=$2
    local s
    local w
    local fs
    s='[[:space:]]*'
    w='[a-zA-Z0-9_]*'
    fs="$(echo @|tr @ '\034')"
    sed -ne "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
        -e "s|^\($s\)\($w\)$s[:-]$s\(.*\)$s\$|\1$fs\2$fs\3|p" "$1" |
    awk -F"$fs" '{
    indent = length($1)/2;
    vname[indent] = $2;
    for (i in vname) {if (i > indent) {delete vname[i]}}
        if (length($3) > 0) {
            vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
            printf("%s%s%s=(\"%s\")\n", "'"$prefix"'",vn, $2, $3);
        }
    }' | sed 's/_=/+=/g'
}

# Read yaml file
parse_yaml $YAMLFILE "_"
eval $(parse_yaml $YAMLFILE "_")

# Execute multiple script lines together as one
# shell_execute filename key_of_group_of_commands
shell_execute() {
  if [ -f /tmp/recipe_script ] ; then
    rm /tmp/recipe_script
  fi
  parse_yaml $YAMLFILE "_" | grep "^$2+=" > /tmp/recipe_script
  sed -i -e 's|^'$2'+=("||g' /tmp/recipe_script
  sed -i -e 's|")$||g' /tmp/recipe_script
  bash -ex /tmp/recipe_script
  rm /tmp/recipe_script
}

APP=$_app
LOWERAPP=${APP,,}
if [ ! -z $_lowerapp ] ; then
  LOWERAPP=$_lowerapp
fi

mkdir -p ./$APP/$APP.AppDir/usr/lib
cd ./$APP/

if [ -d "./$APP.AppDir/" ] ; then
  rm -rf ./$APP.AppDir/
fi 

if [ ! -e functions.sh ] ; then
  wget -q https://github.com/probonopd/AppImages/raw/master/functions.sh -O ./functions.sh
fi
. ./functions.sh

if [ ! -z "${_ingredients_ghreleases[0]}" ] ; then
  for GHREPO in "${_ingredients_ghreleases[@]}" ; do
    wget -q "https://github.com/${GHREPO}/releases/" -O /tmp/gh-release.html
    DEB=$(cat /tmp/gh-release.html | grep ".deb" | grep x86_64 | head -n 1 | cut -d '"' -f 2)
    if [ -z "$DEB" ] ; then
      DEB=$(cat /tmp/gh-release.html | grep ".deb" | grep amd64 | head -n 1 | cut -d '"' -f 2)
    fi
    if [ -z "$DEB" ] ; then
      DEB=$(cat /tmp/gh-release.html | grep ".deb" | grep x64 | head -n 1 | cut -d '"' -f 2)
    fi
    if [ -z "$DEB" ] ; then
      DEB=$(cat /tmp/gh-release.html | grep ".deb" | grep linux64 | head -n 1 | cut -d '"' -f 2)
    fi
    rm /tmp/gh-release.html
    wget -c "https://github.com/${DEB}"
  done
fi

if [ ! -z "${_ingredients_dist}" ] ; then
  rm status 2>/dev/null || true
  generate_status

  # Some packages depend on an exact version of a dependency to be installed.
  # Use
  # ingredients:
  #   pretend:
  #     - packagename version_to_be_pretended
  if [ ! -z "${_ingredients_pretend[0]}" ] ; then
    for PRETEND in "${_ingredients_pretend[@]}" ; do
      P_PKG=$(echo "$PRETEND" | cut -d " " -f 1)
      P_VER=$(echo "$PRETEND" | cut -d " " -f 2)
      cat status | tr '\n' '@' | sed -e 's|@@|\n\n|g' | sed -e 's|Package: '"$P_PKG"'@Status: install ok installed@Architecture: all@Version: 9:999.999.999|Package: '"$P_PKG"'@Status: install ok installed@Architecture: all@Version: '"$P_VER"'|g' | sed -e 's|@|\n|g' > status.temp
      mv status.temp status
    done
  fi

  if [ -e sources.list ] ; then
    rm sources.list
  fi
  for SOURCE in "${_ingredients_sources[@]}" ; do
    echo "${SOURCE}" >> sources.list
  done
  for PPA in "${_ingredients_ppas[@]}" ; do
    echo "deb http://ppa.launchpad.net/${PPA}/ubuntu ${_ingredients_dist} main" >> sources.list
  done
fi

if [ ! -z "${_ingredients_script[0]}" ] ; then
  # Execute extra steps defined in recipe
  shell_execute $YAMLFILE _ingredients_script
fi

if [ ! -z "${_ingredients_dist}" ] ; then
  # Some projects provide raw .deb files without a repository
  # hence we create our own local repository as part of
  # the AppImage creation process in order to "install"
  # the package using apt-get as normal
  if [ ! -z "${_ingredients_debs[0]}" ] ; then
  which dpkg-scanpackages >/dev/null 2>&1 || ( echo dpkg-scanpackages missing && exit 1 )
    for DEB in "${_ingredients_debs[@]}" ; do
      if [ ! -f $(basename "$DEB") ] ; then
        wget -c $DEB
      fi
    done
  fi
  dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz
  echo "deb file:$(readlink -e $PWD) ./" >> sources.list

  INSTALL=$LOWERAPP
  if [ ! -z "${_ingredients_package}" ] ; then
    INSTALL="${_ingredients_package}"
  fi
  if [ ! -z "${_ingredients_packages}" ] ; then
    INSTALL=""
  fi

  # If packages are specifically listed, only install these, not a package with the name of the app
  if [ ! -z "${_ingredients_packages[0]}" ] ; then
    INSTALL=${_ingredients_packages[@]}
  fi

  apt-get $OPTIONS update || true
  URLS=$(apt-get $OPTIONS -y install --print-uris $INSTALL | cut -d "'" -f 2 | grep -e "^http")
  for URL in $URLS ; do
    if [ ! -f $(basename "$URL") ] ; then
      wget -c $URL
    fi
  done
fi

mkdir -p ./$APP.AppDir/
cd ./$APP.AppDir/

mkdir -p usr/bin usr/lib
find ../*.deb -exec dpkg -x {} . \; || true

# Try to copy icons to standard locations where appimaged can pick them up
mkdir -p usr/share/icons/hicolor/{22x22,24x24,32x32,48x48,64x64,128x128,256x256,512x512}/apps/
find . -path *icons* -path *22* -name "*$LOWERAPP*" -exec cp {} usr/share/icons/hicolor/22x22/apps/ \; || true
find . -path *icons* -path *24* -name "*$LOWERAPP*" -exec cp {} usr/share/icons/hicolor/24x24/apps/ \; || true
find . -path *icons* -path *32* -name "*$LOWERAPP*" -exec cp {} usr/share/icons/hicolor/32x32/apps/ \; || true
find . -path *icons* -path *48* -name "*$LOWERAPP*" -exec cp {} usr/share/icons/hicolor/48x48/apps/ \; || true
find . -path *icons* -path *64* -name "*$LOWERAPP*" -exec cp {} usr/share/icons/hicolor/64x64/apps/ \; || true
find . -path *icons* -path *128* -name "*$LOWERAPP*" -exec cp {} usr/share/icons/hicolor/128x128/apps/ \; || true
find . -path *icons* -path *256* -name "*$LOWERAPP*" -exec cp {} usr/share/icons/hicolor/256x256/apps/ \; || true
find . -path *icons* -path *512* -name "*$LOWERAPP*" -exec cp {} usr/share/icons/hicolor/512x512/apps/ \; || true

get_icon

if [ -z "${_union}" ] ; then
  get_apprun
else
cat > AppRun <<\EOF
#!/bin/sh
HERE="$(dirname "$(readlink -f "${0}")")"
export UNION_PRELOAD="${HERE}"
export LD_PRELOAD="${HERE}/libunionpreload.so"
export PATH="${HERE}"/usr/bin/:"${HERE}"/usr/sbin/:"${HERE}"/usr/games/:"${HERE}"/bin/:"${HERE}"/sbin/:"${PATH}"
export LD_LIBRARY_PATH="${HERE}"/usr/lib/:"${HERE}"/usr/lib/i386-linux-gnu/:"${HERE}"/usr/lib/x86_64-linux-gnu/:"${HERE}"/usr/lib32/:"${HERE}"/usr/lib64/:"${HERE}"/lib/:"${HERE}"/lib/i386-linux-gnu/:"${HERE}"/lib/x86_64-linux-gnu/:"${HERE}"/lib32/:"${HERE}"/lib64/:"${LD_LIBRARY_PATH}"
export PYTHONPATH="${HERE}"/usr/share/pyshared/:"${PYTHONPATH}"
export XDG_DATA_DIRS="${HERE}"/usr/share/:"${XDG_DATA_DIRS}"
export PERLLIB="${HERE}"/usr/share/perl5/:"${HERE}"/usr/lib/perl5/:"${PERLLIB}"
export GSETTINGS_SCHEMA_DIR="${HERE}"/usr/share/glib-2.0/schemas/:"${GSETTINGS_SCHEMA_DIR}"
export QT_PLUGIN_PATH="${HERE}"/usr/lib/qt4/plugins/:"${HERE}"/usr/lib/i386-linux-gnu/qt4/plugins/:"${HERE}"/usr/lib/x86_64-linux-gnu/qt4/plugins/:"${HERE}"/usr/lib32/qt4/plugins/:"${HERE}"/usr/lib64/qt4/plugins/:"${HERE}"/usr/lib/qt5/plugins/:"${HERE}"/usr/lib/i386-linux-gnu/qt5/plugins/:"${HERE}"/usr/lib/x86_64-linux-gnu/qt5/plugins/:"${HERE}"/usr/lib32/qt5/plugins/:"${HERE}"/usr/lib64/qt5/plugins/:"${QT_PLUGIN_PATH}"
EXEC=$(grep -e '^Exec=.*' "${HERE}"/*.desktop | head -n 1 | cut -d "=" -f 2- | sed -e 's|%.||g')
exec ${EXEC} $@
EOF
chmod a+x AppRun
fi

get_desktop

# Prevent Qt from loading plugins from the system
unset QTPATH
QTPATH=$(find usr/lib -type d -name qt4 -or -name qt5 | sed -e 's|usr/|../|g')
if [ ! -z $QTPATH ] ; then
cat > usr/bin/qt.conf <<EOF
[Paths]
Prefix = $QTPATH
EOF
fi

if [ -d "./usr/lib/x86_64-linux-gnu/gstreamer-1.0/" ] ; then
  mv ./usr/lib/x86_64-linux-gnu/gstreamer-1.0/* ./usr/lib/x86_64-linux-gnu/
  rm -r ./usr/lib/x86_64-linux-gnu/gstreamer-1.0
fi

if [ -d "./usr/lib/x86_64-linux-gnu/pulseaudio/" ] ; then
  mv ./usr/lib/x86_64-linux-gnu/pulseaudio/* ./usr/lib/x86_64-linux-gnu/
  rm -r ./usr/lib/x86_64-linux-gnu/pulseaudio
fi

# Execute extra steps defined in recipe
if [ ! -z "${_script}" ] ; then
  shell_execute $YAMLFILE _script
fi

# Some non-distribution provided applications have an absolute
# path in the Exec= line which we remove for relocateability
DESKTOP=$(find . -name '*.desktop' | sort | head -n 1)
if [ -z "$DESKTOP" ] ; then
  echo "desktop file not found, aborting"
  exit 1
else
  desktop-file-validate "$DESKTOP" || exit 1
  ORIG=$(grep -o "^Exec=.*$" "${DESKTOP}" | head -n 1| cut -d " " -f 1)
  REPL=$(basename $(grep -o "^Exec=.*$" "${DESKTOP}" | head -n 1 | cut -d " " -f 1 | sed -e 's|Exec=||g'))
  sed -i -e 's|'"${ORIG}"'|Exec='"${REPL}"'|g' "${DESKTOP}"
fi

# Compile GLib schemas if the subdirectory is present in the AppImage
# AppRun has to export GSETTINGS_SCHEMA_DIR for this to work
if [ -d usr/share/glib-2.0/schemas/ ] ; then
  ( cd usr/share/glib-2.0/schemas/ ; glib-compile-schemas . )
fi

if [ -f ../VERSION ] ; then
  VERSION=$(cat ../VERSION).glibc$(glibc_needed)
else
  get_version || true
fi

# patch_usr
# Patching only the executable files seems not to be enough for some apps
if [ ! -z "${_binpatch}" ] ; then
  find usr/ -type f -exec sed -i -e 's|/usr|././|g' {} \;
  find usr/ -type f -exec sed -i -e 's@././/bin/env@/usr/bin/env@g' {} \;
fi

# Don't suffer from NIH; use LD_PRELOAD to override calls to /usr paths
if [ ! -z "${_union}" ] ; then
  mkdir -p usr/src/
  wget -q "https://raw.githubusercontent.com/mikix/deb2snap/master/src/preload.c" -O - | \
  sed -e 's|SNAPPY|UNION|g' | sed -e 's|SNAPP|UNION|g' | sed  -e 's|SNAP|UNION|g' | \
  sed -e 's|snappy|union|g' > usr/src/libunionpreload.c
  gcc -shared -fPIC usr/src/libunionpreload.c -o libunionpreload.so -ldl -DUNION_LIBNAME=\"libunionpreload.so\"
  strip libunionpreload.so
fi

delete_blacklisted

if [ "$ENABLE_DI" = "yes" ] ; then
  get_desktopintegration $LOWERAPP
fi

# Fix desktop files that have file endings for icons
sed -i -e 's|\.png||g' *.desktop || true
sed -i -e 's|\.svg||g' *.desktop || true
sed -i -e 's|\.svgz||g' *.desktop || true
sed -i -e 's|\.xpm||g' *.desktop || true

# Execute extra steps defined in recipe
if [ ! -z "${_post}" ] ; then
  shell_execute $YAMLFILE _post
fi

# Go out of AppImage
cd ..

generate_type2_appimage
ls -lh ../out/*.AppImage

