#!/usr/bin/env bash
#
# Usage:
#
#  build_example  -b|--base=<path>    - Configurations root folder (e.g., ./.pio/build-BRANCH)
#                 -c|--config=<rel>   - Sub-path of the configs to build (within config/examples)
#                [-e|--export=N]      - Use CONFIG_EXPORT N to export the config to the export location
#                [-a|--archive]       - Archive the build (to the export location)
#                [-o|--output]        - Redirect export / archiving to another location
#                                       (By default export to origin config folder)
#                [-f|--nofail]        - Don't stop on a failed build
#                [-w|--nowarn]        - Suppress warnings with extra config options
#                [-r|--reveal]        - Reveal the config/export folder after the build
#                [-h|--help]          - Print usage and exit
#                [--allow]            - Allow this script to run standalone
#

usage() { echo "Usage:

build_example  -b|--base=<path>    - Configurations root folder (e.g., ./.pio/build-BRANCH)
               -c|--config=<rel>   - Sub-path of the configs to build (within config/examples)
              [-e|--export=N]      - Use CONFIG_EXPORT N to export the config to the export location
              [-a|--archive]       - Archive the build (to the export location)
              [-o|--output]        - Redirect export / archiving to another location
                                     (By default export to origin config folder)
              [-f|--nofail]        - Don't stop on a failed build
              [-w|--nowarn]        - Suppress warnings with extra config options
              [-r|--reveal]        - Reveal the config/export folder after the build
              [-h|--help]          - Print usage and exit
              [--allow]            - Allow this script to run standalone
"
}

HERE=`dirname $0`
PATH="$HERE:$PATH"

. mfutil

annc() { echo -e "\033[0;32m$1\033[0m" ; }

# Get arguments
BUILD=./.pio/build
CLEANER=
ALLOW=
ARCHIVE=
BASE=
CONFIG=
REVEAL=
EXPNUM=
NOFAIL=
OUTBASE=
while getopts 'ab:c:e:fhio:r-:' OFLAG; do
  case "${OFLAG}" in
    a) ARCHIVE=1 ;;
    b) BASE="${OPTARG%/}" ;;
    c) CONFIG="${OPTARG%/}" ;;
    e) EXPNUM="$OPTARG" ;;
    o) OUTBASE="${OPTARG%/}" ;;
    h) EXIT_USAGE=1 ; break ;;
    f) NOFAIL=1 ;;
    r) REVEAL=1 ;;
    -) ONAM="${OPTARG%%=*}" ; OVAL="${OPTARG#*=}"
       case "$ONAM" in
        archive) ARCHIVE=1 ;;
          allow) ALLOW=1 ;;
           base) BASE="${OVAL%/}" ;;
         config) CONFIG="${OVAL%/}" ;;
         export) EXPNUM="$OVAL" ;;
         output) OUTBASE="${OVAL%/}" ;;
           help) EXIT_USAGE=1 ; break ;;
         nofail) NOFAIL=1 ;;
         reveal) REVEAL=1 ;;
              *) EXIT_USAGE=2 ; echo "$SELF: unrecognized option \`--$ONAM'" ; break ;;
       esac
       ;;
    *) EXIT_USAGE=2 ; break ;;
  esac
done
shift $((OPTIND - 1))

# Must be called from another script (or with --allow)
[[ $ALLOW || $SHLVL -gt 2 ]] || { echo "Don't call this script directly, use build_all_examples instead." ; exit 1 ; }

# Exit with helpful usage information
((EXIT_USAGE)) && { usage ; let EXIT_USAGE-- ; exit $EXIT_USAGE ; }

# -b|--base and -c|--config are required
[[ -z $BASE ]] && { echo "-b|--base is required" ; exit 1 ; }
[[ -z $CONFIG ]] && { echo "-c|--config is required" ; exit 1 ; }

# Expand ~ to $HOME in provided arguments
BASE=${BASE/#\~/$HOME}
CONFIG=${CONFIG/#\~/$HOME}

# Make sure the examples exist
SUB1="$BASE/config/examples"
[[ -d "$SUB1" ]] || { echo "-b|--base $BASE doesn't contain config/examples" ; exit 1 ; }

# Make sure the specific config folder exists
SUB="$SUB1/$CONFIG"
[[ -d "$SUB" ]] || { echo "-c|--config $CONFIG doesn't exist" ; exit 1 ; }

# ...and contains Configuration.h or Configuration_adv.h
[[ -f "$SUB"/Configuration.h  || -f "$SUB"/Configuration_adv.h ]] || { echo "No configuration files found in $SUB" ; exit 1 ; }

# Get the location for exports and archives
if [[ -n $OUTBASE ]]; then
  ARCSUB="${OUTBASE/#\~/$HOME}/$CONFIG"
  mkdir -p "$ARCSUB"
else
  ARCSUB="$SUB"
fi

# Delete any config files from previous builds
rm -f Marlin/_Bootscreen.h Marlin/_Statusscreen.h

# Copy configurations into the Marlin folder
echo "Getting configuration files from $SUB"
cp "$BASE"/config/default/*.h Marlin/
cp "$SUB"/*.h Marlin/

rm -f Marlin/Config.h Marlin/Config-export.h

set -e

# Strip #error lines from Configuration.h using
awk 'NR < 20 || NR > 30 || !/#error/' Marlin/Configuration.h > Marlin/Configuration.h~
mv Marlin/Configuration.h~ Marlin/Configuration.h

# Hide several warnings when not exporting
[[ -z $EXPNUM ]] && CLEANER=1

# Suppress fatal warnings
if ((CLEANER)); then
  opt_add NO_CONTROLLER_CUSTOM_WIRING_WARNING
  opt_add NO_AUTO_ASSIGN_WARNING
  opt_add NO_CREALITY_DRIVER_WARNING
  opt_add DIAG_JUMPERS_REMOVED
  opt_add DIAG_PINS_REMOVED
  opt_add NO_MK3_FAN_PINS_WARNING
  opt_add NO_USER_FEEDBACK_WARNING
  opt_add NO_Z_SAFE_HOMING_WARNING
  opt_add NO_LCD_CONTRAST_WARNING
  opt_add NO_MICROPROBE_WARNING
  opt_add NO_CONFIGURATION_EMBEDDING_WARNING
  opt_add NO_HOMING_CURRENT_WARNING
fi

# Possible exported file names (in the build folder)
ENAME=("-name" "marlin_config.json" \
  "-o" "-name" "config.ini" \
  "-o" "-name" "schema.json" \
  "-o" "-name" "schema.yml")

# Possible built firmware names (in the build folder)
BNAME=("-type" "f" \
       "-name" 'firmware*.hex' \
  "-o" "-name" "firmware*.bin" \
  "-o" "-name" "project*.bin" \
  "-o" "-name" "Robin*.bin" \
  "-o" "-name" "main_*.bin")

mkdir -p "$BUILD"

# If EXPNUM is set then apply to the config before build
if [[ $EXPNUM ]]; then
  opt_set CONFIG_EXPORT $EXPNUM
  # Clean up old exports
  find "$BUILD" \( "${ENAME[@]}" \) -exec rm "{}" \;
fi

((ARCHIVE)) && find "$BUILD" \( "${BNAME[@]}" \) -exec rm "{}" \;

set +e

echo "Building example $CONFIG ..."
mftest -s -a -n1 ; ERR=$?

((ERR)) && echo "Failed" || echo "Success"

set -e

# Copy exports back to the configs
if [[ -n $EXPNUM ]]; then
  annc "Exporting $EXPNUM"
  [[ -f Marlin/Config-export.h ]] && { cp Marlin/Config-export.h "$ARCSUB"/Config.h ; }
  find "$BUILD" "${ENAME[@]}" -exec cp "{}" "$ARCSUB" \;
fi

# Copy potential firmware files into the config folder
# TODO: Consider firmware that needs an STM32F4_UPDATE folder.
#       Currently only BOARD_CREALITY_F401RE env:STM32F401RE_creality
if ((ARCHIVE)); then
  annc "Archiving"
  rm -f "$ARCSUB"/*.bin.tar.gz "$ARCSUB"/*.hex.tar.gz
  find "$BUILD" \( "${BNAME[@]}" \) -exec sh -c '
    ARCSUB="$1"
    CONFIG="$2"
    shift 2
    for FILE in "$@"; do
      cd "${FILE%/*}"
      BASE=${FILE##*/}
      SHRT=${BASE%.*}
      SHASUM=$(sha256sum "$BASE" | cut -d" " -f1)
      tar -czf "$ARCSUB/$SHRT.tar.gz" "$BASE"
      echo "$CONFIG\n$SHASUM" > "$ARCSUB/$BASE.sha256.txt"
      rm "$BASE"
      cd - >/dev/null
    done
  ' sh "$ARCSUB" "$CONFIG" {} +
fi

# Exit with error unless --nofail is set
[[ $ERR -gt 0 && -z $NOFAIL ]] && exit $ERR

# Reveal the configs after the build, if requested
((REVEAL)) && { annc "Revealing $ARCSUB" ; open "$ARCSUB" ; }

exit 0