#!/bin/bash
#############################################################################
# Require la siguiente estructura de carpetas:
#
# - packages
#   - custom (carpeta con los paquetes adicionales a incluir en la portable)
#   - exclude (fichero con los codigos de paquetes a excluir)
# - standard
#   - gvSIG-desktop*-lin-x86-online.zip
#   - gvSIG-desktop*-lin-x86_64-online.zip
#   - gvSIG-desktop*-win-x86-online.zip
#   - gvSIG-desktop*-win-x86_64-online.zip
#   - gvSIG-desktop*-lin-x86.gvspkg
#   - gvSIG-desktop*-lin-x86_64.gvspkg
#   - gvSIG-desktop*-win-x86.gvspkg
#   - gvSIG-desktop*-win-x86_64.gvspkg
# - patchs
#   - patchs.sh (se ejecuta antes que los scripts de ant y zipear la instalacion)
# - make-portable
#
# Y se ejecutara el archivo "make-portable" desde ese directorio.
#
# Al final se crean las carpetas y archivos:
#
# - target/gvsig-desktop-VERSION-lin-x86
# - target/gvsig-desktop-VERSION-lin-x86_64
# - target/gvsig-desktop-VERSION-win-x86
#
# - target/gvsig-desktop-VERSION-lin-x86.zip
# - target/gvsig-desktop-VERSION-lin-x86_64.zip
# - target/gvsig-desktop-VERSION-win-x86.zip
#
##############################################################################


#=============================================
# JREs to use
URL_JRE_FOLDER="http://downloads.gvsig.org/download/gvsig-desktop-testing/pool/jre"

GVSPKG_JRE_darwin_x86_64="gvSIG-desktop-2.3.0-jre-1.8.0-72-testing-darwin_macos_10.11-x86_64-j1_8.gvspkg"
GVSPKG_JRE_lin_x86_64="gvSIG-desktop-2.6.0-jre-1.8.0-311-testing-lin-x86_64-j1_8.gvspkg"
GVSPKG_JRE_lin_x86="gvSIG-desktop-2.3.0-jre-1.8.0-92-testing-lin-x86-j1_8.gvspkg"
GVSPKG_JRE_win_x86_64="gvSIG-desktop-2.6.0-jre-1.8.0-311-testing-win-x86_64-j1_8.gvspkg"
GVSPKG_JRE_win_x86="gvSIG-desktop-2.3.0-jre-1.8.0-73-testing-win-x86-j1_8.gvspkg"

#
#=============================================

#set -x

#function handle_error() {
#    echo "FAILED: line $1, exit code $2"
#    exit 1
#}
#
#trap 'handle_error $LINENO $?' ERR

set -e

cd "$(dirname $0)"
SCRIPT_NAME=$(basename $0)

export BASEFOLDER="$PWD"
export TARGET="$BASEFOLDER/target"
export PATCHSFOLDER=$BASEFOLDER/patchs

function logger_info() {
    echo "$*"
}

function logger_warn() {
    echo "$*"
}

function get_package_info() {
  PACKAGE_PATH="$1"

  #
  # A veces en el zip los archivos comienzan por "/" y otras no.
  # Asi que lo primero que hacemos es comprobar eso.
  #
  local prefix=""
  local line=""
  # El flag -Z1 muestra los ficheros unicamente, similar a -l pero
  # sin ningun tipo de cabezaras, resumenes o informacion adicional
  # por cada fichero. Solo el nombre con ruta de cada fichero.
  local x=$(unzip -Z1 "$PACKAGE_PATH" "*/package.info")
  if [ "${x:0:1}" == "/" ] ; then
    prefix="/"
  fi
  #
  # Usamos una redireccion y no un pipe ya que los elementos de un pipe se
  # ejecutan en un subshell separado y la asignacion a las variables dentro del
  # while solo tendria efecto en ese subshell.
  #
  # Atencion al parametro W del unzip, ya que si lo quitamos y en el zip hay
  # mas de un "package.info" nos los sacaria todos, y los resultados no serian
  # los esperados. Solo tenemos que leer el "package.info" que hay en el primer
  # subdirectorio del zip.
  # Con el tr intentamos eliminar lo \r ya que algunos package.info generados
  # desde windows tienen \r.
  #
  PACKE_INFO_CONTENTS=$(unzip -nlpWc "$PACKAGE_PATH" "${prefix}*/package.info" | tr -d '\r')
  while read line ; do
    case "$line" in
    type=*)
      PACKAGE_TYPE=${line#type=}
      ;;
    version=*)
      PACKAGE_VERSION=${line#version=}
      ;;
    code=*)
      PACKAGE_CODE=${line#code=}
      ;;
    esac
  done <<END_OF_PACKAGE_INFO_CONTENTS
$PACKE_INFO_CONTENTS
END_OF_PACKAGE_INFO_CONTENTS
}


function install_symbols() {
    INSTALL_FOLDER="$1"

    cd "$INSTALL_FOLDER"
    mkdir -p "preferences/gvSIG/plugins/org.gvsig.app.mainplugin/Symbols"
    cd "preferences/gvSIG/plugins/org.gvsig.app.mainplugin/Symbols"
    rm -rf "$PACKAGE_CODE"
    logger_info "Install symbols $PACKAGE_CODE $PACKAGE_VERSION"
    unzip -nqq "$PACKAGE_PATH" 2>&1 | sed "/warning:  stripped absolute path/d"
}

function install_icontheme() {
    INSTALL_FOLDER="$1"

    cd "$INSTALL_FOLDER"
    mkdir -p "preferences/gvSIG/icon-theme"
    cd "preferences/gvSIG/icon-theme"
    rm -rf "$PACKAGE_CODE"
    logger_info "Install icon theme $PACKAGE_CODE $PACKAGE_VERSION"
    unzip -nqq "$PACKAGE_PATH" 2>&1 | sed "/warning:  stripped absolute path/d"
}

function install_script() {
    INSTALL_FOLDER="$1"

    cd "$INSTALL_FOLDER"
    
    mkdir -p "preferences/gvSIG/plugins/org.gvsig.scripting.app.mainplugin/$PORTABLE_VERSION_WITHOUT_BUILDNUMBER/scripts/addons"
    cd "preferences/gvSIG/plugins/org.gvsig.scripting.app.mainplugin/$PORTABLE_VERSION_WITHOUT_BUILDNUMBER/scripts/addons"
    rm -rf "$PACKAGE_CODE"
    logger_info "Install script $PACKAGE_CODE $PACKAGE_VERSION"
    unzip -nqq "$PACKAGE_PATH" 2>&1 | sed "/warning:  stripped absolute path/d"
}

function install_jCRS_EPSG() {
    INSTALL_FOLDER="$1"

    cd "$INSTALL_FOLDER"
    mkdir -p "preferences/gvSIG/plugins/org.gvsig.projection.app.jcrs/db/EPSG"
    cd "preferences/gvSIG/plugins/org.gvsig.projection.app.jcrs/db/EPSG"
    rm -rf "$PACKAGE_CODE"
    logger_info "Install jCRS EPSG data base $PACKAGE_CODE $PACKAGE_VERSION"
    unzip -nqq "$PACKAGE_PATH" 2>&1 | sed "/warning:  stripped absolute path/d"
}

function install_plugin() {
    INSTALL_FOLDER="$1"

    cd "$INSTALL_FOLDER/gvSIG/extensiones"
    rm -rf "$PACKAGE_CODE"
    logger_info "Install plugin $PACKAGE_CODE $PACKAGE_VERSION"
    unzip -nqq "$PACKAGE_PATH" 2>&1 | sed "/warning:  stripped absolute path/d"
}

function install_translations() {
    INSTALL_FOLDER="$1"

    cd "$INSTALL_FOLDER/i18n"
    rm -rf "$PACKAGE_CODE"
    logger_info "Install translations $PACKAGE_CODE $PACKAGE_VERSION"
    unzip -nqq "$PACKAGE_PATH" 2>&1 | sed "/warning:  stripped absolute path/d"
}

function run_plugins_install_scripts() {
    INSTALL_FOLDER="$1"

    logger_info ""
    logger_info "Running plugins install scripts"
    cd "$INSTALL_FOLDER/gvSIG/extensiones"
    for PLUGIN_CODE in *
    do
        if [ -f "$INSTALL_FOLDER/gvSIG/extensiones/$PLUGIN_CODE/install/install.xml" ] ; then
            logger_info "Running custom install script of $PLUGIN_CODE"
            cd $INSTALL_FOLDER
            ant -Dgvsig_dir="$INSTALL_FOLDER" -Dextensions_dir="$INSTALL_FOLDER/gvSIG/extensiones" -f "$INSTALL_FOLDER/gvSIG/extensiones/$PLUGIN_CODE/install/install.xml"
        fi
    done
}

function install_packages() {
    INSTALL_FOLDER="$1"
    PACKAGES_FOLDER="$2"

    logger_info ""
    logger_info "Processing $(basename $PACKAGES_FOLDER) packages"
    for PACKAGE_PATH in $PACKAGES_FOLDER/*.gvspkg
    do
      if [ -f "$PACKAGE_PATH" ] ; then
        PACKAGE_NAME="$(basename $PACKAGE_PATH)"
        get_package_info $PACKAGE_PATH
        if include_package $PACKAGE_CODE ; then
          case $PACKAGE_TYPE in
          plugin)
            install_plugin "$INSTALL_FOLDER"
            ;;
          jCRS_EPSG)
            install_jCRS_EPSG "$INSTALL_FOLDER"
            ;;
          symbols)
            install_symbols "$INSTALL_FOLDER"
            ;;
          Script)
            install_script "$INSTALL_FOLDER"
            ;;
          translations)
            install_translations "$INSTALL_FOLDER"
            ;;
          icontheme)
            install_icontheme "$INSTALL_FOLDER"
            ;;
          *)
            echo "ERROR: Type of package $PACKAGE_TYPE of $PACKAGE_NAME not supported."
            exit 1
            ;;
          esac
        else
          logger_info "Exclude package $PACKAGE_CODE"
          #cp "$PACKAGE_PATH" "$INSTALL_FOLDER/install"
        fi
      fi
    done
}

function include_package0() {
    set +e
    egrep  "^$1\$" "$BASEFOLDER/packages/excludes" >/dev/null
    FOUND=$?
    set -e
    if [ "$FOUND" == 1 ] ; then
        return 0
    fi
    return 1
}

function include_package() {
  while read pattern ; do
    if [ "${1/#${pattern}/ok}" == "ok" ] ; then
      return 1
    fi
  done <<END_OF_EXCLUDE_CONTENTS
$(cat "$BASEFOLDER/packages/excludes")
END_OF_EXCLUDE_CONTENTS
    return 0
}

function remove_excluded_packages() {
    logger_info "Checking plugins to remove"
    cd "$INSTALL_FOLDER/gvSIG/extensiones"
    while read line; do
        if [ -d "$line" ] ; then
            logger_info "Removing plugin $line"
            rm -rf "$line"
        fi
    done < "$BASEFOLDER/packages/excludes"
}

function install_portable_configuration_files() {
    logger_info "Install portable configuration file (gvSIG.config)"
    cp "$INSTALL_FOLDER/tools/gvSIG.config" "$INSTALL_FOLDER"
    chmod a+x "$INSTALL_FOLDER/gvSIG.sh"
}

function prepare_portable_macos() {
    echo "Creating MacOS app layout"
    mkdir -p "$INSTALL_FOLDER/Contents/MacOS"
    cd "$INSTALL_FOLDER/Contents/MacOS"
    echo '#!/bin/bash
cd "$(dirname $0)/../.."
exec "./gvSIG.sh"
' >"${PORTABLE_NAME}"
    chmod a+x "${PORTABLE_NAME}"
    cp "${PORTABLE_NAME}" "gvSIG"
    cp "${PORTABLE_NAME}" "gvSIG-desktop"
    cp "${PORTABLE_NAME}" "gvSIG-desktop-${PORTABLE_VERSION/-*/}"
    cp "${PORTABLE_NAME}" "gvSIG-desktop-${PORTABLE_VERSION}"
    rm -f "$INSTALL_FOLDER/gvSIG/extensiones/org.gvsig.gdal.app.mainplugin/gdal/libc++.1.dylib"
    cd "$INSTALL_FOLDER"
}

function zipfolder() {
    echo zip -qyr9 "$1" "$2"
    if type zip >/dev/null 2>/dev/null
    then
  zip -qyr9 "$1" "$2"
    else
      echo "

  WARNING: zip command not found.
           $1 not compressed.

"
    fi
}

function expandsVarsOnFile() {
  sed 's/\${INSTALL_DRIVE}/./
s/\${INSTALL_PATH}/./' "$1" >"$1.tmp"
  mv "$1.tmp" "$1"
}

function download_jre() {
  GVSPKG_JRE="GVSPKG_JRE_${PORTABLE_OSFAMILY}_${PORTABLE_PLATFORM}"
  GVSPKG_JRE="${!GVSPKG_JRE}"

  if [ ! -f "${GVSPKG_JRE}" ] ; then
    echo "Downloading JRE ${URL_JRE_FOLDER}/${GVSPKG_JRE}"
    wget  -q "${URL_JRE_FOLDER}/${GVSPKG_JRE}"
  fi
}

function mkdist() {
    cd $BASEFOLDER/standard

    # OS code (lin/win/darwin) + distribution + version
    export PORTABLE_OS="$1"

    # OS family code (lin/win/darwin)
    export PORTABLE_OSFAMILY="${PORTABLE_OS/_*/}"

    # OS name (linux/windows/darwin) for show only
    export PORTABLE_OSNAME="$2"

    # Architectute X86, x86_64
    export PORTABLE_PLATFORM="$3"

    # OS used to locate the online zip
    export ONLINE_OS
    case "$PORTABLE_OSFAMILY" in
    darwin)
        ONLINE_OS="lin"
        ;;
    lin)
        ONLINE_OS="lin"
        ;;
    win)
        ONLINE_OS="win"
        ;;
    *)
        ONLINE_OS="$PORTABLE_OS"
        ;;
    esac

    export PORTABLE_VERSION=$(expr *${ONLINE_OS}-${PORTABLE_PLATFORM}-online.zip : "gvSIG-desktop-\\([0-9.]*-[0-9]*\\)")
    export PORTABLE_STATUS=$(expr *${ONLINE_OS}-${PORTABLE_PLATFORM}-online.zip : "gvSIG-desktop-[0-9.]*-[0-9]*-\\([a-zA-Z]*[0-9]*\)")
    export PORTABLE_NAME="gvSIG-desktop-$PORTABLE_VERSION-${PORTABLE_STATUS}-${PORTABLE_OS}-${PORTABLE_PLATFORM}"

    export PORTABLE_VERSION_WITHOUT_BUILDNUMBER="${PORTABLE_VERSION/-*/}"
    export INSTALL_FOLDER="$TARGET/$PORTABLE_NAME"

    logger_info "
=
=    Creating portable for ${PORTABLE_OSNAME} (${PORTABLE_OSFAMILY}/${PORTABLE_OS}/${PORTABLE_PLATFORM} - online os ${ONLINE_OS})
=
    "
    logger_info "Removing previous files"
    rm -rf "$TARGET/gvsig-desktop"
    rm -rf "$INSTALL_FOLDER"
    rm -f  "$TARGET/${PORTABLE_NAME}"
    rm -f  "$TARGET/${PORTABLE_NAME}.zip"
    rm -rf "$TARGET/packages-${PORTABLE_OS}-${PORTABLE_PLATFORM}"

    logger_info "Uncompressing ${PORTABLE_OSNAME} (${ONLINE_OS}) base files"
    cd $TARGET
    mkdir $PORTABLE_NAME
    cd $PORTABLE_NAME
    ff="$BASEFOLDER/standard/gvSIG-desktop-$PORTABLE_VERSION-$PORTABLE_STATUS-${ONLINE_OS}-${PORTABLE_PLATFORM}-online.zip"
    if [ ! -f "$ff" ] ; then
       echo "ERROR: Can't locate online zip for ${PORTABLE_OSNAME} (${PORTABLE_OSFAMILY}/${PORTABLE_OS}/${PORTABLE_PLATFORM} - online os ${ONLINE_OS})"
       echo "ERROR: Expected file $ff"
       exit 1
    fi
    unzip -nqq "$ff"

    logger_info "Uncompressing ${PORTABLE_OSNAME}-${PORTABLE_PLATFORM} package set"
    mkdir -p "$TARGET/packages-${PORTABLE_OS}-${PORTABLE_PLATFORM}"
    cd "$TARGET/packages-${PORTABLE_OS}-${PORTABLE_PLATFORM}"
    ff="$BASEFOLDER/standard/gvSIG-desktop-${PORTABLE_VERSION}-${PORTABLE_STATUS}-${PORTABLE_OS}-${PORTABLE_PLATFORM}.gvspks"
    if [ ! -f "$ff" ] ; then
       echo "ERROR: Can't locate package set for ${PORTABLE_OSNAME} (${PORTABLE_OSFAMILY}/${PORTABLE_OS}/${PORTABLE_PLATFORM} - online os ${ONLINE_OS})"
       echo "ERROR: Expected file $ff"
       exit 1
    fi
    unzip -nqq "$ff"

    download_jre

    echo "Remove platform independent GDAL version"
    echo "... package $TARGET/packages-${PORTABLE_OS}-${PORTABLE_PLATFORM}/gvSIG-desktop-${PORTABLE_VERSION/-*/}-org.gvsig.gdal.app.mainplugin-"*-all-all-j1_7.gvspkg
    rm -f "$TARGET/packages-${PORTABLE_OS}-${PORTABLE_PLATFORM}/gvSIG-desktop-${PORTABLE_VERSION/-*/}-org.gvsig.gdal.app.mainplugin-"*-all-all-j1_7.gvspkg

    install_packages "$INSTALL_FOLDER" "$TARGET/packages-${PORTABLE_OS}-${PORTABLE_PLATFORM}"

    install_packages "$INSTALL_FOLDER" "$BASEFOLDER/packages/custom"

    install_portable_configuration_files

    remove_excluded_packages

    if [ -f $PATCHSFOLDER/patchs.sh ] ; then
        chmod a+x $PATCHSFOLDER/patchs.sh
        logger_info "Appling patch to the instalation."
        source $PATCHSFOLDER/patchs.sh
    fi

    run_plugins_install_scripts $INSTALL_FOLDER

    case "$PORTABLE_OSFAMILY" in
    darwin)
        prepare_portable_macos
        rm -rf "${INSTALL_FOLDER}.app"
        mv "$INSTALL_FOLDER" "${INSTALL_FOLDER}.app"
        INSTALL_FOLDER="${INSTALL_FOLDER}.app"
        PORTABLE_NAME="${PORTABLE_NAME}.app"
        ;;
    win)
        expandsVarsOnFile "${INSTALL_FOLDER}/gvsig-desktop.vbs"
        expandsVarsOnFile "${INSTALL_FOLDER}/gvsig-desktop.cmd"
        expandsVarsOnFile "${INSTALL_FOLDER}/gvsig-package-installer.cmd"
        ;;
    esac

    logger_info "Compresing ${PORTABLE_OSNAME}-${PORTABLE_PLATFORM} portable (this take a moment)"
    cd "$TARGET"
    zipfolder "${PORTABLE_NAME}.zip" "${PORTABLE_NAME}"

    logger_info "Removing temporary package folder"
    rm -rf $TARGET/packages-${PORTABLE_OS}-${PORTABLE_PLATFORM}

    logger_info "
=
=    Portable created for ${PORTABLE_OSNAME} (${PORTABLE_OSFAMILY}/${PORTABLE_OS}/${PORTABLE_PLATFORM} - online os ${ONLINE_OS})
=
    "
}


function main() {
    mkdist lin linux x86_64
    mkdist win windows x86_64
    mkdist lin linux x86
    mkdist win windows x86
    #mkdist lin_ubuntu_14.04 linux x86
    #mkdist lin_ubuntu_14.04 linux x86_64
    #mkdist darwin_macos_10.11 darwin x86_64
    echo "Creation ended"
}

mkdir -p "$TARGET"
main | tee "$TARGET/${SCRIPT_NAME}.log"

