#!/usr/bin/env bash
#
# @license Apache-2.0
#
# Copyright (c) 2017 The Stdlib Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Build script to run continuous integration on [Travis CI][1].
#
# [1]: travis-ci.org

# shellcheck disable=SC2181


# VARIABLES #

# Get the name of the build task as the first argument to the build script:
task="$1"

# Define an output file to store log output:
log_file='/var/log/travis-ci.log'

# Define a heartbeat interval to periodically print messages in order to prevent Travis CI from prematurely ending a build due to long running commands:
heartbeat_interval='30s'

# Declare a variable for storing the heartbeat process id:
heartbeat_pid=""


# FUNCTIONS #

# Defines an error handler.
#
# $1 - error status
on_error() {
	echo 'ERROR: An error was encountered during execution.' >&2
	cleanup
	exit "$1"
}

# Runs clean-up tasks.
cleanup() {
	stop_heartbeat
}

# Starts a heartbeat.
#
# $1 - heartbeat interval
start_heartbeat() {
	echo 'Starting heartbeat...' >&2

	# Create a heartbeat and send to background:
	heartbeat "$1" &

	# Capture the heartbeat pid:
	heartbeat_pid=$!
	echo "Heartbeat pid: ${heartbeat_pid}" >&2
}

# Runs an infinite print loop.
#
# $1 - heartbeat interval
heartbeat() {
	while true; do
		echo "$(date) - heartbeat..." >&2;
		sleep "$1";
	done
}

# Stops the heartbeat print loop.
stop_heartbeat() {
	echo 'Stopping heartbeat...' >&2
	kill "${heartbeat_pid}"
}

# Creates an output log file.
#
# $1 - log file path
create_log_file() {
	echo "Creating an output log file: $1." >&2
	sudo touch "$1"
	sudo chown travis "$1"
}

# Prints a success message.
print_success() {
	echo 'Success!' >&2
}

# Runs unit tests.
#
# $1 - log file
run_tests() {
	echo 'Running tests...' >&2
	make test >> "$1" 2>&1
	if [[ "$?" -ne 0 ]]; then
		echo 'Tests failed.' >&2
		return 1
	fi
	echo 'Tests passed.' >&2
	return 0
}

# Runs test coverage.
#
# $1 - log file
run_test_coverage() {
	echo 'Running test coverage...' >&2
	make test-cov >> "$1" 2>&1
	if [[ "$?" -ne 0 ]]; then
		echo 'Tests failed.' >&2
		return 1
	fi
	echo 'Tests passed.' >&2
	return 0
}

# Sends test coverage to coverage service.
#
# $1 - report title
# $2 - log file
send_coverage() {
	echo 'Sending coverage report to coverage service...' >&2
	make COVERAGE_NAME="$1" coverage >> "$2" 2>&1
	if [[ "$?" -ne 0 ]]; then
		echo 'Sending coverage report to coverage service failed.' >&2
		return 1
	fi
	echo 'Coverage report sent to coverage service.' >&2
	return 0
}

# Runs benchmarks.
#
# $1 - log file
run_benchmarks() {
	echo 'Running benchmarks...' >&2
	make benchmark >> "$1" 2>&1
	if [[ "$?" -ne 0 ]]; then
		echo 'Benchmarks failed.' >&2
		return 1
	fi
	echo 'Successfully ran benchmarks.' >&2
	return 0
}

# Runs examples.
#
# $1 - log file
run_examples() {
	echo 'Running examples...' >&2
	make examples >> "$1" 2>&1
	if [[ "$?" -ne 0 ]]; then
		echo 'Examples failed.' >&2
		return 1
	fi
	echo 'Successfully ran examples.' >&2
	return 0
}

# Tests whether the project successfully installs via `npm`.
#
# $1 - log file
test_npm_install() {
	echo 'Testing npm install...' >&2
	make test-npm-install >> "$1" 2>&1
	if [[ "$?" -ne 0 ]]; then
		echo 'Installation failed.' >&2
		return 1
	fi
	echo 'Successfully installed.' >&2

	echo 'Testing npm install (via GitHub)...' >&2
	make test-npm-install-github >> "$1" 2>&1
	if [[ "$?" -ne 0 ]]; then
		echo 'Installation (via GitHub) failed.' >&2
		return 1
	fi
	echo 'Successfully installed (via GitHub).' >&2

	return 0
}

# Checks dependencies.
#
# $1 - log file
check_deps() {
	echo 'Checking dependencies...' >&2
	make check-deps >> "$1" 2>&1
	if [[ "$?" -ne 0 ]]; then
		echo 'Dependencies are out-of-date.' >&2
		return 1
	fi
	echo 'Dependencies are up-to-date.' >&2
	return 0
}

# Main execution sequence.
main() {
	create_log_file "${log_file}"
	start_heartbeat "${heartbeat_interval}"

	echo "Task: ${task}." >&2
	if [[ "${task}" = "test-npm-install" ]]; then
		test_npm_install "${log_file}"
		if [[ "$?" -ne 0 ]]; then
			on_error 1
		fi
	elif [[ "${task}" = "test" ]]; then
		run_tests "${log_file}"
		if [[ "$?" -ne 0 ]]; then
			on_error 1
		fi
	elif [[ "${task}" = "benchmark" ]]; then
		run_benchmarks "${log_file}"
		if [[ "$?" -ne 0 ]]; then
			on_error 1
		fi
	elif [[ "${task}" = "examples" ]]; then
		run_examples "${log_file}"
		if [[ "$?" -ne 0 ]]; then
			on_error 1
		fi
	elif [[ "${task}" = "test-coverage" ]]; then
		run_test_coverage "${log_file}"
		if [[ "$?" -ne 0 ]]; then
			on_error 1
		fi
		send_coverage "unit_test" "${log_file}"
		if [[ "$?" -ne 0 ]]; then
			on_error 1
		fi
	elif [[ "${task}" = "check-deps" ]]; then
		check_deps "${log_file}"
		if [[ "$?" -ne 0 ]]; then
			on_error 1
		fi
	else
		echo "ERROR: unknown task: ${task}." >&2
		on_error 1
	fi
	cleanup
	print_success
	exit 0
}

# Set an error handler to print captured output and perform any clean-up tasks:
trap 'on_error' ERR

# Run main:
main
