#!/bin/bash -e
#
# Provides commonly used functions and variables

common_initialize_environment() {
    # Code files relevant for version
    SRC_OPENEMS_CONSTANTS="io.openems.common/src/io/openems/common/OpenemsConstants.java"
    SRC_PACKAGE_JSON="ui/package.json"
    SRC_PACKAGE_LOCK_JSON="ui/package-lock.json"
    SRC_CHANGELOG_CONSTANTS="ui/src/app/changelog/view/component/changelog.constants.ts"

    # Set environment variables
    THEME="${THEME:-openems}"
    PACKAGE_NAME="openems-edge"

    VERSION_STRING=""
    VERSION="$(cd ui && node -p "require('./package.json').version" && cd ..)"
    local tmp_version=$(echo $VERSION | cut -d'-' -f1)
    VERSION_MAJOR=$(echo $tmp_version | cut -d'.' -f1)
    VERSION_MINOR=$(echo $tmp_version | cut -d'.' -f2)
    VERSION_PATCH=$(echo $tmp_version | cut -d'.' -f3)
    VERSION_STRING=$(echo $VERSION | cut -s -d'-' -f2)
    VERSION_FULL=$tmp_version
}

common_build_snapshot_version() {
    if [[ "$VERSION" == *"-SNAPSHOT" ]]; then
        # Replace unwanted characters with '.', compliant with Debian version
        # Ref: https://unix.stackexchange.com/a/23673
        VERSION_DEV_BRANCH="$(git branch --show-current)"
        VERSION_DEV_COMMIT=""
        git diff --exit-code --quiet
        if [ $? -ne 0 ]; then
            VERSION_DEV_COMMIT="dirty"
        else
            VERSION_DEV_COMMIT="$(git rev-parse --short HEAD)"
        fi
        VERSION_DEV_BUILD_TIME=$(date "+%Y%m%d.%H%M")
        # Compliant with https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-version
        VERSION_STRING="$(echo $VERSION_DEV_BRANCH | tr -cs 'a-zA-Z0-9\n' '.').${VERSION_DEV_BUILD_TIME}.${VERSION_DEV_COMMIT}"
        VERSION="${VERSION/-SNAPSHOT/"-${VERSION_STRING}"}"
    fi
}

# Inserts the version number into the Code
common_update_version_in_code() {
    echo "# Update version in Code"
    echo "## Update $SRC_OPENEMS_CONSTANTS"
    sed --in-place "s#\(VERSION_MAJOR = \)\([0-9]\+\);#\1$VERSION_MAJOR;#" $SRC_OPENEMS_CONSTANTS
    sed --in-place "s#\(VERSION_MINOR = \)\([0-9]\+\);#\1$VERSION_MINOR;#" $SRC_OPENEMS_CONSTANTS
    sed --in-place "s#\(VERSION_PATCH = \)\([0-9]\+\);#\1$VERSION_PATCH;#" $SRC_OPENEMS_CONSTANTS
    sed --in-place "s#\(VERSION_STRING = \)\"\(.*\)\";#\1\"$VERSION_STRING\";#" $SRC_OPENEMS_CONSTANTS
    sed --in-place "s#\(VERSION_DEV_BRANCH = \)\"\(.*\)\";#\1\"${VERSION_DEV_BRANCH}\";#" $SRC_OPENEMS_CONSTANTS
    sed --in-place "s#\(VERSION_DEV_COMMIT = \)\"\(.*\)\";#\1\"$VERSION_DEV_COMMIT\";#" $SRC_OPENEMS_CONSTANTS
    sed --in-place "s#\(VERSION_DEV_BUILD_TIME = \)\"\(.*\)\";#\1\"$VERSION_DEV_BUILD_TIME\";#" $SRC_OPENEMS_CONSTANTS

    echo "## Update $SRC_PACKAGE_JSON"
    sed --in-place "s#^\(  \"version\": \"\).*\(\".*$\)#\1$VERSION\2#" $SRC_PACKAGE_JSON

    echo "## Update $SRC_PACKAGE_LOCK_JSON"
    sed --in-place "s#^\(  \"version\": \"\).*\(\".*$\)#\1$VERSION\2#" $SRC_PACKAGE_LOCK_JSON

    echo "## Update $SRC_CHANGELOG_CONSTANTS"
    sed --in-place "s#\(UI_VERSION = \"\).*\(\";\)#\1$VERSION\2#" $SRC_CHANGELOG_CONSTANTS
}

common_print_banner() {
    local text="$1"
    local len="${#text}"
    printf "\n"
    printf ' %*s \n' "$len" '' | tr ' ' '='
    printf ' %s \n' "$text"
    printf ' %*s \n' "$len" '' | tr ' ' '='
}

# Build OpenEMS Backend
common_build_backend() {
    common_print_banner "Build OpenEMS Backend"
    ./gradlew "$@" --build-cache build buildBackend resolve.BackendApp
    git diff --exit-code io.openems.backend.application/BackendApp.bndrun
}

# Build OpenEMS Edge and UI in parallel
common_build_edge_and_ui_in_parallel() {
    # TODO use 'parallel' tool for reliable implementation
    common_build_edge
    common_build_ui
}


# Build OpenEMS Edge
common_build_edge() {
    common_print_banner "Build OpenEMS Edge"
    ./gradlew "$@" --build-cache build buildEdge resolve.EdgeApp
    git diff --exit-code io.openems.edge.application/EdgeApp.bndrun
}

# Run OpenEMS Checkstyle
common_run_checkstyle() {
    common_print_banner "Run Checkstyle"
    ./gradlew "$@" checkstyleAll
}

# Build OpenEMS UI
common_build_ui() {
    common_print_banner "Build OpenEMS UI"
    if [ "${NODE_MODULES_CACHE}" != "" -a -d "$NODE_MODULES_CACHE" ]; then
        echo "## Use cached node_modules"
        mv -f "${NODE_MODULES_CACHE}" "ui/node_modules"
    fi
    cd ui

    # Install dependencies from package.json
    npm ci
    if [ "${NG_CLI_CACHE_PATH}" != "" ]; then
        echo "## Angular Cache: $NG_CLI_CACHE_PATH"
        node_modules/.bin/ng config cli.cache.path "$NG_CLI_CACHE_PATH"
    fi
    # Lint and Build
    node_modules/.bin/ng lint
    node_modules/.bin/ng build -c "${THEME},${THEME}-edge-prod,prod"
    cd ..

    if [ "${NODE_MODULES_CACHE}" != "" ]; then
        echo "## Refresh node_modules cache"
        mv -f "ui/node_modules" "${NODE_MODULES_CACHE}"
    fi
}

common_build_android_app() {
    echo "# Build OpenEMS Android APP"
    if [ "${NODE_MODULES_CACHE}" != "" -a -d "$NODE_MODULES_CACHE" ]; then
        echo "## Use cached node_modules"
        mv -f "${NODE_MODULES_CACHE}" "ui/node_modules"
    fi
    cd ui

    # Install dependencies from package.json
    npm ci
    if [ "${NG_CLI_CACHE_PATH}" != "" ]; then
        echo "## Angular Cache: $NG_CLI_CACHE_PATH"
        node_modules/.bin/ng config cli.cache.path "$NG_CLI_CACHE_PATH"
    fi

    case "${THEME^^}" in
        "EXAMPLE") NODE_ENV="EXAMPLE";;
    esac

    # Install depencencies for capacitor
    NODE_ENV=${NODE_ENV} ionic cap build android -c "${THEME},${THEME}-backend-prod" --no-open

    # Build App
    cd android
    THEME=${THEME} ./gradlew buildThemeRelease

    cd ../..
}

common_build_ios_app() {

    CONFIGURATION="Release"
    echo "Building ios app with $THEME and for $CONFIGURATION"
    cd ui

    # Install dependencies from package.json
    npm ci

    # Schemes respresent targets
    case "${THEME:u}" in
    "EXAMPLE") NODE_ENV="EXAMPLE" SCHEME="App" ;;
    esac

    # Build app
    NODE_ENV=${NODE_ENV} ./node_modules/.bin/ionic cap build ios -c "${THEME},${THEME}-backend-prod" --no-open
    cd ios/App

    # Install capacitor deps
    pod install

    # Update marketing version
    ruby ../../../tools/deploy/ios/update_marketing_version.rb $SCHEME

    # Unlock security keychain to access signing certificates and provisioning profiles
    security unlock-keychain -p $KEYCHAIN_PASSWORD login.keychain

    echo "\n======Building & Archiving=====\n"
    xcodebuild -scheme $SCHEME -workspace App.xcworkspace -configuration $CONFIGURATION clean archive -archivePath App/output/$SCHEME.xcarchive -destination 'generic/platform=iOS' -allowProvisioningUpdates \
        -authenticationKeyID $AUTHENTICATION_KEY_ID \
        -authenticationKeyIssuerID $AUTHENTICATION_KEY_ISSUER_ID \
        -authenticationKeyPath $AUTHENTICATION_KEY_PATH \
        -quiet

    echo "\n=====Exporting/Upload=====\n"
    xcodebuild -exportArchive -archivePath App/output/$SCHEME.xcarchive -exportOptionsPlist ExportOptions.plist -exportPath $SCHEME.ipa -quiet
    echo "\nVersion is ready to be used for a release\n"
}

common_save_environment() {
    local file=${1:-build.environment}
    echo "
    export VERSION=\"$VERSION\"
    export VERSION_MAJOR=\"$VERSION_MAJOR\"
    export VERSION_MINOR=\"$VERSION_MINOR\"
    export VERSION_PATCH=\"$VERSION_PATCH\"
    export VERSION_STRING=\"$VERSION_STRING\"
    export VERSION_DEV_BRANCH=\"$VERSION_DEV_BRANCH\"
    export VERSION_DEV_COMMIT=\"$VERSION_DEV_COMMIT\"
    export VERSION_DEV_BUILD_TIME=\"$VERSION_DEV_BUILD_TIME\"
    export VERSION_FULL=\"$VERSION_FULL\"
    " | tee $file
}

common_check_file() {
    local file=$1
    local error_message=${2:-"File not found!"}
    if [ ! -f "$file" ]; then
        echo "Error: $error_message"
        exit 1
    fi
}