#!/bin/bash

# function: checkForJava
#
# parameters
#    none
#
# return
#    0 - installed version is Java 8.
#    error code - installed version is not 8.
#

function checkForJava
{
    CURRENT_JAVA_VERSION=$("${CSS_JAVA_HOME}/bin/java" -version 2>&1 | grep version | awk -F '\"' '{print $2}')
    if [ -z "${CURRENT_JAVA_VERSION}" ]
    then
        CURRENT_JAVA_VERSION=$("${CSS_JAVA_HOME}/bin/java" -version 2>&1 | head -n 1 | awk -F '\"' '{print $2}')
    fi
    RC=$?
    logPoint "${CURRENT_JAVA_VERSION}"
    # CURRENT_JAVA_VERSION Should look like 1.8.0_382-382 or 1.8.0_382 or 11.0.22 or 17.0.10
    # This relies on Java Version being in double quotes in the top line of the output of java -version. This seems to hold up.
    if [ ${RC} -ne 0 ]
    then
        generateFatalErrorMessage 142 "${CSS_JAVA_HOME}" "${CONFIG_FILE}"
        return 142
    fi

    if ! grep -c 1.8.0 <<< "${CURRENT_JAVA_VERSION}" > /dev/null
    then
      if grep -c 21 <<< "${CURRENT_JAVA_VERSION}" > /dev/null || grep -c 17 <<< "${CURRENT_JAVA_VERSION}" > /dev/null
      then
        return 0
      fi
    fi
    generateFatalErrorMessage 152  "${CSS_JAVA_HOME}" "${CONFIG_FILE}"
}


# function checkForPostgres
#
# parameters
#   none
#
# return
#   0 - postgres is not installed or not on the PATH
#   1 - postgres is installed and on the PATH
#
# function will determine if postgres is installed and on the PATH

function checkForPostgres
{
    logPoint "Validating Postgres is installed"

    RC=0
	psql --version
    if [ $? -ne 0 ]
    then
        generateWarningErrorMessage 126
        RC=1
    fi
    return ${RC}
}

# function: checkForSpace
#
# parameters
#    $1 - the type of directory for the error message
#    $2 - minimum filesystem size for CSS in MB
#    $3 - filesystem to check (this must be the last parameter always, it could be empty and throw off the other parameters
#    $4 - if empty it will decrement like it was originally programmed. If set to any value, it will not decrement the totals of print that part.
#
# return
#    none
#
# function will check for the minimum file system space for the working directory, artifact repository and
#  the optional backup artifact repository directory.  If the specific directories do not have the proper
#  amount of space, the execution will be stopped

function checkForSpace
{
    DIRECTORY_TYPE="${1}"
    MIN_SIZE=${2}
    FILE_SYSTEM=${3}
    SKIP_DECREMENT=${4}

    # check to see if the mode is pov and adjust the minimum size required
    stringEquals ${MODE} ${POV}
    if [ $? -eq 0 ]
    then
        # need to use bc since expr doesn't handle decimal values, the divide by 1 brings the value back to a whole number
        POV_MIN_SIZE=`echo "${MIN_SIZE} * ${DIRECTORY_SIZE_FACTOR} / 1" | bc`
        logPoint "Adjusting the minimum required file system size from ${MIN_SIZE}MB to ${POV_MIN_SIZE}MB for ${DIRECTORY_TYPE}"
        MIN_SIZE=${POV_MIN_SIZE}
    fi

    variableNotEmpty ${FILE_SYSTEM}
    if [ $? -eq 0 ]
    then
        FS_MNT_PNT=`df -Pm ${FILE_SYSTEM} | egrep -v "Available|tmpfs" | tr -s ' ' | cut -f1 -d' '`

        # find the index in the MNT_PNTS array
        INDEX=0
        for MNT_PNT in `df -Pm | sort | egrep -v "Available|tmpfs" | tr -s ' ' | cut -f1 -d' '`
        do
            stringEquals ${FS_MNT_PNT} ${MNT_PNT}
            if [ $? -eq 0 ]
            then
                break
            else
                INDEX=$((INDEX + 1))
            fi
        done

        AVAILABLE=${AVAILABLE_SPACE[${INDEX}]}

        logPoint "File system ${FILE_SYSTEM} for ${DIRECTORY_TYPE} directory on ${FS_MNT_PNT} mount point has ${AVAILABLE}MB available and needs ${MIN_SIZE}MB"

        if [ ${AVAILABLE} -lt ${MIN_SIZE} ]
        then
            # if prereq mode, then allow continuation of all prereq checks, so no fatal errors
            if [ ${PREREQ_MODE} -eq 1 ]
            then
                generateWarningErrorMessage 102 ${FILE_SYSTEM} ${MIN_SIZE} ${AVAILABLE} "${DIRECTORY_TYPE}"
                CHKSPACE_RC=$?

                return $CHKSPACE_RC
            else
                generateFatalErrorMessage 102 ${FILE_SYSTEM} ${MIN_SIZE} ${AVAILABLE} "${DIRECTORY_TYPE}"
            fi
        elif [ "${SKIP_DECREMENT}" = "" ]
        then
            # adjust the array for the possible next file system check, could be the same mount
            ADJUSTED_AVAILABLE=`expr ${AVAILABLE} - ${MIN_SIZE}`
            AVAILABLE_SPACE[${INDEX}]=${ADJUSTED_AVAILABLE}

            logPoint "File system ${FILE_SYSTEM} for ${DIRECTORY_TYPE} directory on ${FS_MNT_PNT} mount point has ${ADJUSTED_AVAILABLE}MB adjusted available for next file system"
        fi
    fi
}

# function: checkAllFileSystemSizes
#
# parameters
#    none
#
# return
#    none
#
# function will check each of the expected file systems for the appropriate amount of space

function checkAllFileSystemSizes
{
    # need to keep track of any one of the directory checks that may have failed, one need one for the overall return code
    # can't just save the last return code as that may have passed but a prior one didn't.  The directory variable must be the
    # last parameter passed to the checkForSpace function because it could be empty and will throw off the other parameters
    OVERALL_SPACE_RC=0
    if [ ${EXECUTION_STATE} -eq ${INSTALL} ]
    then
        logPoint "Checking file space for an install."
        checkForSpace "working" ${MIN_WORKING_DIRECTORY_SIZE} ${WORKING_DIRECTORY}
        SPACE_RC=$?
        if [ ${SPACE_RC} -ne 0 -a ${OVERALL_SPACE_RC} -eq 0 ]
        then
            OVERALL_SPACE_RC=${SPACE_RC}
        fi

        checkForSpace "artifact repository" ${MIN_ARTIFACT_REPO_DIRECTORY_SIZE} ${ARTIFACT_REPOSITORY_DIRECTORY}
        SPACE_RC=$?
        if [ ${SPACE_RC} -ne 0 -a ${OVERALL_SPACE_RC} -eq 0 ]
        then
            OVERALL_SPACE_RC=${SPACE_RC}
        fi
    else
        logPoint "Checking file space for an upgrade."
        checkForSpace "upgrade backup" "${MIN_UPGRADE_BACKUP_DIRECTORY_SIZE}" "${UPGRADE_BACKUP_DIRECTORY}"
        SPACE_RC=$?
        if [ ${SPACE_RC} -ne 0 -a ${OVERALL_SPACE_RC} -eq 0 ]
        then
            OVERALL_SPACE_RC=${SPACE_RC}
        fi

        if [ "${IGNORE_ARTIFACT_BACKUP}" -eq 0 ] && [ "${SKIP_ARTIFACT_SIZE_CHECK}" -eq 0 ]
        then
            CURRENT_PWD=`pwd`
            cdOrFail "${ARTIFACT_REPOSITORY_DIRECTORY}"
            logPoint "Checking the size of the artifacts directory to calculate backup requirements. This may take some time."
            logPoint "If you have already backed up the artifacts or the entire VM, consider running with the -a parameter."
            ARTIFACT_SIZE=`du -m --max-depth 0 | cut -f1`
            cdOrFail "${CURRENT_PWD}"
            checkForSpace "backup artifact repository" "${ARTIFACT_SIZE}" "${UPGRADE_BACKUP_ARTIFACTS_DIRECTORY}"
            SPACE_RC=$?
            if [ ${SPACE_RC} -ne 0 ] && [ ${OVERALL_SPACE_RC} -eq 0 ]
            then
                OVERALL_SPACE_RC=${SPACE_RC}
            fi
        elif [ "${IGNORE_ARTIFACT_BACKUP}" -eq 1 ]
        then
            logPoint "Skipping file size check for artifacts backup as artifact backup is being skipped."
        fi

        if [ ${SKIP_PLUGIN_SIZE_CHECK} -eq 0 ]
        then
            CURRENT_PWD=$(pwd)
            cd "${WORKING_DIRECTORY}/plugins"
                PLUGINS_EXIST=$?
            if [ ${PLUGINS_EXIST} -eq 0 ]
            then
                logPoint "Checking the size of the plugins directory to calculate backup requirements. This may take some time."
                PLUGIN_SIZE=$(du -m --max-depth 0 | cut -f1)
                cdOrFail "${CURRENT_PWD}"
                checkForSpace "backup plugins" "${PLUGIN_SIZE}" "${UPGRADE_BACKUP_PLUGINS_DIRECTORY}"
                SPACE_RC=$?
                if [ ${SPACE_RC} -ne 0 ] && [ ${OVERALL_SPACE_RC} -eq 0 ]
                then
                    OVERALL_SPACE_RC=${SPACE_RC}
                fi
            else
                logPoint "No plugins found at ${WORKING_DIRECTORY}/plugins."
                logPoint "This is expected for older versions of CSS which stored them in the database instead."
            fi
        fi
        variableEmpty "${BACKUP_DATABASE_DIRECTORY}"
        emptyVar=$?
        isPostgresDatabase
        postgresDB=$?
        if [ "${IGNORE_DB_BACKUP}" -eq 0 ] && [ ${emptyVar} -ne 0 ] && [ ${postgresDB} -eq 0 ]
        then
            checkForSpace "database backup" "${MIN_BACKUP_DATABASE_DIRECTORY_SIZE}" "${BACKUP_DATABASE_DIRECTORY}"
            SPACE_RC=$?
            if [ ${SPACE_RC} -ne 0 ] && [ ${OVERALL_SPACE_RC} -eq 0 ]
            then
                OVERALL_SPACE_RC=${SPACE_RC}
            fi
        fi
    fi

    return ${OVERALL_SPACE_RC}
}

# function: checkDirectoriesAgainstBaseInstall
#
# parameters
#    none
#
# return
#    0 - directory location is not under the base install directory
#    1 - directory location is under the base install directory
#
# function will check to see if any of the configured directories are located under
# the CSS install directory.  Can't allow this as upgrades could overlay and
# the directories would be lost

function checkDirectoriesAgainstBaseInstall
{
    DIR_LOC_RC=0

    sameBaseDirectory ${CSS_HOME} ${WORKING_DIRECTORY}
    if [ $? -eq 0 ]
    then
        generateWarningErrorMessage 104 "WORKING_DIRECTORY" ${WORKING_DIRECTORY} ${CSS_HOME}
        DIR_LOC_RC=$?
    fi

    sameBaseDirectory ${CSS_HOME} ${ARTIFACT_REPOSITORY_DIRECTORY}
    if [ $? -eq 0 ]
    then
        generateWarningErrorMessage 104 "ARTIFACT_REPOSITORY_DIRECTORY" ${ARTIFACT_REPOSITORY_DIRECTORY} ${CSS_HOME}
        DIR_LOC_RC=$?
    fi

    sameBaseDirectory ${CSS_HOME} ${UPGRADE_BACKUP_ARTIFACTS_DIRECTORY}
    if [ $? -eq 0 ]
    then
        generateWarningErrorMessage 104 "UPGRADE_BACKUP_ARTIFACTS_DIRECTORY" ${UPGRADE_BACKUP_ARTIFACTS_DIRECTORY} ${CSS_HOME}
        DIR_LOC_RC=$?
    fi

    return ${DIR_LOC_RC}
}

# function: checkDatabaseType
#
# parameters
#    none
#
# return
#    0 - database type is supported
#    1 - database type is unsupported
#
# function will the DATABASE_TYPE configuration to make sure it is set correctly

function checkDatabaseType
{
    if isOracleDatabase
    then
        return 0
    elif isPostgresDatabase
    then
        return 0
    else
        generateFatalErrorMessage 108 ${DATABASE_TYPE} "DATABASE_TYPE"
        return 1
    fi
}

# function: checkDatabaseConnections
#
# parameters
#    none
#
# return
#    0 - able to connect to the database
#    1 - unable to connect to the database
#
# function will check that the database configuration allows the process to connect to the database
function checkDatabaseConnections
{
    checkDatabaseConnection SYSTEM
    DB_UTIL_RCS=$?
    if [ ${EXECUTION_STATE} -ne ${INSTALL} ]
    then
        checkDatabaseConnection USER
        DB_UTIL_RCS2=$?
        DB_UTIL_RCS=`expr ${DB_UTIL_RCS} + ${DB_UTIL_RCS2}`
    fi
    return ${DB_UTIL_RCS}
}

# function: checkDatabaseConnection
#
# parameters
#    1 - SYSTEM or USER - Which user and pw to check.
#
# return
#    0 - able to connect to the database
#    1 - unable to connect to the database
#
# function will check that the database configuration allows the process to connect to the database

function checkDatabaseConnection
{
    # to validate the password
    if [ ${1} = "SYSTEM" ]
    then
        USER=${SYSTEM_DB_USER}
        USER_TYPE="SYSTEM"
        prompt "Enter database system password" ${SYSTEM_DB_PASSWORD}
        SYSTEM_DB_PASSWORD=${PROMPT_VALUE}
        PASSWORD=${PROMPT_VALUE}
    else
        USER=${CSS_DB_USER}
        USER_TYPE="USER"
        prompt "Enter CSS ${CSS_DB_USER} password" ${CSS_DB_PASSWORD}
        CSS_DB_PASSWORD=${PROMPT_VALUE}
        PASSWORD=${PROMPT_VALUE}
    fi    

	${CSS_JAVA_HOME}/bin/java -cp ${DB_UTIL_CLASSPATH} flexagon.css.installer.DatabaseManagement -OPERATION PREREQ -URL ${DATABASE_URL} -DB_USERNAME ${USER} -DB_PASSWORD ${PASSWORD} -LOG_FILE ${LOG_FILE} -PREREQ_USER_TYPE ${USER_TYPE} -SKIP_BACKUP ${IGNORE_DB_BACKUP} -INSTALL_DIR "${INSTALLER_TEMP_SOFTWARE_DIRECTORY}" -BACKUP_DIR "${BACKUP_DATABASE_DIRECTORY}" -PREREQ_OP "${EXECUTION_STATE}"
	DB_UTIL_RC=$?
	handleDbError ${DB_UTIL_RC} "${USER}"
	return ${DB_UTIL_RC}
}


# function: checkRequiredVariables
#
# parameters
#    0 - all required variables are set
#    1 - not all required variables are provided
#
#    ---DEFAULTS---
# CONTAINER_NAME default : css
# CONTAINER_TIMEZONE default: America/Chicago
# DOCKER_RUN_ADDITIONAL_ARGS default: (empty)
# USER_NAMESPACE_OFFSET default: 0
# CSS_PORT default for tomcat : 8000
# CSS_PORT default for docker : 8004
# MAINTAIN_EXISTING_CONTEXT_FILE default : 1
# MAINTAIN_EXISTING_SERVER_FILE default : 1
# WORKING_DIRECTORY default : ${CSS_HOME}/application
# ARTIFACT_REPOSITORY_DIRECTORY default : ${CSS_HOME}/artifacts
#
#    ---Required---
# CSS_DB_PASSWORD REQ
# SYSTEM_DB_USER REQ 
# SYSTEM_DB_PASSWORD REQ
# CSS_INSTALLER_HOME REQ
# CSS_HOME REQ
# BACKUP_DATABASE_DIRECTORY REQ
# DATABASE_URL REQ
#
# return
#    none
# sets the EXECUTION_STATE
# function will verify that all required properties are provided

function checkRequiredVariables
{

    REQ_VAR_RC=0

	# CSS_INSTALLER_HOME
	if variableEmpty ${CSS_INSTALLER_HOME}
	then
		MISSING_VARS="${MISSING_VARS} CSS_INSTALLER_HOME,"
	fi

    # CSS_HOME
    
    if variableEmpty ${CSS_HOME}
    then
        MISSING_VARS="${MISSING_VARS} CSS_HOME,"
    fi

    # CSS_JAVA_HOME
    
    if variableEmpty ${CSS_JAVA_HOME}
    then
        MISSING_VARS="${MISSING_VARS} CSS_JAVA_HOME,"
    fi

    # DATABASE_URL
    if variableEmpty ${DATABASE_URL} 
    then
        MISSING_VARS="${MISSING_VARS} DATABASE_URL,"
    fi

	# BACKUP_DATABASE_DIRECTORY
	
	variableEmpty ${BACKUP_DATABASE_DIRECTORY}
	emptyVar=$?
	isPostgresDatabase
	postgresDB=$?
	if [ ${emptyVar} -ne 0 -a ${postgresDB} -eq 0 ]
	then
		# If postgres database and backup database directory is provided then check to ensure that postgres is installed and able to be called
		checkForPostgres
		if [ $? -eq 0 ]
		then
			REQ_VAR_RC=1
		fi
	fi

    # WORKING_DIRECTORY DEFAULT
    if variableEmpty ${WORKING_DIRECTORY} 
    then
        WORKING_DIRECTORY=${CSS_HOME}/application
    fi
    
    # ARTIFACT_REPOSITORY_DIRECTORY DEFAULT
    if variableEmpty ${ARTIFACT_REPOSITORY_DIRECTORY} 
    then
        ARTIFACT_REPOSITORY_DIRECTORY=${CSS_HOME}/artifacts
    fi

    if [ ${DOCKER_INSTALL} -eq 1 ]
    then
        #CONTAINER_NAME DEFAULT
        if variableEmpty ${CONTAINER_NAME} 
        then
            CONTAINER_NAME=css
        fi

        #CONTAINER_TIMEZONE DEFAULT
        if variableEmpty ${CONTAINER_TIMEZONE} 
        then
            CONTAINER_TIMEZONE=America/Chicago
        fi
        
        #CSS_PORT DEFAULT
        if variableEmpty ${CSS_PORT}
        then
            CSS_PORT=8004
        fi

        validateUserNamespaceOffset
        if [ $? -ne 0 ]
        then
            REQ_VAR_RC=1
        fi
    else

        #CSS_PORT DEFAULT
        if variableEmpty ${CSS_PORT}
        then
            CSS_PORT=8000
        fi

        #MAINTAIN_EXISTING_CONTEXT_FILE DEFAULT
        if variableEmpty ${MAINTAIN_EXISTING_CONTEXT_FILE} 
        then
            MAINTAIN_EXISTING_CONTEXT_FILE=1
        fi

        #MAINTAIN_EXISTING_SERVER_FILE DEFAULT
        if variableEmpty ${MAINTAIN_EXISTING_SERVER_FILE} 
        then
            MAINTAIN_EXISTING_SERVER_FILE=1
        fi

    fi

    # Determine state to determine whether we need system user and password or fd db user and password
    determineState
    EXECUTION_STATE=$?

    # SYSTEM_DB_USER
    
    if variableEmpty ${SYSTEM_DB_USER} 
    then
        MISSING_VARS="${MISSING_VARS} SYSTEM_DB_USER,"
    fi

    # CSS_DB_USER
    
    if variableEmpty ${CSS_DB_USER}
    then
        MISSING_VARS="${MISSING_VARS} CSS_DB_USER,"
    fi
	

	if variableNotEmpty ${MISSING_VARS}
	then
		MISSING_VARS=$(echo ${MISSING_VARS} | sed 's/.$//')
		generateFatalErrorMessage 125 ${CONFIG_FILE} "${MISSING_VARS}" 
		REQ_VAR_RC=$?
        logPoint "The missing configuration properties must be set before running the installer again."
        exit 1
	fi

	return ${REQ_VAR_RC}
}

function checkServerXmlForApacheTomcatCSSReferences
{
    if [ -f "${CSS_HOME}/${APACHE_TOMCAT_CSS_CONF}/${TOMCAT_SERVER_XML}" ]
    then
        HIT=$(grep -c apache-tomcat-css "${CSS_HOME}/${APACHE_TOMCAT_CSS_CONF}/${TOMCAT_SERVER_XML}")
        if [ "${HIT}" -gt 0 ]
        then
            logPoint "Your server.xml file references the apache-tomcat-css folder."
            generateFatalErrorMessage 100 "${CSS_HOME}/${APACHE_TOMCAT_CSS_CONF}/${TOMCAT_SERVER_XML}"
        fi
    fi

}

# function: prerequisites
#
# parameters
#    none
#
# return
#    none
#
# function will execute all of the prerequisite checks

function prerequisites
{
    # need to keep track of any one of the prereq checks that may have failed, one need one for the overall return code
    # can't just save the last return code as that may have passed but a prior one didn't
    OVERALL_PREREQ_RC=${DOWNLOADS_FAILED}

    checkServerXmlForApacheTomcatCSSReferences

    checkForJava
    JAVA_RC=$?
    if [ ${JAVA_RC} -ne 0 -a ${OVERALL_PREREQ_RC} -eq 0 ]
    then
        OVERALL_PREREQ_RC=${JAVA_RC}
    fi

    checkAllFileSystemSizes
    SPACE_RC=$?
    if [ ${SPACE_RC} -ne 0 -a ${OVERALL_PREREQ_RC} -eq 0 ]
    then
        OVERALL_PREREQ_RC=${SPACE_RC}
    fi

    checkDatabaseType
    DBTYPE_RC=$?
    if [ ${DBTYPE_RC} -ne 0 -a ${OVERALL_PREREQ_RC} -eq 0 ]
    then
        OVERALL_PREREQ_RC=${DBTYPE_RC}
    fi

    if [ ${JAVA_RC} -eq 0 ] 
    then
        checkDatabaseConnections
        DBCONNECT_RC=$?
        if [ ${DBCONNECT_RC} -ne 0 -a ${OVERALL_PREREQ_RC} -eq 0 ]
        then
            OVERALL_PREREQ_RC=${DBCONNECT_RC}
        fi
    else
        logPoint "Unable to verify database connection without a valid Java Home. Skipping Database connectivity checks."
    fi

    if [ ${DOCKER_INSTALL} -eq 1 ]
    then
        validateDockerCSSOwnershipPermissions
        DOCKER_OWNERSHIP_RC=$?
        if [ ${DOCKER_OWNERSHIP_RC} -ne 0 -a ${OVERALL_PREREQ_RC} -eq 0 ]
        then
            OVERALL_PREREQ_RC=${DOCKER_OWNERSHIP_RC}
        fi
    fi

    # test to see if there are any customer changes in either the context.xml or server.xml that might be lost
    if [ ${DOCKER_INSTALL} -eq 0 ]
    then
        testOrUpdateContextFile 1
        testOrUpdateServerFile 1
    fi

    if [ ${OVERALL_PREREQ_RC} -eq 0 ] && [ ${PREREQ_MODE} -eq 1 ] && [ "${ERROR_CODES}" = "" ]
    then
            logPoint "Prerequisites have been successfully checked, continue installation without the -p option"
    elif [ ${PREREQ_MODE} -eq 1 ]
    then
            logPoint "Prerequisites checks failed, please resolve and re-run prerequisite checks until successful. See log file ${LOG_FILE}."
    fi

    printWarningSummary
    return ${OVERALL_PREREQ_RC}
}
