#!/bin/bash

# Copyright (c) 2012-2014 Kaarle Ritvanen
# See LICENSE file for license details

function _aconf_req {
    local url=$ACONF_URL$1
    shift

    local resp
    resp=$(curl -s -w $'\n\nStatus: %{response_code}\r\n' \
	${AConf_Auth_Token:+-H "X-AConf-Auth-Token: $AConf_Auth_Token"} \
	${AConf_Transaction_ID:+-H "X-AConf-Transaction-ID: $AConf_Transaction_ID"} \
	"$@" $url)
    local code=$?

    if [ $code -gt 0 ]; then
	echo "Request failed, code $code" >&2
	return 1
    fi

    resp=$(echo "$resp" | sed $'s/\r//')
    echo "$resp"

    local status=$(echo "$resp" | sed 's/^Status: //;ta;d;:a;q')
    [ "${status:0:1}" = 2 ] && return

    echo "Request failed" >&2
    return 1
}

function _aconf_start_req {
    local url=$1
    shift

    local resp
    resp=$(_aconf_req "$url" "$@" -D /proc/self/fd/1 -o /proc/self/fd/3)
    [ $? -eq 0 ] || return

    local txn_id=$AConf_Transaction_ID

    while read line; do
	eval export "$line"
    done < <(echo "$resp" | \
	sed 's/^X-\(AConf-[-A-Za-z]\+\): /\1=/;ta;d;:a;y/-/_/')

    bash --rcfile "$ACONF_DEV_SHELL"
    [ $? -eq 254 ] || _aconf_req $url -X DELETE

    AConf_Transaction_ID=$txn_id
}

if [ "$AConf_Auth_Token" ]; then

    if [ "$AConf_Transaction_ID" ]; then
	cat >&2 <<EOF
Transaction $AConf_Transaction_ID started
Type 'commit' to commit, 'exit' to abort

EOF
    else
	cat >&2 <<EOF
Available commands:
  Fetch object:                              get <path>
  Create/update object:                      put <path> <JSON content>
  Add member to list/set or perform action:  post <path> <JSON content>
  Delete object:                             delete <path>
  Fetch metadata:                            meta <path>
  Start transaction:                         start
EOF
	if [ $AConf_Save_Required = 1 ]; then
	    echo "  Save changes persistently:                 save" >&2
	fi
cat >&2 <<EOF

Example: put /awall/zone/internet '{"iface": ["eth0"]}'

EOF
    fi

    PS1="$ACONF_USER@aconf-dev-shell${AConf_Transaction_ID:+($AConf_Transaction_ID)}> "

    if [ $AConf_Save_Required = 1 ]; then
	function save {
	    if [ "$AConf_Transaction_ID" ]; then
		echo "Transaction not committed" >&2
		return 1
	    fi
	    _aconf_req /save -X POST
	}
    fi

    function start {
	_aconf_start_req /transaction -X POST
    }

    function meta {
	_aconf_req "/meta$1"
    }

    function _aconf_obj_req {
	local path=/config$1
	shift
	_aconf_req "$path" "$@"
    }

    function _aconf_post_req {
	_aconf_obj_req "$2" -d "$3" -X $1
    }

    function get {
	_aconf_obj_req "$1"
    }

    function put {
	_aconf_post_req PUT "$@"
    }

    function post {
	_aconf_post_req POST "$@"
    }

    function delete {
	_aconf_obj_req "$1" -X DELETE
    }

    function commit {
	if [ "$AConf_Transaction_ID" ]; then
	    if _aconf_req /transaction -X PUT; then
		echo Committed >&2
		exit 254
	    fi
	else
	    echo "No transaction started" >&2
	fi
	return 1
    }

else
    cat >&2 <<EOF
Development shell for Alpine Configurator
Copyright (c) 2012-2014 Kaarle Ritvanen

EOF

    exec 3>&1
    export ACONF_DEV_SHELL=$0

    export ACONF_URL=http://localhost:8000
    export ACONF_USER=`whoami`
    PASSWORD=

    function usage {
	echo "Usage: $0 [-H <server_url>] [-u <username>] [-p <password>]" >&2
	exit $1
    }

    ARGS=$(getopt -o hH:p:u: -- "$@")
    [ $? -gt 0 ] && usage 1
    eval set -- $ARGS

    while :; do
	case $1 in
	    -h)
		usage 0
		;;
	    -H)
		shift
		ACONF_URL=$1
		;;
	    -p)
		shift
		PASSWORD=$1
		;;
	    -u)
		shift
		ACONF_USER=$1
		;;
	    --)
		break
	esac
	shift
    done

    if [ -z "$PASSWORD" ]; then
	echo -n "Password: " >&2
	read PASSWORD
	echo >&2
    fi

    AConf_Transaction_ID=

    _aconf_start_req /login \
	-d "{\"username\": \"$ACONF_USER\", \"password\": \"$PASSWORD\"}"
fi
