#!/usr/bin/bash

# source bash base library
# shellcheck disable=SC1091
source /usr/libexec/bash-base.bash || {
        echo "$0: fatal error: failed to source /usr/libexec/bash-base.bash" >&2
        exit 1
}

bb_require_libs bash-ini ldapusermgmt/common

# shellcheck disable=SC2120,SC2034
function local_usage() {
    usage "${1-1}" "${2-}" "add" "del [<name>]" "deltree" \
        "list" <<EOF
  Removes on or more users specified on command line or read from pipe not
  connected to a terminal.
  Note: -s <section> is mandatory for add and deltree
EOF
}

function subhier_add() {
    (( $# == 0 )) || bb_fatal "subhier_add expects no args but got $#"

    local SUBHIER_NAME="${LDAP_EXTRA_SUBHIER-}"

    [ -n "$SUBHIER_NAME" ] || \
        bb_quit 1 "no subhier configured in section '${SECTION}' (needs ldap extra subhier)"

    ldap_cmd write ldapadd <<EOF || \
        bb_quit 1 "failed to add subhier: $SUBHIER_NAME"
dn: ou=$SUBHIER_NAME,${LDAP_USER_SUBHIER},${LDAP_SEARCH_BASE}
ou: $SUBHIER_NAME
objectClass: organizationalUnit

dn: ou=$SUBHIER_NAME,${LDAP_GROUP_SUBHIER},${LDAP_SEARCH_BASE}
ou: $SUBHIER_NAME
objectClass: organizationalUnit

dn: ou=$SUBHIER_NAME,${LDAP_AUTOFS_HOMES},${LDAP_AUTOFS_SUBHIER},${LDAP_SEARCH_BASE}
ou: $SUBHIER_NAME
objectClass: organizationalUnit
EOF
}

# subhier_del
# deletes empty subhiers
function subhier_del() {
    (( $# <= 1 )) || bb_fatal "subhier_del expects 0 or 1 arg but got $#"

    local _ou="${1-${LDAP_EXTRA_SUBHIER-}}"

    [ -n "$_ou" ] || \
        bb_quit 1 "need subhier name: specify as argument or with -s <section> (ldap extra subhier)"

    ldap_cmd write ldapdelete -c \
        "ou=$_ou,${LDAP_USER_SUBHIER},${LDAP_SEARCH_BASE}" \
        "ou=$_ou,${LDAP_GROUP_SUBHIER},${LDAP_SEARCH_BASE}" \
        "ou=$_ou,${LDAP_AUTOFS_HOMES},${LDAP_AUTOFS_SUBHIER},${LDAP_SEARCH_BASE}" \
        || bb_quit 1 "failed to delete subhier (maybe not empty?): $_ou"
}

# _expand_homedir_helper <homedir> <index>
# modifies vars: shdel__home_hosts _home_paths
function _expand_homedir_helper() {
    (( $# == 2 )) || \
        bb_fatal "_expand_homedir_helper called with $# instead of 2 args"

    local _homedir="$1"
    local _index="$2"

    if [[ "$_homedir" =~ : ]]
    then
        shdel__home_hosts[_index]="${_homedir%%:*}"
        shdel__home_paths[_index]="${_homedir#*:}"
    else
        shdel__home_hosts[_index]="localhost"
        shdel__home_paths[_index]="$_homedir"
    fi
}

# shdel_process_host <host>
# shellcheck disable=SC2034
function shdel_process_host() {
    (( $# == 1 )) || \
        bb_fatal "shdel_process_host called with $# instead of 1 arg"

    local _host="$1"

    local DEL_MUL_NAME="SUBHIER-$_ou"

    # FIXME: HOMEDIR_HOST_EXTRA_DELETE_PATHS should better be an array
    # shellcheck disable=SC2206
    local -a DEL_MUL_EXTRA_PATHS=($HOMEDIR_HOST_EXTRA_DELETE_PATHS)

    # FIXME: ARCHIVE_EXCLUDES should better be an array
    # shellcheck disable=SC2206
    local -a ARCHIVE_EXCLUDES=(${ARCHIVE_EXCLUDES-})

    local -a DEL_MUL_CNS DEL_MUL_HOMEDIRS
    local -i _i

    # filter all users that reside on this host
    for _i in "${!shdel__uids[@]}"
    do
        if [ "${shdel__home_hosts[$_i]}" == "$_host" ]
        then
            DEL_MUL_CNS[_i]="${shdel__uids[$_i]}"
            DEL_MUL_HOMEDIRS[_i]="${shdel__home_paths[$_i]}"
        fi
    done

    homedir_host_helper "$_host" delete_multiple_userdata \
        HOMEDIR_HOST_ARCHIVES_PATH ARCHIVE_EXCLUDES \
        DEL_MUL_NAME DEL_MUL_CNS DEL_MUL_HOMEDIRS DEL_MUL_EXTRA_PATHS
}

# subhier_deltree
# deletes subhiers including all users
function subhier_deltree() {
    (( $# == 0 )) || bb_fatal "subhier_deltree expects no args but got $#"

    local _ou="${LDAP_EXTRA_SUBHIER-}"

    [ -n "$_ou" ] || \
        bb_quit 1 "no subhier configured in section '${SECTION}' (needs ldap extra subhier)"

    [ -n "${LDAP_ONLY-}" ] || {
        local -a shdel__uids
        ldap_extract_attributes "uid" shdel__uids < \
            <(ldap_cmd read ldapsearch -LLL -z 0 \
            -b "ou=$_ou,${LDAP_USER_SUBHIER},${LDAP_SEARCH_BASE}" \
            objectclass=account uid || true)

        local -i _retval=0
        bb_array_is_empty shdel__uids || _retval="$?"
        (( _retval == 91 )) || {
            bb_msg info "deltree: subhier '$_ou' seems to be empty," \
                "redirecting to del"
            subhier_del "$_ou"
            return $?
        }

        bb_msg info "deltree users: ${shdel__uids[*]}"

        local -a shdel__homedirs=()
        local -i _i
        for i in "${!shdel__uids[@]}"
        do
            local _homedir
            if resolve_homedir _homedir "${shdel__uids[i]}" "$SECTION"
            then
                shdel__homedirs[i]="$_homedir"
            else
                local _ret=$?
                if (( _ret == 2 ))
                then
                    bb_msg err "user ${shdel__uids[$i]}: LDAP entry differs from config"
                else
                    bb_msg err "user ${shdel__uids[$i]}: cannot resolve homedir"
                fi
                bb_msg err "aborting deltree operation due to resolution error"
                return 1
            fi
        done

        bb_msg info "deltree homedirs: ${shdel__homedirs[*]}"

        # shellcheck disable=SC2034
        local -a shdel__home_hosts shdel__home_paths
        bb_array_iter_i shdel__homedirs _expand_homedir_helper

        local -a shdel__home_hosts_unique
        bb_array_unique shdel__home_hosts_unique \
            shdel__home_hosts

        bb_msg info "deltree unique hosts: ${shdel__home_hosts_unique[*]}"


        local -a shdel__current_host
        for shdel__current_host in "${shdel__home_hosts_unique[@]}"
        do
            bb_msg info "deltree: now working on host $shdel__current_host"
            shdel_process_host "$shdel__current_host"
        done

        # run POST_DELETE_USERS_HOOK
        if (( ${#POST_DELETE_USERS_HOOK[@]} > 0 ))
        then
            dw_run "${POST_DELETE_USERS_HOOK[@]}" || \
                bb_msg err "post delete users hook failed: $?"
        fi
    }

    # shellcheck disable=SC2034
    local -a LDAP_LOCAL_ARGS=("-r")

    ldap_cmd write ldapdelete -c \
        "ou=$_ou,${LDAP_USER_SUBHIER},${LDAP_SEARCH_BASE}" \
        "ou=$_ou,${LDAP_GROUP_SUBHIER},${LDAP_SEARCH_BASE}" \
        "ou=$_ou,${LDAP_AUTOFS_HOMES},${LDAP_AUTOFS_SUBHIER},${LDAP_SEARCH_BASE}" || \
        bb_quit 1 "failed to delete subhier tree '$_ou'"

    subhier_add
}

function subhier_list() {
    (( VERBOSITY < 2 )) || echo -e 'EXTRA-SUBHIER\tPARENT-SUBHIERS'
    {
        ldap_cmd read ldapsearch -Q -LLL -s children \
            -b "${LDAP_USER_SUBHIER},${LDAP_SEARCH_BASE}" \
            'objectClass=organizationalUnit' dn || \
            bb_fatal "subhier_list: ldapsearch failed";
        ldap_cmd read ldapsearch -Q -LLL -s children \
            -b "${LDAP_GROUP_SUBHIER},${LDAP_SEARCH_BASE}" \
            'objectClass=organizationalUnit' dn || \
            bb_fatal "subhier_list: ldapsearch failed";
        ldap_cmd read ldapsearch -Q -LLL -s children \
            -b "${LDAP_AUTOFS_HOMES},${LDAP_AUTOFS_SUBHIER},${LDAP_SEARCH_BASE}" \
            'objectClass=organizationalUnit' dn || \
            bb_fatal "subhier_list: ldapsearch failed";
    } | awk -F, '/^dn: / {gsub("dn: ",""); gsub("ou=","",$1); hash[$1] = sprintf( "%s %s", hash[$1], $2)} END { for (key in hash) { printf "%s\t\t%s\n", key, hash[key] }}' \
        | sort
}

function main() {
    # shellcheck disable=SC2119
    (( $# > 0 )) || local_usage 1 "Missing mandatory argument"

    config_init

    local _op="$1"
    shift
    case "$_op" in
        add)
            if [ -z "${SECTION-}" ]
            then
                bb_quit 1 "add requires a section to be specified with -s"
            fi
            subhier_add "$@";;
        del) subhier_del "$@";;
        deltree)
            # Section ist mandatory für deltree
            if [ -z "${SECTION-}" ]
            then
                bb_quit 1 "deltree requires a section to be specified with -s"
            fi

            if [ -z "${FORCE-}" ]
            then
                [ -t 0 ] || bb_quit 1 "deltree required force" \
                    "or interactive terminal on stdin to ask"
                bb_msg alert 'THIS WILL DELETE THE WHOLE SUBTREE!'
                bb_msg alert 'enter to continue, ctrl-c to abort'
                read -r || bb_quit 1 "aborted on users request"
            fi
            subhier_deltree "$@";;
        list) subhier_list;;
        *) local_usage 1 "illegal argument: $_op";;
    esac
}

parse_common_args main "" "" "$@"
bb_quit
