#!/bin/bash
# Copyright 2014 BarD Software s.r.o
# This script launches GanttProject. It can be symlinked and can be ran from
# any working directory

SCRIPT_FILE="$0"

# If we can write to /tmp/ganttproject-launcher.log then LOG_TEXT
# will be empty, and we'll write the launcher logs to the file
# Otherwise it will be not empty and will accumulate the
# logged information in memory.
LOG_TEXT=""
echo "" > /tmp/ganttproject-launcher.log || LOG_TEXT="----"

log() {
  if [ -n "$LOG_TEXT" ]; then
    LOG_TEXT="$LOG_TEXT\n$1";
  else
    echo "$1" >> /tmp/ganttproject-launcher.log
  fi
  [ -z "$DEBUG_ARGS" ] || echo $1
}

trap 'print_log' ERR
trap 'print_log' EXIT

print_log() {
  if [ "$?" -eq "0" ]; then
    return;
  fi
  if [ -n "$LOG_TEXT" ]; then
    >&2 echo "$LOG_TEXT"
  else
    >&2 cat /tmp/ganttproject-launcher.log
  fi
}

find_ganttproject_home() {
  WORKING_DIR="$(pwd)"
  # We want to find the directory where the real script file resides.
  # If real file is symlinked (possibly many times) then we need to follow
  # symlinks until we reach the real script
  # After that we run pwd to get directory path
  cd "$(dirname "$SCRIPT_FILE")"
  SCRIPT_FILE="$(basename "$SCRIPT_FILE")"

  while [ -L "$SCRIPT_FILE" ]; do
    SCRIPT_FILE="$(readlink "$SCRIPT_FILE")"
    cd "$(dirname "$SCRIPT_FILE")"
    SCRIPT_FILE="$(basename "$SCRIPT_FILE")"
  done

  pwd
}
GP_HOME="$(find_ganttproject_home)"
if [ -z "$GP_HOME" ]; then
  echo "GanttProject home directory is not set. Please point GP_HOME environment variable to the directory with GanttProject files."
  exit 1
fi

# Parse the command line arguments. In this script we parse only those arguments which
# are related to the Java VM launching. The remaining application-specific arguments
# are passed as-is to the Java process.

USE_BUNDLED_RUNTIME=1
DEBUG_ARGS=""
APP_ARGS=()

while true; do
  case "$1" in
    # Debug will switch on some debugging output and will allow for connecting to Java
    # process with a debugger
    -d|--debug)
      case "$2" in
        +[:digit:])
          DEBUG_ARGS="-agentlib:jdwp=transport=dt_socket,server=y,address=*:$2,suspend=y"
          shift 2
          ;;
        *)
          DEBUG_ARGS="-agentlib:jdwp=transport=dt_socket,server=y,address=*:5005,suspend=y"
          shift 1
          ;;
      esac
      log "Debug arguments: $DEBUG_ARGS"
      ;;
    # This allows for specifying the path to Java Runtime instead of the default bundled Java Runtime
    -j|--java-home)
      USE_BUNDLED_RUNTIME=0
      if [ -d "$2" ]; then
        JAVA_HOME="$2"
        log "Using JAVA_HOME=$2"
        shift 2
      else
        log "This is not a directory: $2"
        exit 1
      fi
      ;;
    "")
      break;
      ;;
    *)
      APP_ARGS+=("$1")
      shift 1
      ;;
  esac
done

# Create log directory
GP_LOG_DIR="$HOME/.ganttproject.d/logs"
# Check if log dir is present (or create it)
if [ ! -d "$GP_LOG_DIR" ]; then
  if [ -e  "$GP_LOG_DIR" ]; then
    echo "File $GP_LOG_DIR exists and is not a directory. Please remove it and launch $SCRIPT_FILE again" >&2
    exit 1
  fi
  if ! mkdir -p "$GP_LOG_DIR" ; then
    echo "Could not create $GP_LOG_DIR directory. Is directory $HOME writable?" >&2
    exit 1
  fi
fi

# Create unique name for the application log file
LOG_FILE="$GP_LOG_DIR/.ganttproject-"$(date +%Y%m%d%H%M%S)".log"
if [ -e "$LOG_FILE" ] && [ ! -w "$LOG_FILE" ]; then
  echo "Log file $LOG_FILE is not writable" >2
  exit 1
fi

# This function checks if the passed argument is a good java command.
# It is expected to be executable and expected to return version 11+ when launched with -version
# argument.
check_java() {
  JAVA_COMMAND=$1
  log  "Searching for Java in $JAVA_COMMAND"

  if [ ! -x "$JAVA_COMMAND" ]; then
    log "...missing or not executable"
    JAVA_COMMAND=""
    return 1
  fi

  VERSION="$( $JAVA_COMMAND -version 2>&1 | grep version | head -n 1)"
  log "...found $VERSION"
  [[ "$VERSION" =~ 11\.? ]] && return 0;
  [[ "$VERSION" =~ 12\.? ]] && return 0;
  [[ "$VERSION" =~ 13\.? ]] && return 0;
  [[ "$VERSION" =~ 14\.? ]] && return 0;
  [[ "$VERSION" =~ 15\.? ]] && return 0;
  [[ "$VERSION" =~ 16\.? ]] && return 0;
  [[ "$VERSION" =~ 17\.? ]] && return 0;
  log "...this seems to be an old Java Runtime";
  JAVA_COMMAND=""
  return 1
}

# We search for Java Runtime in the following sequence:
# 1. Try using the bundled runtime in $GP_HOME, unless -j argument is passed
# 2. Try using JAVA_HOME value (this is also set by -j option)
# 3. Try using java command from the classpath
find_java() {
  if [ $USE_BUNDLED_RUNTIME == 1 ]; then
    check_java "$GP_HOME/runtime/bin/java" && return 0;
  fi
  if [ ! -z "$JAVA_HOME" ]; then
    check_java "$JAVA_HOME/bin/java" && return 0;
  fi
  JAVA_COMMAND=$(which java)
  if [ "0" = "$?" ]; then
    check_java "$JAVA_COMMAND" && return 0;
  fi
  if [ -d /usr/lib/jvm ]; then
    for d in /usr/lib/jvm/*; do
      check_java "$d/bin/java" && return 0;
    done;
  fi

  report_java_not_found && exit 1;
}

report_java_not_found() {
  log "JavaVM executable not found.
  You may want to set the path to the root of your Java Runtime installation
  in JAVA_HOME environment variable or pass it to ganttproject in --java-home argument";
}

# Create updates directory if not exists
USER_UPDATES_DIR="$HOME/.ganttproject.d/updates"
mkdir -p "$USER_UPDATES_DIR"

find_java

if [ ! -f "$GP_HOME/eclipsito.jar" ]; then
  log "Can't find the required Eclipsito library at $GP_HOME/eclipsito.jar"
  exit 1
fi
CLASSPATH="$CLASSPATH:$GP_HOME/eclipsito.jar:$GP_HOME"
export CLASSPATH
BOOT_CLASS=com.bardsoftware.eclipsito.Launch

log "JAVA_HOME=$JAVA_HOME"
log "JAVA_COMMAND=$JAVA_COMMAND"
log "GP_HOME=$GP_HOME"
log "user.dir=$(pwd)"

JAVA_EXPORTS="--module-path "/usr/lib/jvm/openjfx17" \
	--add-modules=javafx.base,javafx.graphics,javafx.controls,javafx.swing,java.desktop"

"$JAVA_COMMAND" -Xmx1024m $JAVA_EXPORTS -Duser.dir="$(pwd)" $DEBUG_ARGS $BOOT_CLASS \
  --app net.sourceforge.ganttproject.GanttProject \
  --version-dirs "$GP_HOME"/plugins:~/.ganttproject.d/updates \
  -log true -log_file "$LOG_FILE" "${APP_ARGS[@]}"
