## library functions

LOG_DEBUG=
LOG_CMD=y
LOG_INFO=y
LOG_WARN=y
LOG_ERROR=y

function log_debug () {
    [ $LOG_DEBUG ] && echo "... $@" >&2

    return 0
}

function log_debugf () {
    local fmt=$1; shift 1

    [ $LOG_DEBUG ] && printf "... $fmt\n"  "$@"  >&2

    return 0
}

function log_info () {
    [ $LOG_INFO ] && echo "--- $@" >&2

    return 0
}

function log_cmd () {
    [ $LOG_CMD ] && echo ">>> $@" >&2

    return 0
}

function log_warn () {
    [ $LOG_WARN ] && echo "XXX $@" >&2

    return 0
}

function log_error () {
    [ $LOG_ERROR ] && echo "!!! $@" >&2

    return 0
}

function die () {
    log_error "$@"

    exit 1
}

# Execute command verbosely, and exit on failure
CMD_MOCK=
CMD_PROMPT=y

function cmd () {
    log_cmd "$@"

    [ $CMD_MOCK ] && return 0

    "$@" # return $?
}

function cmd_confirm () {
    [ $CMD_PROMPT ] && read -p "Confirm: $* ? "

    cmd "$@"
}

function cmd_sudo () {
    [ $CMD_PROMPT ] && read -p "Confirm: sudo: $* ? "

    cmd sudo -- "$@"
}


function expand_MB () {
    local size=${1^}

    case ${size: -1} in 
        G)
            size=$(( ${size%G} * 1024))

            ;;
    esac

    echo $size
}

function extract_iso () {
    iso=$1
    dst=$2

    [ ! -r "$iso" ] && die "Given .iso is not readable: $iso"
    [ -z "$dst" ] && die "Must give destination: $dst"
    [ -e "$dst" ] && die "Given destination already exists: $dst"

    # temporary mount
    mnt=$(mktemp -d mnt.XXXX)

    # clean on exit
    function cleanup () {
        if mountpoint -q $mnt; then
           sudo umount $mnt
        fi

        [ -d $mnt ] && rmdir $mnt

        return $1
    }

    # loop-mount
    cmd_sudo mount -o loop $iso $mnt || cleanup 1

    # copy
    cmd cp -rd $mnt $dst || cleanup 1

    # done, cleanup
    cleanup 0
}

function my_md5sum () {
    /usr/bin/md5sum $1 | (
        read md5sum path
        echo $md5sum
    )
}

function expand_line () {
    local line=$1

    # evaluate {...} expressions
    # a slight hack, but it works \o/
    # http://stackoverflow.com/questions/415677/how-to-replace-placeholders-in-a-text-file/7633579#7633579
    line="${line//\\/\\\\}"
    line="${line//\"/\\\"}"
    line="${line//\`/\\\`}"
    line="${line//\$/\\\$}"
    line="${line//{/\${}"   # This is just for vim: } "

    # log_debug "($line)" >&2
    eval "echo \"$line\""
}

function expand_template () {
    local linecount=0

    # read in each line at a time
    while IFS='' read -r line; do
        linecount=$((linecount + 1))

        if [ "${line:0:1}" == "#" ]; then
            # ignore comments; pass through as-is
            echo "$line"
        
        else
            expand_line "$line" || die "Error at $tpl:$linecount: $line"
        fi
 
    done
}

function expand_file () {
    local src=$1
    local dst=$2

    log_info "expand: file $src -> $dst"

    expand_template < $src > $dst
}

# Recursive expand_template files from src -> dst
# XXX: not used
function expand_tree () {
    local src=$1
    local dst=$2
    local filter=${3:-'*'}

    log_info "expand: tree $src/$filter -> $dst"

    [ ! -d $dst ] && cmd mkdir $dst

    for path in ${src}/${filter}; do
        local name=$(basename $path)
        local target=$dst/$name

        log_debug "expand_tree: $src: path=$path, name=$name, target=$target"

        if [ -d $path ]; then
            log_debug "expand_tree: $src: tree $name -> $target"
            expand_tree $path $target "$filter"

        elif [ -f $path ]; then
            log_debug "expand_tree: $src: file $name -> $target"
            expand_file $path $target

        else
            log_warn "expand_tree: $src: ignore $name"

        fi
    done
}
