#!/bin/bash
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

unset OPENJ9_JAVA_OPTIONS

# Default size for SCC
SCC_SIZE="50m"

# Runs for generating SCC
SCC_GEN_RUNS_COUNT=3

# is running on ubuntu or debian - package manager apt
IS_APT_ENV=false
# Intitialise default / allowed sample app status
RUN_ECLIPSE=false
RUN_TOMCAT=true

# Intitialise default / required packages status
INSTALL_GTK=false
INSTALL_XVFB=false

# App download locations
DOWNLOAD_PATH_ECLIPSE=/tmp/eclipse
DOWNLOAD_PATH_TOMCAT=/tmp/tomcat

# App installation locations
INSTALL_PATH_ECLIPSE="${HOME}"/eclipse-home
INSTALL_PATH_TOMCAT="${HOME}"/tomcat-home

# URL's for the artifacts
ECLIPSE_DWNLD_URL="http://www.mirrorservice.org/sites/download.eclipse.org/eclipseMirror/technology/epp/downloads/release/2020-06/M3/eclipse-java-2020-06-M3-linux-gtk-x86_64.tar.gz"
TOMCAT_DWNLD_URL="https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.35/bin/apache-tomcat-9.0.35.tar.gz"

# Check and downlaod eclipse
function check_to_download_eclipse() {
    if [ "${RUN_ECLIPSE}" == true ]; then
        # Creating a temporary directory for eclipse download
        mkdir -p "${DOWNLOAD_PATH_ECLIPSE}" "${INSTALL_PATH_ECLIPSE}"

        # Downloading eclipse
        if curl --fail -o "${DOWNLOAD_PATH_ECLIPSE}"/eclipse.tar.gz  "${ECLIPSE_DWNLD_URL}"; then
            # Extracting eclipse
            tar -xvzf "${DOWNLOAD_PATH_ECLIPSE}"/eclipse.tar.gz -C "$INSTALL_PATH_ECLIPSE" --strip-components=1
        else
            RUN_ECLIPSE=false
        fi

        # Removing the tar file
        rm -rf "${DOWNLOAD_PATH_ECLIPSE}"
    fi
}

# Check and download tomcat
function check_to_download_tomcat() {
    if [ "${RUN_TOMCAT}" == true ]; then
        # Creating a temporary directory for tomcat download
        mkdir -p "${DOWNLOAD_PATH_TOMCAT}" "${INSTALL_PATH_TOMCAT}"

        # Downloading tomcat
        if curl --fail -o "${DOWNLOAD_PATH_TOMCAT}"/tomcat.tar.gz "${TOMCAT_DWNLD_URL}"; then
            # Extracting tomcat
            tar -xvzf "${DOWNLOAD_PATH_TOMCAT}"/tomcat.tar.gz -C "${INSTALL_PATH_TOMCAT}" --strip-components=1
        else
            RUN_TOMCAT=false
        fi

        # Removing the tar file
        rm -rf "${DOWNLOAD_PATH_TOMCAT}"
    fi
}

# ubuntu/debian install packages required for eclipse
function apt_install_packages() {
    # update the repositories
    apt update

    # Set non-interactive frontend (to avoid `tzdata` config options selection)
    APT_INSTALL_CMD="DEBIAN_FRONTEND=noninteractive"
    APT_INSTALL_CMD="${APT_INSTALL_CMD} apt install -y"

    if [ "${INSTALL_GTK}" == true ]; then
        # install gtk+3.0
        APT_INSTALL_CMD="${APT_INSTALL_CMD} gtk+3.0"
    fi

    if [ "${INSTALL_XVFB}" == true ]; then
        # install xvfb
        APT_INSTALL_CMD="${APT_INSTALL_CMD} xvfb"
    fi

    eval "${APT_INSTALL_CMD}"
}

# Check if any application needs virtual screen and launch it
function check_and_start_xvfb() {
    # check if `xvfb` installed
    if [ "${INSTALL_XVFB}" == true ]; then
        # Spawning a virtual screen for GUI apps
        Xvfb :1 -ac -screen 0 1024x768x8 &
        # Saving the PID
        XVFB_PID=$!
        # Saving older display value
        OLD_DISPLAY=$DISPLAY
        # Setting DISPLAY to created screen
        export DISPLAY=:1
    fi
}

# Kill the created virtual screen
function check_and_stop_xvfb() {
    # check if `xvfb` installed
    if [ "${INSTALL_XVFB}" == true ]; then
        # Killing `xvfb` process to remove screen
        kill -9 $XVFB_PID
        # Setting back the DISPLAY to older value
        export DISPLAY=$OLD_DISPLAY
    fi
}

# Run the applications for specified iterations
function run_apps() {
    for ((i=0; i<SCC_GEN_RUNS_COUNT; i++))
    do
        if [ "${RUN_ECLIPSE}" == true ]; then
            run_eclipse_and_stop
        fi
        if [ "${RUN_TOMCAT}" == true ]; then
            run_tomcat_and_stop
        fi
    done
}

# function to install packages
function install_packages() {
    if [ "${IS_APT_ENV}" == true ]; then
        apt_install_packages
    fi
}

# function to download the applications
function download_and_install_artifacts() {

    # check for eclipse
    check_to_download_eclipse

    # check for tomcat
    check_to_download_tomcat

}

# dry run to right size the cache
function dry_run() {
    # Creating base layer first instead of running sample programs to generate SCC directly
    java -Xshareclasses:name=dry_run_scc,cacheDir=/opt/java/.scc,bootClassesOnly,nonFatal,createLayer -Xscmx$SCC_SIZE -version

    # Pointing cache for sample program runs
    export OPENJ9_JAVA_OPTIONS="-Xshareclasses:name=dry_run_scc,cacheDir=/opt/java/.scc,bootClassesOnly,nonFatal"

    # check if we need xvfb for running application and start a virtual screen if required
    check_and_start_xvfb

    # Run the applications to generate SCC
    run_apps

    # check if started a virtual screen and kill the process
    check_and_stop_xvfb

    FULL=$( (java -Xshareclasses:name=dry_run_scc,cacheDir=/opt/java/.scc,printallStats || true) 2>&1 | awk '/^Cache is [0-9.]*% .*full/ {print substr($3, 1, length($3)-1)}')

    java -Xshareclasses:name=dry_run_scc,cacheDir=/opt/java/.scc,destroy || true

    SCC_SIZE="${SCC_SIZE:0:-1}"

    SCC_SIZE=$(awk "BEGIN {print int($SCC_SIZE * $FULL / 100.0)}")

    [ "${SCC_SIZE}" -eq 0 ] && SCC_SIZE=1

    SCC_SIZE="${SCC_SIZE}m"

    # Re-generating cache with new size
    java -Xshareclasses:name=openj9_system_scc,cacheDir=/opt/java/.scc,bootClassesOnly,nonFatal,createLayer -Xscmx$SCC_SIZE -version

    unset OPENJ9_JAVA_OPTIONS
}

# Generate SCC by running apps
function generate_scc() {
    # Pointing cache for sample app runs
    export OPENJ9_JAVA_OPTIONS="-Xshareclasses:name=openj9_system_scc,cacheDir=/opt/java/.scc,bootClassesOnly,nonFatal"

    # check if we need xvfb for running application and start a virtual screen if required
    check_and_start_xvfb

    # Run the applications to generate SCC
    run_apps

    # check if started a virtual screen and kill the process
    check_and_stop_xvfb

    # Checking the cache level
    FULL=$( (java -Xshareclasses:name=openj9_system_scc,cacheDir=/opt/java/.scc,printallStats || true) 2>&1 | awk '/^Cache is [0-9.]*% .*full/ {print substr($3, 1, length($3)-1)}')

    echo "SCC layer is $FULL% full."
}

# Remove the downloaded sample apps
function remove_artifacts() {
    # Command to remove apps
    REMOVE_APPS="rm -rf"

    # check for eclipse
    if [ "${RUN_ECLIPSE}" == true ]; then
        REMOVE_APPS="${REMOVE_APPS} ${INSTALL_PATH_ECLIPSE}"
    fi

    # check for tomcat
    if [ "${RUN_TOMCAT}" == true ]; then
        REMOVE_APPS="${REMOVE_APPS} ${INSTALL_PATH_TOMCAT}"
    fi

    eval "$REMOVE_APPS"
}

# Run eclipse and stop it after the startup
function run_eclipse_and_stop() {
    # Starting eclipse in background
    "${INSTALL_PATH_ECLIPSE}"/eclipse/eclipse &
    # Saving eclipse PID
    ECLIPSE_PID=$!
    # Waiting for eclipse to start - Sleeping for 1 minute
    sleep 1m
    # Killing eclipse process
    kill -9 $ECLIPSE_PID
    # Waiting for process to be killed - Sleeping for 10 seconds
    sleep 10s
}

# Run tomcat and stop it after the startup
function run_tomcat_and_stop() {
    # Start tomcat wait till it comes up shut it down
    "${INSTALL_PATH_TOMCAT}"/bin/startup.sh
    # wait till tomcat starts -  wait for 5 seconds
    sleep 5
    # Stop tomcat
    "${INSTALL_PATH_TOMCAT}"/bin/shutdown.sh
    # wait till tomcat stops -  wait for 5 seconds
    sleep 5
}

# Remove the installed packages
function remove_packages() {
    if [ "${IS_APT_ENV}" == true ]; then
        APT_REMOVE_CMD="apt --purge -y autoremove"

        if [ "${INSTALL_GTK}" == true ]; then
            # remove gtk+3.0
            APT_REMOVE_CMD="${APT_REMOVE_CMD} gtk+3.0"
        fi

        if [ "${INSTALL_XVFB}" == true ]; then
            # remove xvfb
            APT_REMOVE_CMD="${APT_REMOVE_CMD} xvfb"
        fi

        eval "${APT_REMOVE_CMD}"
    fi
}

# check for OS release file
if [ -f /etc/os-release ]; then
    # load file to get the ID (OS name)
    # shellcheck disable=SC1091
    source /etc/os-release
    OS=$ID
fi

# Check if OS is ubuntu/debian (we can run eclipse as packages required for it are available)
if [ "${OS}" == "ubuntu" ]  || [ "${OS}" = "debian" ]; then
    # set IS_APT_ENV true
    IS_APT_ENV=true

    # Set eclipse run to `true`
    RUN_ECLIPSE=true

    # Set the required packages for eclipse to `true`
    INSTALL_GTK=true
    INSTALL_XVFB=true

    # Call function `install_pkgs_via_apt` to install packages
    install_packages
fi

# Download the sample apps and install
download_and_install_artifacts

# Dry run for SCC generation (To get exact size)
dry_run

# Generate SCC
generate_scc

# Remove installed artifacts
remove_artifacts

# Remove packages
remove_packages
