#!/bin/bash

APP_PORT="${APP_PORT:=5000}"
BUILDSTEP_IMAGE="${BUILDSTEP_IMAGE:=ayufan/dokku-alt-buildstep:foreman}"

set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x

function info() {
	echo "-----> $@"
}

function info2() {
	echo "=====> $@"
}

function verbose() {
	echo "       $@"
}

function fail() {
	echo "$@" 1>&2
	exit 1
}

function generate_random_password() {
	< /dev/urandom tr -dc A-Za-z0-9 | head -c${1:-16} || true
}

function stop_container() {
	docker stop "$@" 1>/dev/null 2>/dev/null || true
}

function remove_container() {
	docker rm "$@" 1>/dev/null 2>/dev/null || true
}

function stop_and_remove_container() {
	stop_container "$@"
	remove_container "$@"
}

function remove_image() {
	docker rmi "$@" 1>/dev/null 2>/dev/null || true
}

function verify_max_args() {
	local MAX_ARGS="$1"
	[[ $# -le $((MAX_ARGS+1)) ]] || fail "Invalid number of arguments ($(($#-1)), expected $MAX_ARGS)."
}

function sanitize_name() {
	local NAME="$1"
	[[ "$NAME" == "" ]] && fail "You must specify an $2"
	local NAME2="${NAME//[^a-zA-Z0-9_-]//}"
	[[ "$NAME" != "$NAME2" ]] && fail "Invalid $2"
	return 0
}

function check_app_name() {
	sanitize_name "$1" "app name"
	APP="$1"
	IMAGE_GENERIC="dokku/$APP"

	if [[ "$IMAGE_TAG" != "" ]]; then
		IMAGE="$IMAGE_GENERIC:$IMAGE_TAG"
	else
		local CMD_TYPE="$(basename $0)"
		case "$CMD_TYPE" in
			"pre-build"|"post-build")		IMAGE="$IMAGE_GENERIC:build" ;;
			"pre-release"|"post-release")	IMAGE="$IMAGE_GENERIC:release" ;;
			*)								IMAGE="$IMAGE_GENERIC:latest" ;;
		esac
	fi

	APP_DIR="$DOKKU_ROOT/$APP"
	APP_NAME_FILE="$APP_DIR/CONTAINER"
	APP_NAME=""
	[[ -f "$APP_NAME_FILE" ]] && APP_NAME="$(< "$APP_NAME_FILE")"
	APP_CID_DIR="$APP_DIR/CONTAINERS"
	APP_CACHE_NAME="cache_data_$APP"
	APP_PERSISTENT_NAMES="$APP_CACHE_NAME"
	return 0
}

function get_app_container_name() {
	echo "${1}_${APP}_$(date +%s)_$RANDOM"
}

function get_cid_file_name() {
	[[ "$APP_CID_DIR" == "" ]] && fail "$APP: app not specified"
	mkdir -p "$APP_CID_DIR"
	echo "$APP_CID_DIR/${1}_$(date +%s)_$RANDOM.cid"
}

function config_get() {
	[[ "$APP" == "" ]] && fail "$APP: app not specified"
	[[ "$1" == "" ]] && fail "$APP: config key not specified"
	: | pluginhook env-vars "$APP" | grep "^$1=" | cut -d"=" -f2-
}

function stop_and_remove_app_containers() {
	[[ "$APP_CID_DIR" == "" ]] && fail "$APP: app not specified"

	if [[ "$1" != "" ]]; then
		info "Shutting down old containers ($1)"
		stop_and_remove_container "$1_$APP" &
		FILTER="$1_*.cid"
	else
		info "Shutting down old containers"
		stop_and_remove_container "dokku_$APP" &
		stop_and_remove_container "run_$APP" &
		FILTER="*.cid"
	fi

	if [[ -d "$APP_CID_DIR" ]]; then
		while read CID_FILE; do
			(
				CID="$(< "$CID_FILE")"
				if [[ "$CID" != "$2" ]]; then
					stop_and_remove_container "$(< "$CID_FILE")";
					rm -f "$CID_FILE"
				fi
			) &
		done < <(find "$APP_CID_DIR" -name "$FILTER")
	fi

	wait
}

function verify_app_name() {
	check_app_name "$@"
	[[ ! -d "$APP_DIR" ]] && fail "$APP: app doesn't exist"
	return 0
}

function require_image() {
	IMAGES=$(docker images "$1" | wc -l)
	[[ $IMAGES -ne 0 ]] && return
	fail "$1 image not found... Did you run 'dokku plugins-install' ?"
}

function release_app() {
  dokku release "$@"
}

function deploy_app() {
  dokku deploy "$@"
}

function redeploy_app() {
	release_app "$@"
	deploy_app "$@"
}

function tag_image() {
	docker tag -f "$1" "$2"
}

function wait_for_container() {
	for i in 1 2 3 4 5 6 7 8 9 0; do
		if docker inspect "$1" > /dev/null; then
			return 0
		fi
		sleep 0.3s
	done
	return 0
}

function is_image_buildstep_based() {
	docker run --entrypoint="/bin/bash" --rm "$@" -c "[[ -f /exec ]]"
}

function commit_image() {
	read ID
	wait_for_container "$ID"
	test $(docker wait "$ID") -eq 0
	docker commit "$ID" "$@" 1>/dev/null 2>/dev/null
	docker rm -f "$ID" 1>/dev/null 2>/dev/null || true
	return 0
}

function attach_and_commit_image() {
	read ID
	wait_for_container "$ID"
	for i in 1 2 3; do
		if docker attach "$ID"; then
			break
		fi
		sleep 0.3s
	done
	test $(docker wait "$ID") -eq 0
	docker commit "$ID" "$@" 1>/dev/null 2>/dev/null
	docker rm -f "$ID" 1>/dev/null 2>/dev/null || true
	return 0
}

function reset_timestamps() {
	find "$@" -exec touch -t 201401010000 "{}" \;
}

[[ -z "$DOKKU_ROOT" ]] && fail "DOKKU_ROOT not set"

CWD="$(cd "$(dirname "$0")" && pwd)"
