set -eu
set -o pipefail
# set -x

export MASON_ROOT=${MASON_ROOT:-$(pwd)/mason_packages}
MASON_BUCKET=${MASON_BUCKET:-mason-binaries}
MASON_IGNORE_OSX_SDK=${MASON_IGNORE_OSX_SDK:-false}

MASON_UNAME=$(uname -s)
if [ "${MASON_UNAME}" = 'Darwin' ]; then
    MASON_PLATFORM=${MASON_PLATFORM:-osx}
    MASON_XCODE_ROOT=$("xcode-select" -p)
elif [ "${MASON_UNAME}" = 'Linux' ]; then
    MASON_PLATFORM=${MASON_PLATFORM:-linux}
fi

# In non-interactive environments like Travis CI, we use -s (--silent)
# because otherwise it will quickly fill up the log
case $- in
    *i*) MASON_CURL_ARGS=   ;; # interactive
    *)   MASON_CURL_ARGS=-s ;; # non-interative
esac

case ${MASON_UNAME} in
    'Darwin')    MASON_CONCURRENCY=$(sysctl -n hw.ncpu) ;;
    'Linux')        MASON_CONCURRENCY=$(grep -c ^processor /proc/cpuinfo) ;;
    *)              MASON_CONCURRENCY=1 ;;
esac

function mason_step    { >&2 printf "\033[1;36m%s\033[0m\n" "* $*"; }
function mason_substep { >&2 printf "\033[0;36m%s\033[0m\n" "* $*"; }
function mason_success { >&2 printf "\033[1;32m%s\033[0m\n" "* $*"; }
function mason_error   { >&2 printf "\033[1;31m%s\033[0m\n" "$*"; }


case ${MASON_ROOT} in
    *\ * ) mason_error "Directory '${MASON_ROOT} contains spaces."; exit ;;
esac

if [ "${MASON_PLATFORM}" = 'osx' ]; then
    export MASON_HOST_ARG="--host=x86_64-apple-darwin"
    export MASON_PLATFORM_VERSION=$(uname -m)

    if [[ ${MASON_IGNORE_OSX_SDK} == false ]]; then
        MASON_SDK_VERSION=$(xcrun --sdk macosx --show-sdk-version)
        if [[ ! ${MASON_SDK_VERSION} ]]; then
            mason_error "The command 'xcrun --sdk macosx --show-sdk-version' returned nothing. Is your xcode environment setup correctly?"
            exit 1
        fi
        MASON_SDK_ROOT=${MASON_XCODE_ROOT}/Platforms/MacOSX.platform/Developer
        # note: as of xcode >= 8.2 there is an unversioned "<Platform>.sdk" directory
        # such that for 10.12 the `MacOSX10.12.sdk` is a symlink to `MacOSX.sdk`
        # We use the unversioned directory here so that CFLAGS and CXXFLAGS are portable across
        # systems that might have a different SDK (e.g. xcode 8.3 vs 8.2)
        MASON_SDK_PATH="${MASON_SDK_ROOT}/SDKs/MacOSX.sdk"

        if [[ ${MASON_SYSTEM_PACKAGE:-} && ${MASON_SDK_VERSION%%.*} -ge 10 && ${MASON_SDK_VERSION##*.} -ge 11 ]]; then
            export MASON_DYNLIB_SUFFIX="tbd"
        else
            export MASON_DYNLIB_SUFFIX="dylib"
        fi

        MIN_SDK_VERSION_FLAG="-mmacosx-version-min=10.8"
        SYSROOT_FLAGS="-isysroot ${MASON_SDK_PATH} -arch x86_64 ${MIN_SDK_VERSION_FLAG}"
        export CFLAGS="${SYSROOT_FLAGS}"
        export CXXFLAGS="${CFLAGS} -fvisibility-inlines-hidden -stdlib=libc++ -std=c++11"
        # NOTE: OSX needs '-stdlib=libc++ -std=c++11' in both CXXFLAGS and LDFLAGS
        # to correctly target c++11 for build systems that don't know about it yet (like libgeos 3.4.2)
        # But because LDFLAGS is also for C libs we can only put these flags into LDFLAGS per package
        export LDFLAGS="-Wl,-search_paths_first ${SYSROOT_FLAGS}"
        export CXX="/usr/bin/clang++"
        export CC="/usr/bin/clang"
    fi

elif [ "${MASON_PLATFORM}" = 'ios' ]; then
    export MASON_HOST_ARG="--host=arm-apple-darwin"
    export MASON_PLATFORM_VERSION="8.0" # Deployment target version

    MASON_SDK_VERSION=$(xcrun --sdk iphoneos --show-sdk-version)
    if [[ ! ${MASON_SDK_VERSION} ]]; then
        mason_error "The command 'xcrun --sdk iphoneos --show-sdk-version' returned nothing. Is your xcode environment setup correctly?"
        exit 1
    fi
    MASON_SDK_ROOT=${MASON_XCODE_ROOT}/Platforms/iPhoneOS.platform/Developer
    MASON_SDK_PATH="${MASON_SDK_ROOT}/SDKs/iPhoneOS${MASON_SDK_VERSION}.sdk"

    MIN_SDK_VERSION_FLAG="-miphoneos-version-min=${MASON_PLATFORM_VERSION}"
    export MASON_IOS_CFLAGS="${MIN_SDK_VERSION_FLAG} -isysroot ${MASON_SDK_PATH}"
    if [[ ${MASON_SDK_VERSION%%.*} -ge 9 ]]; then
        export MASON_IOS_CFLAGS="${MASON_IOS_CFLAGS} -fembed-bitcode"
        export MASON_DYNLIB_SUFFIX="tbd"
    else
        export MASON_DYNLIB_SUFFIX="dylib"
    fi

    if [ "$(xcrun --sdk iphonesimulator --show-sdk-version)" != "${MASON_SDK_VERSION}" ]; then
        mason_error "iPhone Simulator SDK version doesn't match iPhone SDK version"
        exit 1
    fi

    MASON_SDK_ROOT=${MASON_XCODE_ROOT}/Platforms/iPhoneSimulator.platform/Developer
    MASON_SDK_PATH="${MASON_SDK_ROOT}/SDKs/iPhoneSimulator${MASON_SDK_VERSION}.sdk"
    export MASON_ISIM_CFLAGS="${MIN_SDK_VERSION_FLAG} -isysroot ${MASON_SDK_PATH}"

elif [ "${MASON_PLATFORM}" = 'linux' ]; then

    export MASON_DYNLIB_SUFFIX="so"

    # Assume current system is the target platform
    if [ ! ${MASON_PLATFORM_VERSION:-} ] ; then
        export MASON_PLATFORM_VERSION=$(uname -m)
    fi

    export CFLAGS="-fPIC"
    export LDFLAGS=""
    export CXXFLAGS="${CFLAGS} -std=c++11"

    if [ "$(uname -m)" != "${MASON_PLATFORM_VERSION}" ] ; then
        # Install the cross compiler
        MASON_XC_PACKAGE_NAME=gcc
        MASON_XC_PACKAGE_VERSION=${MASON_XC_GCC_VERSION:-5.3.0}-${MASON_PLATFORM_VERSION}
        MASON_XC_PACKAGE=${MASON_XC_PACKAGE_NAME}-${MASON_XC_PACKAGE_VERSION}
        MASON_XC_ROOT=$(MASON_PLATFORM= MASON_PLATFORM_VERSION= ${MASON_DIR}/mason prefix ${MASON_XC_PACKAGE_NAME} ${MASON_XC_PACKAGE_VERSION})
        if [[ ! ${MASON_XC_ROOT} =~ ".build" ]] && [ ! -d ${MASON_XC_ROOT} ] ; then
            MASON_PLATFORM= MASON_PLATFORM_VERSION= ${MASON_DIR}/mason install ${MASON_XC_PACKAGE_NAME} ${MASON_XC_PACKAGE_VERSION}
            MASON_XC_ROOT=$(MASON_PLATFORM= MASON_PLATFORM_VERSION= ${MASON_DIR}/mason prefix ${MASON_XC_PACKAGE_NAME} ${MASON_XC_PACKAGE_VERSION})
        fi

        # Load toolchain specific variables
        if [[ ! ${MASON_XC_ROOT} =~ ".build" ]] && [ -f ${MASON_XC_ROOT}/toolchain.sh ] ; then
            source "${MASON_XC_ROOT}/toolchain.sh"
        fi
    fi

elif [ "${MASON_PLATFORM}" = 'android' ]; then
    case "${MASON_PLATFORM_VERSION:-}" in
        arm-v5-14) export MASON_ANDROID_ABI=arm-v5 ;;
        arm-v7-14) export MASON_ANDROID_ABI=arm-v7 ;;
        arm-v8-21) export MASON_ANDROID_ABI=arm-v8 ;;
        x86-14) export MASON_ANDROID_ABI=x86 ;;
        x86-64-21) export MASON_ANDROID_ABI=x86-64 ;;
        mips-14) export MASON_ANDROID_ABI=mips ;;
        mips64-21) export MASON_ANDROID_ABI=mips64 ;;
        *) export MASON_ANDROID_ABI=${MASON_ANDROID_ABI:-arm-v7}
    esac

    CFLAGS="-g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security"
    LDFLAGS="-Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now"
    export CPPFLAGS="-D__ANDROID__"

    if [ ${MASON_ANDROID_ABI} = 'arm-v8' ]; then
        MASON_ANDROID_TOOLCHAIN="aarch64-linux-android"
        export MASON_HOST_ARG="--host=${MASON_ANDROID_TOOLCHAIN}"

        CFLAGS="-target aarch64-none-linux-android ${CFLAGS}"

        export JNIDIR="arm64-v8a"
        MASON_ANDROID_ARCH="arm64"
        MASON_ANDROID_PLATFORM="21"

    elif [ ${MASON_ANDROID_ABI} = 'arm-v7' ]; then
        MASON_ANDROID_TOOLCHAIN="arm-linux-androideabi"
        export MASON_HOST_ARG="--host=${MASON_ANDROID_TOOLCHAIN}"

        CFLAGS="-target armv7-none-linux-androideabi ${CFLAGS} -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -fno-integrated-as -mthumb"
        LDFLAGS="${LDFLAGS} -Wl,--fix-cortex-a8 -Wl,--exclude-libs,libunwind.a"

        export JNIDIR="armeabi-v7a"
        MASON_ANDROID_ARCH="arm"
        MASON_ANDROID_PLATFORM="14"

    elif [ ${MASON_ANDROID_ABI} = 'arm-v5' ]; then
        MASON_ANDROID_TOOLCHAIN="arm-linux-androideabi"
        export MASON_HOST_ARG="--host=${MASON_ANDROID_TOOLCHAIN}"

        CFLAGS="-target armv5te-none-linux-androideabi ${CFLAGS} -march=armv5te -mtune=xscale -msoft-float -fno-integrated-as -mthumb"
        LDFLAGS="${LDFLAGS} -Wl,--exclude-libs,libunwind.a"

        export JNIDIR="armeabi"
        MASON_ANDROID_ARCH="arm"
        MASON_ANDROID_PLATFORM="14"

    elif [ ${MASON_ANDROID_ABI} = 'x86' ]; then
        MASON_ANDROID_TOOLCHAIN="i686-linux-android"
        export MASON_HOST_ARG="--host=${MASON_ANDROID_TOOLCHAIN}"

        CFLAGS="-target i686-none-linux-android ${CFLAGS}"

        export JNIDIR="x86"
        MASON_ANDROID_ARCH="x86"
        MASON_ANDROID_PLATFORM="14"

    elif [ ${MASON_ANDROID_ABI} = 'x86-64' ]; then
        MASON_ANDROID_TOOLCHAIN="x86_64-linux-android"
        export MASON_HOST_ARG="--host=${MASON_ANDROID_TOOLCHAIN}"

        export JNIDIR="x86_64"
        CFLAGS="-target x86_64-none-linux-android ${CFLAGS}"

        MASON_ANDROID_ARCH="x86_64"
        MASON_ANDROID_PLATFORM="21"

    elif [ ${MASON_ANDROID_ABI} = 'mips' ]; then
        MASON_ANDROID_TOOLCHAIN="mipsel-linux-android"
        export MASON_HOST_ARG="--host=${MASON_ANDROID_TOOLCHAIN}"

        CFLAGS="-target mipsel-none-linux-android ${CFLAGS} -mips32"

        export JNIDIR="mips"
        MASON_ANDROID_ARCH="mips"
        MASON_ANDROID_PLATFORM="14"

    elif [ ${MASON_ANDROID_ABI} = 'mips-64' ]; then
        MASON_ANDROID_TOOLCHAIN="mips64el-linux-android"
        export MASON_HOST_ARG="--host=${MASON_ANDROID_TOOLCHAIN}"

        CFLAGS="-target mips64el-none-linux-android ${CFLAGS} -fintegrated-as"

        export JNIDIR="mips64"
        MASON_ANDROID_ARCH="mips64"
        MASON_ANDROID_PLATFORM="21"
    fi

    export MASON_DYNLIB_SUFFIX="so"
    export MASON_PLATFORM_VERSION="${MASON_ANDROID_ABI}-${MASON_ANDROID_PLATFORM}"
    MASON_API_LEVEL=${MASON_API_LEVEL:-android-$MASON_ANDROID_PLATFORM}

    # Installs the native SDK
    export MASON_NDK_PACKAGE_VERSION=${MASON_ANDROID_ARCH}-${MASON_ANDROID_PLATFORM}-r16b
    MASON_SDK_ROOT=$(MASON_PLATFORM= MASON_PLATFORM_VERSION= ${MASON_DIR}/mason prefix android-ndk ${MASON_NDK_PACKAGE_VERSION})
    if [ ! -d "${MASON_SDK_ROOT}" ] ; then
        MASON_PLATFORM= MASON_PLATFORM_VERSION= ${MASON_DIR}/mason install android-ndk ${MASON_NDK_PACKAGE_VERSION}
    fi
    MASON_SDK_PATH="${MASON_SDK_ROOT}/sysroot"
    export PATH=${MASON_SDK_ROOT}/bin:${PATH}

    export CFLAGS="--sysroot=${MASON_SDK_PATH} ${CFLAGS}"
    export CXXFLAGS="--sysroot=${MASON_SDK_PATH} ${CFLAGS}"
    export LDFLAGS="--sysroot=${MASON_SDK_PATH} ${LDFLAGS}"

    export CXX="${MASON_ANDROID_TOOLCHAIN}-clang++"
    export CC="${MASON_ANDROID_TOOLCHAIN}-clang"
    export LD="${MASON_ANDROID_TOOLCHAIN}-ld"
    export AR="${MASON_ANDROID_TOOLCHAIN}-ar"
    export RANLIB="${MASON_ANDROID_TOOLCHAIN}-ranlib"
    export STRIP="${MASON_ANDROID_TOOLCHAIN}-strip"
fi


# Variable defaults
MASON_HOST_ARG=${MASON_HOST_ARG:-}
MASON_PLATFORM_VERSION=${MASON_PLATFORM_VERSION:-0}
MASON_NAME=${MASON_NAME:-nopackage}
MASON_VERSION=${MASON_VERSION:-noversion}
MASON_HEADER_ONLY=${MASON_HEADER_ONLY:-false}
MASON_SLUG=${MASON_NAME}-${MASON_VERSION}
if [[ ${MASON_HEADER_ONLY} == true ]]; then
    MASON_PLATFORM_ID=headers
else
    MASON_PLATFORM_ID=${MASON_PLATFORM}-${MASON_PLATFORM_VERSION}
fi
MASON_PREFIX=${MASON_ROOT}/${MASON_PLATFORM_ID}/${MASON_NAME}/${MASON_VERSION}
MASON_BINARIES=${MASON_PLATFORM_ID}/${MASON_NAME}/${MASON_VERSION}.tar.gz
MASON_BINARIES_PATH=${MASON_ROOT}/.binaries/${MASON_BINARIES}
MASON_BINARIES_URL="https://${MASON_BUCKET}.s3.amazonaws.com/${MASON_BINARIES}"




function mason_check_existing {
    # skip installing if it already exists
    if [ "${MASON_HEADER_ONLY:-false}" = true ] ; then
        if [ -d "${MASON_PREFIX}" ] ; then
            mason_success "Already installed at ${MASON_PREFIX}"
            exit 0
        fi
    elif [ "${MASON_SYSTEM_PACKAGE:-false}" = true ]; then
        if [ -f "${MASON_PREFIX}/version" ] ; then
            local version # no assignment, local ignores exit status from $(...)
            version=$(set -eu; mason_system_version)
            mason_success "Using system-provided ${MASON_NAME} ${version}"
            exit 0
        fi
    else
        if [ -f "${MASON_PREFIX}/${MASON_LIB_FILE}" ] ; then
            mason_success "Already installed at ${MASON_PREFIX}"
            exit 0
        fi
    fi
}


function mason_check_installed {
    # skip installing if it already exists
    if [ "${MASON_HEADER_ONLY:-false}" = true ] ; then
        if [ -d "${MASON_PREFIX}" ] ; then
            return 0
        fi
    elif [ "${MASON_SYSTEM_PACKAGE:-false}" = true ]; then
        if [ -f "${MASON_PREFIX}/version" ] ; then
            return 0
        fi
    elif [ -f "${MASON_PREFIX}/${MASON_LIB_FILE}" ] ; then
        return 0
    fi
    mason_error "Package ${MASON_NAME} ${MASON_VERSION} isn't installed"
    return 1
}


function mason_clear_existing {
    if [ -e "${MASON_PREFIX}" ] || [ -h "${MASON_PREFIX}" ]; then
        mason_step "Removing existing package... ${MASON_PREFIX}"
        rm -rf "${MASON_PREFIX}"
    fi
}


function mason_curl {
    curl -f -L ${MASON_CURL_ARGS} "$@"
    #
    # -f, --fail
    #       (HTTP) Fail silently (no output at all) on server errors.
    #
    # -L, --location
    #       (HTTP) If the server reports that the requested page has
    #       moved to a different location, this option will make curl
    #       redo the request on the new place.
}


function mason_download {
    mkdir -p "${MASON_ROOT}/.cache"
    cd "${MASON_ROOT}/.cache"
    if [ ! -f "${MASON_SLUG}" ] ; then
        mason_step "Downloading $1..."
        local CURL_RESULT=0
        mason_curl -S --retry 3 "$1" -o "${MASON_SLUG}" || CURL_RESULT=$?
        if [[ ${CURL_RESULT} != 0 ]]; then
            mason_error "Failed to download ${1} (returncode: $CURL_RESULT)"
            exit $CURL_RESULT
        fi
    fi

    MASON_HASH=$(git hash-object "${MASON_SLUG}")
    if [ "$2" != "${MASON_HASH}" ] ; then
        mason_error "Hash ${MASON_HASH} of file ${MASON_ROOT}/.cache/${MASON_SLUG} doesn't match $2"
        exit 1
    fi
}

function mason_setup_build_dir {
    rm -rf "${MASON_ROOT}/.build/${MASON_SLUG}"
    mkdir -p "${MASON_ROOT}/.build/"
    cd "${MASON_ROOT}/.build/"
}

function mason_extract_tar_gz {
    mason_setup_build_dir
    tar xzf "../.cache/${MASON_SLUG}" $@
}

function mason_extract_tar_bz2 {
    mason_setup_build_dir
    tar xjf "../.cache/${MASON_SLUG}" $@
}

function mason_extract_tar_xz {
    mason_setup_build_dir
    tar xJf "../.cache/${MASON_SLUG}" $@
}

function mason_prepare_compile {
    :
}

function mason_compile {
    mason_error "COMPILE FUNCTION MISSING"
    exit 1
}

function mason_clean {
    :
}

function bash_lndir() {
    local src dst
    src=$(cd -- "$1" && pwd)
    dst=$(cd -- "$2" && pwd)

    find "$src" -mindepth 1 -type d -exec \
        /usr/bin/env src="$src" dst="$dst" bash -c \
        '
            mkdir -p -- "${@/#"$src"/$dst}"
            for src_dir
            do
                dst_dir="${src_dir/#"$src"/$dst}"
                export dst_dir

                # OSX ln does not support -t (--target-directory),
                # that is why -exec sh -c "ln -sf -- files... dir"
                # is used instead of -exec ln -sft dir files...

                find "$src_dir" -maxdepth 1 \
                    \( -type f -o -type l \) \
                    \! -name "*~" \
                    -exec /bin/sh -c \
                    "
                        ln -sf -- \"\$@\" \"\$dst_dir/\"

                    " sh_lnfiles "{""}" +
            done

        ' bash_lndir '{}' +
}


function run_lndir() {
    # TODO: cp is fast, but inconsistent across osx
    #/bin/cp -R -n ${MASON_PREFIX}/* ${TARGET_SUBDIR}
    mason_step "Linking ${MASON_PREFIX}"
    mason_step "Links will be inside ${TARGET_SUBDIR}"
    local cp_help=$(cp --help 2>/dev/null)
    if [[ $cp_help =~ [[:space:]]--symbolic-link[[:space:]] &&
          $cp_help =~ [[:space:]]--target-directory= ]]
    then
        mason_substep "Using 'cp' for symlinking"
        find "${MASON_PREFIX}" -mindepth 1 -type d -prune -exec \
            cp -RPfp --symbolic-link \
                --target-directory="${TARGET_SUBDIR}" \
                -- '{}' +
    else
        mason_substep "Using bash fallback for symlinking (GNU cp needed for faster symlinking)"
        bash_lndir "${MASON_PREFIX}/" "${TARGET_SUBDIR}"
    fi
    mason_step "Done linking ${MASON_PREFIX}"
}

function mason_link {
    if [ ! -d "${MASON_PREFIX}" ] ; then
        mason_error "${MASON_PREFIX} not found, please install first"
        exit 0
    fi
    TARGET_SUBDIR="${MASON_ROOT}/.link/"
    mkdir -p "${TARGET_SUBDIR}"
    run_lndir
}


function mason_build {
    mason_load_source

    mason_step "Building for Platform '${MASON_PLATFORM}/${MASON_PLATFORM_VERSION}'..."
    cd "${MASON_BUILD_PATH}"
    mason_prepare_compile

    if [ "${MASON_PLATFORM}" = 'ios' ]; then

        SIMULATOR_TARGETS="i386 x86_64"
        DEVICE_TARGETS="armv7 arm64"
        LIB_FOLDERS=

        for ARCH in ${SIMULATOR_TARGETS} ; do
            mason_substep "Building for iOS Simulator ${ARCH}..."
            export CFLAGS="${MASON_ISIM_CFLAGS} -arch ${ARCH}"
            export CXXFLAGS="${MASON_ISIM_CFLAGS} -arch ${ARCH}"
            cd "${MASON_BUILD_PATH}"
            mason_compile
            cd "${MASON_PREFIX}"
            mv lib "lib-isim-${ARCH}"
            for i in lib-isim-${ARCH}/*.a ; do lipo -info "$i" ; done
            LIB_FOLDERS="${LIB_FOLDERS} lib-isim-${ARCH}"
        done

        for ARCH in ${DEVICE_TARGETS} ; do
            mason_substep "Building for iOS ${ARCH}..."
            export CFLAGS="${MASON_IOS_CFLAGS} -arch ${ARCH}"
            export CXXFLAGS="${MASON_IOS_CFLAGS} -arch ${ARCH}"
            cd "${MASON_BUILD_PATH}"
            mason_compile
            cd "${MASON_PREFIX}"
            mv lib lib-ios-${ARCH}
            for i in lib-ios-${ARCH}/*.a ; do lipo -info $i ; done
            LIB_FOLDERS="${LIB_FOLDERS} lib-ios-${ARCH}"
        done

        # Create universal binary
        mason_substep "Creating Universal Binary..."
        cd "${MASON_PREFIX}"
        mkdir -p lib
        for LIB in $(find ${LIB_FOLDERS} -name "*.a" | xargs basename | sort | uniq) ; do
            lipo -create $(find ${LIB_FOLDERS} -name "${LIB}") -output lib/${LIB}
            lipo -info "lib/${LIB}"
        done

        cd "${MASON_PREFIX}"
        rm -rf "${LIB_FOLDERS}"
    elif [ ${MASON_PLATFORM} = 'android' ]; then
        cd "${MASON_BUILD_PATH}"
        mason_compile
    else
        cd "${MASON_BUILD_PATH}"
        mason_compile
    fi

    mason_success "Installed at ${MASON_PREFIX}"

    #rm -rf ${MASON_ROOT}/.build
}

function mason_config_custom {
    # Override this function in your script to add more configuration variables
    :
}

function mason_config {
    local MASON_CONFIG_CFLAGS MASON_CONFIG_LDFLAGS MASON_CONFIG_STATIC_LIBS MASON_CONFIG_PREFIX LN
    local MASON_CONFIG_INCLUDE_DIRS MASON_CONFIG_DEFINITIONS MASON_CONFIG_OPTIONS

    MASON_CONFIG_CFLAGS=$(set -e;mason_cflags)
    MASON_CONFIG_LDFLAGS=$(set -e;mason_ldflags)
    MASON_CONFIG_STATIC_LIBS=$(set -e;mason_static_libs)
    MASON_CONFIG_PREFIX="{prefix}"

    # Split up the cflags into include dirs, definitions and options.
    LN=$'\n'
    MASON_CONFIG_CFLAGS="${MASON_CONFIG_CFLAGS// -/${LN}-}"
    MASON_CONFIG_INCLUDE_DIRS=$(echo -n "${MASON_CONFIG_CFLAGS}" | sed -nE 's/^-(I|isystem) *([^ ]+)/\2/p' | uniq)
    MASON_CONFIG_DEFINITIONS=$(echo -n "${MASON_CONFIG_CFLAGS}" | sed -nE 's/^-(D) *([^ ]+)/\2/p')
    MASON_CONFIG_OPTIONS=$(echo -n "${MASON_CONFIG_CFLAGS}" | sed -nE '/^-(D|I|isystem) *([^ ]+)/!p')

    echo "name=${MASON_NAME}"
    echo "version=${MASON_VERSION}"
    if ${MASON_HEADER_ONLY}; then
        echo "header_only=${MASON_HEADER_ONLY}"
    else
        echo "platform=${MASON_PLATFORM}"
        echo "platform_version=${MASON_PLATFORM_VERSION}"
    fi
    echo "root=${MASON_ROOT}"
    mason_config_custom
    for name in include_dirs definitions options ldflags static_libs ; do
        eval value=\$MASON_CONFIG_$(echo ${name} | tr '[:lower:]' '[:upper:]')
        if [ ! -z "${value}" ]; then
            echo "${name}=${value//${MASON_PREFIX}/${MASON_CONFIG_PREFIX}}"
        fi
    done
}

function mason_write_config {
    local INI_FILE
    INI_FILE="${MASON_PREFIX}/mason.ini"
    MASON_INI_DATA=$(set -e;mason_config)
    echo "${MASON_INI_DATA}" > "${INI_FILE}"
    mason_substep "Wrote configuration file ${INI_FILE}:"
    cat "${INI_FILE}"
}

function mason_try_binary {
    MASON_BINARIES_DIR=$(dirname "${MASON_BINARIES}")
    mkdir -p "${MASON_ROOT}/.binaries/${MASON_BINARIES_DIR}"

    # try downloading from S3
    if [ ! -f "${MASON_BINARIES_PATH}" ] ; then
        mason_step "Downloading binary package ${MASON_BINARIES_URL}"
        local CURL_RESULT=0
        local HTTP_RETURN=0
        HTTP_RETURN=$(mason_curl -w "%{http_code}" --retry 3 "${MASON_BINARIES_URL}" -o "${MASON_BINARIES_PATH}.tmp") || CURL_RESULT=$?
        if [[ ${CURL_RESULT} != 0 ]]; then
            if [[ ${HTTP_RETURN} == "403" ]]; then
                mason_step "Binary not available for ${MASON_BINARIES_URL}"
            else
                mason_error "Failed to download ${MASON_BINARIES_URL} (returncode: ${CURL_RESULT})"
                exit $CURL_RESULT
            fi
        else
            mv "${MASON_BINARIES_PATH}.tmp" "${MASON_BINARIES_PATH}"
        fi
    else
        mason_step "Updating binary package ${MASON_BINARIES}..."
        local CURL_RESULT=0
        local HTTP_RETURN=0
        HTTP_RETURN=$(mason_curl -w "%{http_code}" --retry 3 -z "${MASON_BINARIES_PATH}" "${MASON_BINARIES_URL}" -o "${MASON_BINARIES_PATH}.tmp") || CURL_RESULT=$?
        if [[ ${CURL_RESULT} != 0 ]]; then
            if [ -f "${MASON_BINARIES_PATH}.tmp" ]; then
                mv "${MASON_BINARIES_PATH}.tmp" "${MASON_BINARIES_PATH}"
            else
                mason_step "Binary package is still up to date"
            fi
        else
            mason_step "Binary not available yet for ${MASON_BINARIES}"
        fi
    fi

    # unzip the file if it exists
    if [ -f "${MASON_BINARIES_PATH}" ] ; then
        mkdir -p "${MASON_PREFIX}"
        cd "${MASON_PREFIX}"

        # Try to force the ownership of the unpacked files
        # to the current user using fakeroot if available
        $(which fakeroot) tar xzf "${MASON_BINARIES_PATH}"

        local bdist_root= match replace

        if [ -f "${MASON_PREFIX}/mason.ini" ]; then
            bdist_root=$(sed -ne 's|^root=||p' "${MASON_PREFIX}/mason.ini")
        fi

        # fallback for packages without root=/path/to/mason_packages in mason.ini
        case ${#bdist_root},${MASON_PLATFORM} in
            0,ios| \
            0,osx) bdist_root="/Users/travis/build/mapbox/mason/mason_packages" ;;
            0,*  ) bdist_root="/home/travis/build/mapbox/mason/mason_packages" ;;
        esac

        match=$(sed 's:[][$*.^\\&]:\\&:g' <<< ${bdist_root})
        replace=$(sed 's:[\\&]:\\&:g' <<< ${MASON_ROOT})

        # fixup libtool .la and pkgconfig .pc files
        find "${MASON_PREFIX}" -name include -prune -o -type f \
            \( -name '*.la' -o -path '*/pkgconfig/*.pc' \) \
            -exec sed -i.bak "s&${match}&${replace}&g" '{}' +

        mason_success "Installed binary package at ${MASON_PREFIX}"
        exit 0
    fi
}


function mason_pkgconfig {
    MASON_PKGCONFIG_FILES=""
    for pkgconfig_file in ${MASON_PKGCONFIG_FILE:-}; do
        MASON_PKGCONFIG_FILES="${MASON_PKGCONFIG_FILES} ${MASON_PREFIX}/${pkgconfig_file}"
    done
    echo pkg-config "${MASON_PKGCONFIG_FILES}"
}

function mason_cflags {
    if [[ ! ${MASON_PKGCONFIG_FILE:-} ]]; then
        mason_error " The MASON_PKGCONFIG_FILE variable not found in script.sh. Please either provide this variable or override the mason_cflags function hook"
        exit 1
    fi
    local FLAGS
    FLAGS=$(set -e;$(mason_pkgconfig) --static --cflags)
    # Replace double-prefix in case we use a sysroot.
    echo "${FLAGS//${MASON_SYSROOT:-}${MASON_PREFIX}/${MASON_PREFIX}}"
}

function mason_ldflags {
    if [[ ! ${MASON_PKGCONFIG_FILE:-} ]]; then
        mason_error " The MASON_PKGCONFIG_FILE variable not found in script.sh. Please either provide this variable or override the mason_ldflags function hook"
        exit 1
    fi
    local FLAGS
    FLAGS=$(set -e;$(mason_pkgconfig) --static --libs)
    # Replace double-prefix in case we use a sysroot.
    echo "${FLAGS//${MASON_SYSROOT:-}${MASON_PREFIX}/${MASON_PREFIX}}"
}

function mason_static_libs {
    if [ -z "${MASON_LIB_FILE:-}" ]; then
        mason_substep "Linking ${MASON_NAME} ${MASON_VERSION} dynamically"
    elif [ -f "${MASON_PREFIX}/${MASON_LIB_FILE}" ]; then
        echo "${MASON_PREFIX}/${MASON_LIB_FILE}"
    else
        mason_error "No static library file '${MASON_PREFIX}/${MASON_LIB_FILE}'"
        exit 1
    fi
}

function mason_prefix {
    echo "${MASON_PREFIX}"
}

function mason_version {
    if [ "${MASON_SYSTEM_PACKAGE:-false}" = true ]; then
        mason_system_version
    else
        echo "${MASON_VERSION}"
    fi
}

function mason_list_existing_package {
    local PREFIX RESULT
    PREFIX=$1
    RESULT=$(aws s3api head-object --bucket mason-binaries --key "$PREFIX/$MASON_NAME/$MASON_VERSION.tar.gz" 2>/dev/null)
    if [ ! -z "${RESULT}" ]; then
        printf "%-30s %6.1fM    %s\n" \
            "${PREFIX}" \
            "$(bc -l <<< "$(echo "${RESULT}" | jq -r .ContentLength) / 1000000")" \
            "$(echo "${RESULT}" | jq -r .LastModified)"
    else
        printf "%-30s %s\n" "${PREFIX}" "<missing>"
    fi
}

function mason_list_existing {
    if [ "${MASON_SYSTEM_PACKAGE:-false}" = true ]; then
        mason_error "System packages don't have published packages."
        exit 1
    elif [ "${MASON_HEADER_ONLY:-false}" = true ]; then
        mason_list_existing_package headers
    else
        for PREFIX in $(jq -r .CommonPrefixes[].Prefix[0:-1] <<< "$(aws s3api list-objects --bucket=mason-binaries --delimiter=/)") ; do
            if [ "${PREFIX}" != "headers" ] && [ "${PREFIX}" != "prebuilt" ] ; then
                mason_list_existing_package "${PREFIX}"
            fi
        done
    fi
}

function mason_publish {
    local CONTENT_TYPE DATE MD5 SIGNATURE
    if [ ! "${MASON_HEADER_ONLY:-false}" = true ] && [ ! -z "${MASON_LIB_FILE:-}" ] && [ ! -f "${MASON_PREFIX}/${MASON_LIB_FILE}" ]; then
        mason_error "Required library file ${MASON_PREFIX}/${MASON_LIB_FILE} doesn't exist."
        exit 1
    fi

    if [ -z "${AWS_ACCESS_KEY_ID}" ]; then
        mason_error "AWS_ACCESS_KEY_ID is not set."
        exit 1
    fi

    if [ -z "${AWS_SECRET_ACCESS_KEY}" ]; then
        mason_error "AWS_SECRET_ACCESS_KEY is not set."
        exit 1
    fi

    mkdir -p "$(dirname ${MASON_BINARIES_PATH})"
    cd "${MASON_PREFIX}"
    rm -rf "${MASON_BINARIES_PATH}"
    tar czf "${MASON_BINARIES_PATH}" .
    (cd "${MASON_ROOT}/.binaries" && ls -lh "${MASON_BINARIES}")
    mason_step "Uploading binary package..."

    CONTENT_TYPE="application/octet-stream"
    DATE="$(LC_ALL=C date -u +"%a, %d %b %Y %X %z")"
    MD5="$(openssl md5 -binary < "${MASON_BINARIES_PATH}" | base64)"
    SIGNATURE="$(printf "PUT\n$MD5\n$CONTENT_TYPE\n$DATE\nx-amz-acl:public-read\n/${MASON_BUCKET}/${MASON_BINARIES}" | openssl sha1 -binary -hmac "$AWS_SECRET_ACCESS_KEY" | base64)"

    curl -S -T "${MASON_BINARIES_PATH}" "${MASON_BINARIES_URL}" \
        -H "Date: $DATE" \
        -H "Authorization: AWS $AWS_ACCESS_KEY_ID:$SIGNATURE" \
        -H "Content-Type: $CONTENT_TYPE" \
        -H "Content-MD5: $MD5" \
        -H "x-amz-acl: public-read"

    echo "${MASON_BINARIES_URL}"
    curl -f -I "${MASON_BINARIES_URL}"
}

function mason_run {
    if [ "$1" == "install" ]; then
        if [ "${MASON_SYSTEM_PACKAGE:-false}" = true ]; then
            mason_check_existing
            mason_clear_existing
            mason_build
            mason_write_config
            local version # no assignment, local ignores exit status from $(...)
            version=$(set -eu; mason_system_version)
            mason_success "Installed system-provided ${MASON_NAME} ${version}"
        else
            mason_check_existing
            mason_clear_existing
            mason_try_binary
            mason_build
            mason_write_config
        fi
    elif [ "$1" == "link" ]; then
        mason_link
    elif [ "$1" == "remove" ]; then
        mason_clear_existing
    elif [ "$1" == "publish" ]; then
        mason_publish
    elif [ "$1" == "build" ]; then
        mason_clear_existing
        mason_build
        mason_write_config
    elif [ "$1" == "cflags" ]; then
        mason_check_installed
        mason_cflags
    elif [ "$1" == "ldflags" ]; then
        mason_check_installed
        mason_ldflags
    elif [ "$1" == "config" ]; then
        mason_check_installed
        mason_config
    elif [ "$1" == "static_libs" ]; then
        mason_check_installed
        mason_static_libs
    elif [ "$1" == "version" ]; then
        mason_check_installed
        mason_version
    elif [ "$1" == "prefix" ]; then
        mason_prefix
    elif [ "$1" == "existing" ]; then
        mason_list_existing
    elif [ $1 ]; then
        mason_error "Unknown command '$1'"
        exit 1
    else
        mason_error "Usage: $0 <command> <lib> <version>"
        exit 1
    fi
}
