#!/usr/bin/env bash
set -e

if [ -z "$DOCKER_HOST" -a "$DOCKER_PORT_2375_TCP" ]; then
	export DOCKER_HOST='tcp://docker:2375'
fi

# for local testing only
#HOME_DIR=.

if [ "${LOG_FILE}" == "" ]; then
    LOG_DIR=/var/log/crontab
	LOG_FILE=${LOG_DIR}/jobs.log
	mkdir -p ${LOG_DIR}
    touch ${LOG_FILE}
fi

CONFIG=${HOME_DIR}/config.json
DOCKER_SOCK=/var/run/docker.sock
CRONTAB_FILE=/etc/crontabs/docker

# Ensure dir exist - in case of volume mapping
mkdir -p ${HOME_DIR}/jobs ${HOME_DIR}/projects

ensure_docker_socket_accessible() {
    if ! grep -q "^docker:" /etc/group; then
        # Ensure 'docker' user has permissions for docker socket (without changing permissions)
        DOCKER_GID=$(stat -c '%g' ${DOCKER_SOCK})
        if [ "${DOCKER_GID}" != "0" ]; then
            if ! grep -qE "^[^:]+:[^:]+:${DOCKER_GID}:" /etc/group; then
                # No group with such gid exists - create group docker
                addgroup -g ${DOCKER_GID} docker
                adduser docker docker
            else
                # Group with such gid exists - add user "docker" to this group
                DOCKER_GROUP_NAME=`getent group "${DOCKER_GID}" | awk -F':' '{{ print $1 }}'`
                adduser docker $DOCKER_GROUP_NAME
            fi
        else
            # Docker socket belongs to "root" group - add user "docker" to this group
            adduser docker root
        fi
    fi
}

slugify() {
    echo "$@" | iconv -t ascii | sed -r s/[~\^]+//g | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z
}

make_image_cmd() {
    DOCKERARGS=$(echo ${1} | jq -r .dockerargs)
    if [ "${DOCKERARGS}" == "null" ]; then DOCKERARGS=; fi
    IMAGE=$(echo ${1} | jq -r .image | envsubst)
    TMP_COMMAND=$(echo ${1} | jq -r .command)
    echo "docker run ${DOCKERARGS} ${IMAGE} ${TMP_COMMAND}"
}

make_container_cmd() {
    DOCKERARGS=$(echo ${1} | jq -r .dockerargs)
    if [ "${DOCKERARGS}" == "null" ]; then DOCKERARGS=; fi
    SCRIPT_NAME=$(echo ${1} | jq -r .name)
    SCRIPT_NAME=$(slugify $SCRIPT_NAME)
    PROJECT=$(echo ${1} | jq -r .project)
    CONTAINER=$(echo ${1} | jq -r .container | envsubst)
    TMP_COMMAND=$(echo ${1} | jq -r .command)

    if [ "${PROJECT}" != "null" ]; then

        # create bash script to detect all running containers
        if [ "${SCRIPT_NAME}" == "null" ]; then
            SCRIPT_NAME=$(cat /proc/sys/kernel/random/uuid)
        fi
cat << EOF > ${HOME_DIR}/projects/${SCRIPT_NAME}.sh
#!/usr/bin/env bash
set -e

CONTAINERS=\$(docker ps --format '{{.Names}}' | grep -E "^${PROJECT}_${CONTAINER}.[0-9]+")
for CONTAINER_NAME in \$CONTAINERS; do
    docker exec ${DOCKERARGS} \${CONTAINER_NAME} ${TMP_COMMAND}
done
EOF
        echo "/bin/bash ${HOME_DIR}/projects/${SCRIPT_NAME}.sh"
    else
        echo "docker exec ${DOCKERARGS} ${CONTAINER} ${TMP_COMMAND}"
    fi
}

#make_host_cmd() {
#   HOST_BINARY=$(echo ${1} | jq -r .host)
#   TMP_COMMAND=$(echo ${1} | jq -r .command)
#   echo "${HOST_BINARY} ${TMP_COMMAND}"
#}

make_cmd() {
    if [ "$(echo ${1} | jq -r .image)" != "null" ]; then
        make_image_cmd "$1"
    elif [ "$(echo ${1} | jq -r .container)" != "null" ]; then
        make_container_cmd "$1"
    #elif [ "$(echo ${1} | jq -r .host)" != "null" ]; then
    #   make_host_cmd "$1"
    else
        echo ${1} | jq -r .command
    fi
}

parse_schedule() {
	case $1 in
        "@yearly")
            echo "0 0 1 1 *"
            ;;
        "@annually")
            echo "0 0 1 1 *"
            ;;
        "@monthly")
            echo "0 0 1 * *"
            ;;
        "@weekly")
            echo "0 0 * * 0"
            ;;
        "@daily")
            echo "0 0 * * *"
            ;;
        "@midnight")
            echo "0 0 * * *"
            ;;
        "@hourly")
            echo "0 * * * *"
            ;;
        "@every")
            TIME=$2
            TOTAL=0

            M=$(echo $TIME | grep -o '[0-9]\+m')
            H=$(echo $TIME | grep -o '[0-9]\+h')
            D=$(echo $TIME | grep -o '[0-9]\+d')

            if [ -n "${M}" ]; then
                TOTAL=$(($TOTAL + ${M::-1}))
            fi
            if [ -n "${H}" ]; then
                TOTAL=$(($TOTAL + ${H::-1} * 60))
            fi
            if [ -n "${D}" ]; then
                TOTAL=$(($TOTAL + ${D::-1} * 60 * 24))
            fi

            echo "*/${TOTAL} * * * *"
            ;;
        *)
            echo "${@}"
            ;;
    esac
}

function build_crontab() {
    rm -rf ${CRONTAB_FILE}

    ONSTART=()
    while read i ; do

        SCHEDULE=$(jq -r .[$i].schedule ${CONFIG} | sed 's/\*/\\*/g')
        if [ "${SCHEDULE}" == "null" ]; then
            echo "Schedule Missing: $(jq -r .[$i].schedule ${CONFIG})"
            continue
        fi
        SCHEDULE=$(parse_schedule ${SCHEDULE} | sed 's/\\//g')

        if [ "$(jq -r .[$i].command ${CONFIG})" == "null" ]; then
            echo "Command Missing: $(jq -r .[$i].command ${CONFIG})"
            continue
        fi

        COMMENT=$(jq -r .[$i].comment ${CONFIG})
        if [ "${COMMENT}" != "null" ]; then
            echo "# ${COMMENT}" >> ${CRONTAB_FILE}
        fi

        SCRIPT_NAME=$(jq -r .[$i].name ${CONFIG})
        SCRIPT_NAME=$(slugify $SCRIPT_NAME)
        if [ "${SCRIPT_NAME}" == "null" ]; then
            SCRIPT_NAME=$(cat /proc/sys/kernel/random/uuid)
        fi

        COMMAND="/bin/bash ${HOME_DIR}/jobs/${SCRIPT_NAME}.sh"
cat << EOF > ${HOME_DIR}/jobs/${SCRIPT_NAME}.sh
#!/usr/bin/env bash
set -e

# TODO find workaround
# [error] write /dev/stdout: broken pipe <- when using docker commands
#UUID=\$(cat /proc/sys/kernel/random/uuid)
#exec > >(read message; echo "\${UUID} \$(date -Iseconds) [info] \$message" | tee -a ${LOG_FILE} )
#exec 2> >(read message; echo "\${UUID} \$(date -Iseconds) [error] \$message" | tee -a ${LOG_FILE} >&2)

echo "Start Cronjob **${SCRIPT_NAME}** ${COMMENT}"

$(make_cmd "$(jq -c .[$i] ${CONFIG})")
EOF



        if [ "$(jq -r .[$i].trigger ${CONFIG})" != "null" ]; then
            while read j ; do
                if [ "$(jq .[$i].trigger[$j].command ${CONFIG})" == "null" ]; then
                    echo "Command Missing: $(jq -r .[$i].trigger[$j].command ${CONFIG})"
                    continue
                fi
                #TRIGGER_COMMAND=$(make_cmd "$(jq -c .[$i].trigger[$j] ${CONFIG})")
                echo "$(make_cmd "$(jq -c .[$i].trigger[$j] ${CONFIG})")" >> ${HOME_DIR}/jobs/${SCRIPT_NAME}.sh
                #COMMAND="${COMMAND} && ${TRIGGER_COMMAND}"
            done < <(jq -r '.['$i'].trigger|keys[]' ${CONFIG})
        fi

        echo "echo \"End Cronjob **${SCRIPT_NAME}** ${COMMENT}\"" >> ${HOME_DIR}/jobs/${SCRIPT_NAME}.sh

        echo "${SCHEDULE} ${COMMAND}" >> ${CRONTAB_FILE}

        if [ "$(jq -r .[$i].onstart ${CONFIG})" == "true" ]; then
            ONSTART+=("${COMMAND}")
        fi
    done < <(jq -r '.|keys[]' ${CONFIG})

    echo "##### crontab generation complete #####"
    cat ${CRONTAB_FILE}

    echo "##### run commands with onstart #####"
    for COMMAND in "${ONSTART[@]}"; do
        echo "${COMMAND}"
        ${COMMAND} &
    done
}

ensure_docker_socket_accessible

if [ "$1" = "crond" ]; then
    if [ -f ${CONFIG} ]; then
        build_crontab
    else
        echo "Unable to find ${HOME_DIR}/config.json"
    fi
fi

echo "$@"
exec "$@"