#!/usr/bin/env bash
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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
#
#    http://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.
#

export DEFAULT_MYSQL_VERSION=5.1.39

if [[ -L ${BASH_SOURCE-$0} ]]; then
  FWDIR=$(dirname $(readlink "${BASH_SOURCE-$0}"))
else
  FWDIR=$(dirname "${BASH_SOURCE-$0}")
fi

if [[ -z "${SUBMARINE_HOME}" ]]; then
  # Make SUBMARINE_HOME look cleaner in logs by getting rid of the
  # extra ../
  export SUBMARINE_HOME="$(cd "${FWDIR}/.."; pwd)"
fi

if [[ -z "${SUBMARINE_CONF_DIR}" ]]; then
  export SUBMARINE_CONF_DIR="${SUBMARINE_HOME}/conf"
fi

if [[ -z "${SUBMARINE_LOG_DIR}" ]]; then
  export SUBMARINE_LOG_DIR="${SUBMARINE_HOME}/logs"
fi

if [[ -f "${SUBMARINE_CONF_DIR}/submarine-env.sh" ]]; then
  . "${SUBMARINE_CONF_DIR}/submarine-env.sh"
fi

SUBMARINE_SERVER_CLASSPATH+=":${SUBMARINE_CONF_DIR}"

function add_each_jar_in_dir(){
  if [[ -d "${1}" ]]; then
    for jar in $(find -L "${1}" -maxdepth 1 -name '*jar'); do
      SUBMARINE_SERVER_CLASSPATH="$jar:$SUBMARINE_SERVER_CLASSPATH"
    done
  fi
}

function add_each_jar_in_dir_recursive(){
  if [[ -d "${1}" ]]; then
    for jar in $(find -L "${1}" -type f -name '*jar'); do
      SUBMARINE_SERVER_CLASSPATH="$jar:$SUBMARINE_SERVER_CLASSPATH"
    done
  fi
}

function add_jar_in_dir(){
  if [[ -d "${1}" ]]; then
    SUBMARINE_SERVER_CLASSPATH="${1}/*:${SUBMARINE_SERVER_CLASSPATH}"
  fi
}

function download_mysql_jdbc_jar(){
  if [[ -z "${MYSQL_JAR_URL}" ]]; then
    if [[ -z "${MYSQL_VERSION}" ]]; then
      MYSQL_VERSION="${DEFAULT_MYSQL_VERSION}"
    fi
    MYSQL_JAR_URL="https://repo1.maven.org/maven2/mysql/mysql-connector-java/${MYSQL_VERSION}/mysql-connector-java-${MYSQL_VERSION}.jar"
  fi

  echo "Downloading mysql jdbc jar from ${MYSQL_JAR_URL}."
  if type wget >/dev/null 2>&1; then
    wget ${MYSQL_JAR_URL} -P "${SUBMARINE_HOME}/lib" --no-check-certificate
  elif type curl >/dev/null 2>&1; then
    curl -o "${SUBMARINE_HOME}/lib/mysql-connector-java-${MYSQL_VERSION}.jar" ${MYSQL_JAR_URL}
  else
    echo 'We need a tool to transfer data from or to a server. Such as wget/curl.'
    echo 'Bye, bye!'
    exit 1
  fi

  echo "Mysql jdbc jar is downloaded and put in the path of submarine/lib."
}

JAVA_OPTS+=" -Dfile.encoding=UTF-8"
JAVA_OPTS+=" -Dlog4j.configuration=file://${SUBMARINE_CONF_DIR}/log4j.properties"
export JAVA_OPTS

if [[ -n "${JAVA_HOME}" ]]; then
  JAVA_RUNNER="${JAVA_HOME}/bin/java"
else
  JAVA_RUNNER=java
fi
export JAVA_RUNNER
