#!/usr/bin/env bash
################################################################################
# DO NOT ALTER THIS LINE
VERSION=62
################################################################################

SERVER="https://realearth.ssec.wisc.edu"
KEY=
URI=

IS_HELP=0
if [ -n "$1" -a "$1" = "-h" ]; then
        IS_HELP=1
fi
CHECK_SH=`basename ${SHELL}`
if [ ${IS_HELP} -eq 0 -a \
     "${CHECK_SH}" != "sh" -a \
     "${CHECK_SH}" != "ash" -a \
     "${CHECK_SH}" != "bash" ]; then
	echo "Error: Bad interpreter: \"${CHECK_SH}\""
	echo "Please modify the first line of this script to use sh, ash, or bash"
	echo "Or call explicity with:"
	echo "	/bin/sh $0 $@"
	exit 6
fi

CURL=`which curl 2>/dev/null`
if [ -z "${CURL}" ]; then
	echo "Error: Cannot find \"curl\""
	exit 5
fi
CHECK_CURL=`${CURL} --version |head -1 |awk '{print $2}' |awk -F. '{print $1}'`
if [ -z "${CHECK_CURL}" -o ${CHECK_CURL} -lt 7 ]; then
	echo "Error: \"curl\" version must be 7+"
	exit 5
fi

BASE64=`which base64 2>/dev/null`
TIMEOUT_BIN=`which timeout 2>/dev/null`
TIMEOUT=
if [ -n "${TIMEOUT_BIN}" ]; then
	TIMEOUT="${TIMEOUT_BIN} -s 9 600"
fi
TMPDIR=/tmp/re_upload.$$

showHelp() {
	SELF=`basename $0`
	echo ""
	echo "$0 [-huojtcg1dxv] [-f [hours]] [-p [part]] [-k key|file] [-l \"URI\"] [-s server:port] file [name] [date] [time]"
	echo ""
	echo "   -h: Show help"
	echo "   -u: Check for update"
	echo "       Version: ${VERSION}"
	echo ""
	echo "   -p: Designate file as part of a larger product (part # optional)"
	echo "   -f: Force overwrite if there is a conflict (hour range optional)"
	echo "   -o: Convert to COG (requires GDAL tools)"
	echo "   -j: Use JPEG compression (requires GDAL tools)"
	echo "   -t: Do not timeout"
	echo ""
	echo "   -k: Specify the upload key or file"
	echo "   -l: Specify a URI for download of the original data"
	echo ""
	echo "   -c: Add random sleep to mitigate concurrent uploads (eg. cron jobs)"
	echo "   -g: Send through public gateway"
	echo "   -s: Specify the server and port"
	echo "       Default: ${SERVER}"
	echo ""
	echo "   -1: Do not retry on failure"
	echo "   -d: Delete file on successful upload"
	echo "   -x: Print target server and port (do not upload)"
	echo "   -v: Be verbose"
	echo ""
	echo " file: Path to file"
	echo "       Format: /path/to/[name]_[YYYYMMDD]_[HHMMSS].???"
	echo ""
	echo " name: Specify the product name"
	echo "       Required when the file name does not contain [name]"
	echo "       Format: Cannot contain '_'"
	echo " date: Specify the date"
	echo "       Required when the file name does not contain [date]"
	echo "       Format: YYYYMMDD"
	echo " time: Specify the time"
	echo "       Required when the file name does not contain [time]"
	echo "       Format: HHMMSS"
	echo ""
}

checkUpdate() {
	DL_URL="${SERVER}/upload/re_upload"
	URL="$DL_URL?version=${VERSION}"
	VERSION_CHECK=`${CURL} -L --insecure -s ${URL}`
	if [ -n "${VERSION_CHECK}" ]; then
		echo "A new version is available at:"
		echo "    ${DL_URL}"
		echo "Download with:"
		echo "    ${CURL} -L ${DL_URL} -o $0"
		if [ -n "${KEY}" ]; then
			echo "WARNING: Custom upload key must be set manually:"
			echo "    KEY=${KEY}"
		fi
		if [ -n "${URI}" ]; then
			echo "WARNING: Custom upload URI must be set manually:"
			echo "    URI=${URI}"
		fi
	else
		echo "This version is up to date"
	fi
}

# Cleanup
cleanup() {
	if [ ${RE_VERBOSE} -ne 0 ]; then
		echo "Removing ${TMPDIR}"
	fi
	rm -Rf "${TMPDIR}"
	if [ ${RE_DELETE} -ne 0 ]; then
		if [ ${RE_VERBOSE} -ne 0 ]; then
			echo "Deleting ${RE_FILE_NAME}"
		fi
		rm -f ${RE_FILE}
		if [ -f ${RE_FILE_PATH} ]; then
			rm -f ${RE_FILE_PATH}
		fi
	fi
}
trap cleanup SIGHUP SIGINT SIGTERM

# Get the options from the command line
RE_ONCE=0
RE_FORCE=0
RE_PART=0
RE_SLEEP=0
RE_PUBLIC=0
RE_VERBOSE=0
RE_PRINT=0
RE_COG=0
RE_JPEG=0
RE_DELETE=0
if [ -z "$1" ]; then
	showHelp
	exit 1
fi
while getopts 1hufpojtcrgdxvk:l:s: o; do
	case "$o" in
	1)	RE_ONCE=1
		;;
	h)	showHelp
		exit 1
		;;
	u)	checkUpdate
		exit 1
		;;
        f)      eval NEXTIND=\${$OPTIND}
                RE_GREP=$(echo "${NEXTIND}" |grep -Ec ^[0-9]+$)
                if [ -n "${NEXTIND}" -a ${RE_GREP} -ne 0 -a ! -f "${NEXTIND}" ]; then
                        OPTIND=$((OPTIND + 1))
                        RE_FORCE=${NEXTIND}
                else
                        RE_FORCE=-1
                fi
                ;;
	p)	eval NEXTIND=\${$OPTIND}
                RE_GREP=$(echo "${NEXTIND}" |grep -Ec ^[0-9]+$)
                if [ -n "${NEXTIND}" -a ${RE_GREP} -ne 0 -a ! -f "${NEXTIND}" ]; then
			OPTIND=$((OPTIND + 1))
			RE_PART=${NEXTIND}
		else
			RE_PART=-1
		fi
		;;
	c)	RE_SLEEP=1
		;;
	r)	RE_PUBLIC=1
		;;
	g)	RE_PUBLIC=1
		;;
	v)	RE_VERBOSE=1
		;;
	x)	RE_PRINT=1
		;;
	o)	RE_COG=1
		;;
	j)	RE_JPEG=1
		;;
	d)	RE_DELETE=1
		;;
	t)	TIMEOUT=
		;;
	k)	KEY=${OPTARG}
		;;
	l)	URI=${OPTARG}
		if [ -z "${BASE64}" ]; then
			echo "Error: Cannot find \"base64\""
			exit 5
		fi
		;;
	s)	SERVER=${OPTARG}
		;;
	*)	showHelp
		exit 1
		;;
	esac
done
shift $((${OPTIND} -1))

# Insert http:// if not part of SERVER
RE_GREP=$(echo "${SERVER}" |grep -Ec ^http)
if [ ${RE_GREP} -eq 0 ]; then
	SERVER="http://${SERVER}"
fi
SERVER_GW="${SERVER}"

# Set our variables
RE_FILE=$1
RE_NAME=$2
RE_DATE=$3
RE_TIME=$4

# Does the file exist?
if [ ! -f "${RE_FILE}" -a ${RE_PRINT} -eq 0 ]; then
	echo "ERROR: Could not find file: ${RE_FILE}"
	exit 4
fi

# Is the key a file?
if [ -n "${KEY}" -a -r "${KEY}" ]; then
	KEY=`cat "${KEY}"`
elif [ -n "${KEY}" -a $(echo "${KEY}" |grep -c "/") -ne 0 ]; then
	echo "ERROR: Key file ${KEY} is not readable"
	exit 4
fi

# Set the defaults for sending
RE_FILE_PATH=`realpath ${RE_FILE}`
RE_FILE_DIR=`dirname "${RE_FILE}"`
RE_FILE_NAME=`basename "${RE_FILE}"`
RE_FILE_PARTS=`echo "${RE_FILE_NAME}" |awk -F. '{print $1}'`

# Verify the product name
CHECK_NAME=${RE_NAME}
if [ -z "${CHECK_NAME}" ]; then
	CHECK_NAME=`echo ${RE_FILE_PARTS} |awk -F_ '{print $1}'`
fi
if [ -n "${CHECK_NAME}" ]; then
	match=`expr "${CHECK_NAME}" : '\([a-zA-Z0-9\-]\{1,\}\)'`
	if [ "$match" != "${CHECK_NAME}" ]; then
		echo ""
		echo "ERROR: Invalid product name"
		showHelp
		exit 4
	fi
fi

# Verify the product date
CHECK_DATE=${RE_DATE}
if [ -z "${CHECK_DATE}" ]; then
	CHECK_DATE=`echo ${RE_FILE_PARTS} |awk -F_ '{print $2}'`
fi
if [ -n "${CHECK_DATE}" ]; then
	match=`expr "${CHECK_DATE}" : '\([0-9]\{7,8\}\)'`
	if [ "$match" != "${CHECK_DATE}" ]; then
		echo ""
		echo "ERROR: Invalid product date"
		showHelp
		exit 4
	fi
fi

# Verify the product time
CHECK_TIME=${RE_TIME}
if [ -z "${CHECK_TIME}" ]; then
	CHECK_TIME=`echo ${RE_FILE_PARTS} |awk -F_ '{print $3}'`
fi
if [ -n "${CHECK_TIME}" ]; then
	match=`expr "${CHECK_TIME}" : '\([0-9]\{6\}\)'`
	if [ "$match" != "${CHECK_TIME}" ]; then
		echo ""
		echo "ERROR: Invalid product time"
		showHelp
		exit 4
	fi
fi

# Get the direct upload name (unless -g was specified)
if [ ${RE_PUBLIC} -eq 0 ]; then
	SERVER_DIRECT=
	if [ -n "${RE_NAME}" ]; then
		SERVER_DIRECT=`${CURL} -L --insecure -s ${SERVER}/upload/re_upload?name=${RE_NAME}`
	else
		SERVER_DIRECT=`${CURL} -L --insecure -s ${SERVER}/upload/re_upload?file=${RE_FILE_NAME}`
	fi
	if [ -n "${SERVER_DIRECT}" ]; then
		SERVER=${SERVER_DIRECT}
		RE_GREP=$(echo "${SERVER}" |grep -Ec ^http)
		if [ ${RE_GREP} -eq 0 ]; then
			SERVER="http://${SERVER}"
		fi
	else
		if [ ${RE_VERBOSE} -ne 0 ]; then
			echo "WARNING: Could not determine the direct URL for proxy upload"
		fi
	fi

	# Test the direct upload
	if [ ${RE_VERBOSE} -ne 0 ]; then
		echo "Testing direct connection to ${SERVER}..."
	fi
	SERVER_TEST=`${CURL} -L --max-time 5 --insecure -s ${SERVER}/api/version`
	RE_GREP=$(echo "${SERVER_TEST}" |grep -Ec ^[\.0-9]+$)
	if [ -z "${SERVER_TEST}" -o ${RE_GREP} -eq 0 ]; then
		if [ ${RE_VERBOSE} -ne 0 ]; then
			echo "WARNING: Could not connect directly, using gateway"
		fi
		SERVER="${SERVER_GW}"
	fi
fi

# Print
if [ ${RE_PRINT} -ne 0 ]; then
	echo ""
	echo "   File: ${RE_FILE}"
	echo ""
	echo "Product: ${CHECK_NAME}"
	echo "   Date: ${CHECK_DATE}"
	echo "   Time: ${CHECK_TIME}"
	echo ""
	echo " Target: ${SERVER}"
	echo ""
	exit 0
fi

# Sleep up to 15 seconds if asked to
if [ ${RE_SLEEP} -ne 0 ]; then
	SLEEP=$((${RANDOM} * 15 / 32767))
	echo "Sleeping for ${SLEEP} seconds..."
	sleep ${SLEEP}
fi

# See if we can use translate
if [ ${RE_COG} -ne 0 -o ${RE_JPEG} -ne 0 ]; then
	GDAL_TRANSLATE=`which gdal_translate 2>/dev/null`
	if [ -z "${GDAL_TRANSLATE}" ]; then
		echo "Warning: Cannot find \"gdal_translate\", COG and JPEG compression disabled"
		RE_COG=0
		RE_JPEG=0
	fi
	RE_GREP=$(echo "${RE_FILE_NAME}" |grep -Ec \.tif$)
	if [ ${RE_GREP} -eq 0 ]; then
		echo "Warning: COG and JPEG compression only applies to GeoTIFFs"
		RE_COG=0
		RE_JPEG=0
	fi
fi

# Did we ask for COG?
if [ ${RE_COG} -ne 0 ]; then
        if [ ${RE_VERBOSE} -ne 0 ]; then
                echo "Converting to COG..."
        fi
        mkdir -p ${TMPDIR}
        if [ ${RE_VERBOSE} -ne 0 ]; then
		echo "Using ${TMPDIR}"
        	echo "gdal_translate \"${RE_FILE}\" \"${TMPDIR}/${RE_FILE_NAME}\" -of COG -co COMPRESS=DEFLATE -co NUM_THREADS=4"
        	gdal_translate "${RE_FILE}" "${TMPDIR}/${RE_FILE_NAME}" -of COG -co COMPRESS=DEFLATE -co NUM_THREADS=4
		echo "Output:"
		ls -l ${TMPDIR}
	else
        	gdal_translate "${RE_FILE}" "${TMPDIR}/${RE_FILE_NAME}" -of COG -co COMPRESS=DEFLATE -co NUM_THREADS=4 >/dev/null 2>&1
	fi
        if [ -f "${TMPDIR}/${RE_FILE_NAME}" ]; then
                RE_FILE_DIR=${TMPDIR}
        else
                echo "Warning: Failed to convert GeoTIFF to COG"
        fi
fi

# Did we ask for compression?
if [ ${RE_JPEG} -ne 0 ]; then
	if [ ${RE_VERBOSE} -ne 0 ]; then
		echo "Compressing w/JPEG..."
	fi
	mkdir -p ${TMPDIR}
        if [ ${RE_VERBOSE} -ne 0 ]; then
		echo "Using ${TMPDIR}"
		echo "gdal_translate \"${RE_FILE}\" \"${TMPDIR}/${RE_FILE_NAME}\" -co \"COMPRESS=JPEG\" -co \"JPEG_QUALITY=90\" -co \"TILED=YES\""
		gdal_translate "${RE_FILE}" "${TMPDIR}/${RE_FILE_NAME}" -co "COMPRESS=JPEG" -co "JPEG_QUALITY=90" -co "TILED=YES"
		echo "Output:"
		ls -l ${TMPDIR}
	else
		gdal_translate "${RE_FILE}" "${TMPDIR}/${RE_FILE_NAME}" -co "COMPRESS=JPEG" -co "JPEG_QUALITY=90" -co "TILED=YES" >/dev/null 2>&1
	fi
	if [ -f "${TMPDIR}/${RE_NEW_NAME}" ]; then
		RE_FILE_DIR=${TMPDIR}
	else
		echo "Warning: Failed to compress GeoTIFF"
	fi
fi

# Change to the dir with the file
cd "${RE_FILE_DIR}"
echo "Connecting to ${SERVER}..."

# Check if the server is ready to receive the file
if [ ${RE_VERBOSE} -ne 0 ]; then
	echo "Checking upload availability"
fi
BYTES=`/bin/ls -Lln "${RE_FILE_NAME}" |awk '{print $5}'`
COMMAND="${CURL} --connect-timeout 15 -L --insecure -s ${SERVER}/upload/re_upload?bytes=${BYTES}"

if [ ${RE_VERBOSE} -ne 0 ]; then
	echo "Running: ${COMMAND}"
fi
SUCCESS=`${COMMAND} -o - 2>/dev/null |head -1`
if [ -z "${SUCCESS}" ]; then
        echo "  Server cannot be reached at this time, try again later"
        exit 3
fi
if [ "${SUCCESS}" -eq "${SUCCESS}" ] 2>/dev/null; then
	if [ "${SUCCESS}" = "-1" ]; then
		echo "  Server cannot accept the file, it is too large!"
		cleanup
		exit 3
	fi
	if [ "${SUCCESS}" = "2" ]; then
		echo "  Server has already received a file with this signature, use -f to force upload"
		cleanup
		exit 2
	fi
	if [ "${SUCCESS}" = "3" ]; then
		echo "  Server is currently ingesting a file with this name, use -f to force upload"
		cleanup
		exit 3
	fi
	while [ "${SUCCESS}" != "1" ]; do
		if [ ${RE_ONCE} -ne 0 ]; then
			echo "  Server cannot accept the file at this time, try again later"
			exit 3
		fi
		SLEEP=$((${RANDOM} * 5 / 32767 + 10));
		echo "  Server cannot accept the file at this time, trying again in ${SLEEP} seconds..."
		sleep ${SLEEP}
		SUCCESS=`${COMMAND} -o - |head -1`
	done
else
	if [ ${RE_VERBOSE} -ne 0 ]; then
		echo "  Server does not understand file size check, continuing..."
	fi
fi

# Send the file
echo "Sending ${RE_FILE_NAME} (${BYTES} bytes)"
COMMAND="${TIMEOUT} ${CURL} -L --max-time 600 --post301 --write-out %{http_code} --silent --fail --insecure -o /dev/null ${SERVER}/upload/ -F file=@${RE_FILE_NAME}"
if [ -n "${RE_NAME}" ]; then
	COMMAND="${COMMAND} -F name=${RE_NAME}"
	echo "  Name: ${RE_NAME}"
fi
if [ -n "${RE_DATE}" ]; then
	COMMAND="${COMMAND} -F date=${RE_DATE}"
	echo "  Date: ${RE_DATE}"
fi
if [ -n "${RE_TIME}" ]; then
	COMMAND="${COMMAND} -F time=${RE_TIME}"
	echo "  Time: ${RE_TIME}"
fi
if [ ${RE_PART} -ne 0 ]; then
	COMMAND="${COMMAND} -F part=${RE_PART}"
	if [ ${RE_PART} -gt 0 ]; then
		echo "  Part: ${RE_PART}"
	else
		echo "  Part"
	fi
fi
if [ ${RE_FORCE} -ne 0 ]; then
        COMMAND="${COMMAND} -F force=1"
        if [ ${RE_FORCE} -gt 0 ]; then
        	COMMAND="${COMMAND} -F cast=${RE_FORCE}"
                echo "  Force: ${RE_FORCE}h"
        else
                echo "  Force"
        fi
fi
if [ ${RE_COG} -ne 0 ]; then
	echo "  COG format"
fi
if [ ${RE_JPEG} -ne 0 ]; then
	echo "  JPEG compressed"
fi
if [ -n "${KEY}" ]; then
	COMMAND="${COMMAND} -F key=${KEY}"
fi
if [ -n "${URI}" ]; then
	B64URI=`echo "${URI}" |${BASE64} |tr -d '\n'`
	COMMAND="${COMMAND} -F uri=\"${B64URI}\" -F uri64=true"
fi

# Retry a few times...
RETRIES=3
if [ ${RE_ONCE} -ne 0 ]; then
	RETRIES=0
fi
if [ ${RE_VERBOSE} -ne 0 ]; then
	echo "Running: ${COMMAND}"
fi
CODE=$(${COMMAND} |head -n 1 |sed -e 's/.*\s//')
LASTEXIT=$?
if [ $((${CODE}+0)) -ge 400 ]; then
	LASTEXIT=${CODE}
fi
while [ ${LASTEXIT} -ne 0 -a ${RETRIES} -gt 0 ]; do
	echo "Curl command failed: ${LASTEXIT}, HTTP code: ${CODE}"
	if [ ${CODE} -ge 400 -a ${CODE} -lt 500 ]; then
		if [ ${CODE} -eq 400 ]; then
			echo "Invalid filename"
			break;
		elif [ ${CODE} -eq 401 ]; then
			echo "Authorization failed"
			break;
		elif [ ${CODE} -eq 409 ]; then
			echo "Conflict"
			break;
		fi
		echo "Client error"
		break;
	fi
	SLEEP=$((${RANDOM} * 30 / 32767))
	echo "Sleeping for ${SLEEP} seconds..."
	sleep ${SLEEP}
	echo "Trying again..."
	CODE=$(${COMMAND} |head -n 1 |sed -e 's/.*\s//')
	LASTEXIT=$?
	if [ $((${CODE}+0)) -ge 400 ]; then
		LASTEXIT=${CODE}
	fi
	RETRIES=$((${RETRIES} - 1))
done
if [ ${RE_VERBOSE} -ne 0 ]; then
	echo "HTTP code: ${CODE}"
	echo "CURL exit: ${LASTEXIT}"
fi
if [ ${LASTEXIT} -eq 0 ]; then
	echo "Done"
else
	echo "Giving up"
fi

cleanup

exit ${LASTEXIT}