#!/usr/bin/env sh
# shellcheck source=/dev/null

# a wrapper function to handle cookies for unauthenticated downloads and to fetch document size all
_cookies_and_document_stuff() {
    "${EXTRA_LOG}" "justify" "Fetching" " ${1:?}.." "-"
    # shellcheck disable=SC2086
    _curl --compressed ${CURL_PROGRESS} ${3:-} \
        "${4:---header}" "${5:-}" \
        -c "${TMPFILE}_${file_id_download_file}_COOKIE" -o "${TMPFILE}_${file_id_download_file}_misc" \
        "${2:?}" || return 1
    # ensure that the file is created
    print '' >> "${TMPFILE}_${file_id_download_file}_misc"
    for _ in 1 2; do _clear_line 1; done
}

###################################################
# common stuff in both curl and aria2c function
# uses file_id var
# Todo: write doc
###################################################
_common_stuff() {
    export OAUTH_ENABLED TMPFILE ACCESS_TOKEN API_URL API_VERSION API_KEY API_KEY_DOWNLOAD EXTRA_LOG CURL_PROGRESS DOWNLOADER DOCUMENT_FORMAT DOCUMENT_FORMAT_ESCAPED
    # download with oauth creds if enabled
    if [ -n "${OAUTH_ENABLED:-${API_KEY_DOWNLOAD}}" ]; then
        url_download_file="${API_URL}/drive/${API_VERSION}/files/${file_id_download_file}$(
            case "${mime_download_file}" in
                "application/vnd.google-apps."*) printf "%s" "/export?mimeType=${DOCUMENT_FORMAT_ESCAPED}" ;;
                *) printf "?alt=media" ;;
            esac
        )&supportsAllDrives=true&includeItemsFromAllDrives=true"

        if [ -n "${OAUTH_ENABLED}" ]; then
            . "${TMPFILE}_ACCESS_TOKEN"
            flag_download_file="--header" flag_value_download_file="Authorization: Bearer ${ACCESS_TOKEN}"
        elif [ -n "${API_KEY_DOWNLOAD}" ]; then
            # download with api key
            flag_download_file="--referer" flag_value_download_file="https://drive.google.com"
            url_download_file="${url_download_file}&key=${API_KEY}"
        fi

        case "${mime_download_file}" in
            "application/vnd.google-apps."*)
                _cookies_and_document_stuff "document size" "${url_download_file}" "-LI" "${flag_download_file}" "${flag_value_download_file}" || return 1
                server_size_download_file="$(($(_tmp="$(grep -F 'content-length' "${TMPFILE}_${file_id_download_file}_misc")" && _tmp="${_tmp##content-length: }" && printf "%s\n" "${_tmp%"$(printf '\r')"}")))"
                server_size_readable_download_file="$(_bytes_to_human "${server_size_download_file}" 2>| /dev/null)"

                _clear_line 1
                _print_center "justify" "${name_download_file}" " | ${server_size_readable_download_file}" "="
                ;;
            *) : ;;
        esac
    else
        flag_download_file="-b" flag_value_download_file="${TMPFILE}_${file_id_download_file}_COOKIE"

        case "${mime_download_file}" in
            "application/vnd.google-apps."*)
                # fetch the export links
                json_common_stuff="$("${API_REQUEST_FUNCTION}" "files/${file_id_download_file}?alt=json&fields=exportLinks")" || return 1
                url_download_file="$(printf "%s\n" "${json_common_stuff}" | _json_value "${DOCUMENT_FORMAT_ESCAPED}" 1 1)" || return 0

                _cookies_and_document_stuff "cookies and document size" "${url_download_file}" "-LI" || return 1

                server_size_download_file="$(($(_tmp="$(grep -F 'content-length' "${TMPFILE}_${file_id_download_file}_misc")" && _tmp="${_tmp##content-length: }" && printf "%s\n" "${_tmp%"$(printf '\r')"}")))"

                server_size_readable_download_file="$(_bytes_to_human "${server_size_download_file}" 2>| /dev/null)"
                _clear_line 1
                _print_center "justify" "${name_download_file}" " | ${server_size_readable_download_file}" "="
                ;;
            *) # normal downloading
                url_download_file="https://drive.google.com/uc?export=download&id=${file_id_download_file}"

                _cookies_and_document_stuff "cookies" "${url_download_file}" "-L" || return 1

                confirm_string="$(_tmp="$(grep -F 'download_warning' "${TMPFILE}_${file_id_download_file}_COOKIE")" && printf "%s\n" "${_tmp##*"$(printf '\t')"}")" || :
                # https://github.com/Akianonymus/gdrive-downloader/issues/37
                # sometimes the url doesn't return a proper cookie
                # so try to parse the html output and get the confirm string
                [ -z "${confirm_string}" ] && {
                    confirm_string="$(_tmp="$(grep -Eo "export=download.*${file_id_download_file}.*confirm=\w+" "${TMPFILE}_${file_id_download_file}_misc")" && printf "%s\n" "${_tmp##*=}")"
                }

                url_download_file="${url_download_file}${confirm_string:+&confirm=${confirm_string}}"
                ;;
        esac
        # aria need some elements removed from cookies when it is generated by curl
        [ "${DOWNLOADER}" = "aria2c" ] && {
            cookies_download_file="$(sed -e "s/^\# .*//g" -e "s/^\#HttpOnly_//g" "${TMPFILE}_${file_id_download_file}_COOKIE")"
            printf "%s\n" "${cookies_download_file}" >| "${TMPFILE}_${file_id_download_file}_COOKIE"
            flag_download_file="--load-cookies"
        }

    fi

    return 0
}

###################################################
# Download with aria2c
# Todo: write doc
###################################################
_download_with_aria2c() {
    export ARIA_FLAGS QUIET
    [ $# -lt 3 ] && printf "Missing arguments\n" && return 1
    file_id_download_file="${1}" name_download_file="${2}" mime_download_file="${3}" server_size_download_file="${4}" parallel_download_file="${5}"
    unset flag_download_file flag_value_download_file url_download_file cookies_download_file

    server_size_readable_download_file="$(_bytes_to_human "${server_size_download_file}" 2>| /dev/null)"
    _print_center "justify" "${name_download_file}" " | ${server_size_readable_download_file}" "="

    # flag_download_file, flag_value_download_file and url_download_file var is modified by this function and later used
    # also setup the cookies in no auth or no api key download
    _common_stuff || return 1
    download_status=0

    # shellcheck disable=SC2086
    aria2c ${ARIA_FLAGS} \
        "${flag_download_file}" "${flag_value_download_file}" \
        "${url_download_file}" -o "${name_download_file}" || download_status=1

    if [ "${download_status}" -eq 0 ]; then
        "${QUIET:-_print_center}" "justify" "Downloaded" "=" && _newline "\n"
        rm -f -- "${name}.aria2"
    else
        "${QUIET:-_print_center}" "justify" "Error: Incomplete" " download." "=" 1>&2
        return 1
    fi
    _log_in_file "${name_download_file}" "${server_size_readable_download_file}" "${file_id_download_file}"
    return 0
}

###################################################
# Download with curl
# Todo: write doc
###################################################
_download_with_curl() {
    export QUIET
    [ $# -lt 3 ] && printf "Missing arguments\n" && return 1
    file_id_download_file="${1}" name_download_file="${2}" mime_download_file="${3}" server_size_download_file="${4}" parallel_download_file="${5}"
    unset range_download_file downloaded_download_file old_downloaded_download_file left_download_file speed_download_file eta_download_file \
        flag_download_file flag_value_download_file url_download_file cookies_download_file

    server_size_readable_download_file="$(_bytes_to_human "${server_size_download_file}" 2>| /dev/null)"
    _print_center "justify" "${name_download_file}" " | ${server_size_readable_download_file}" "="

    __check_for_resume_download_with_curl() {
        if [ -s "${name_download_file}" ]; then
            local_size_download_file="$(_actual_size_in_bytes "${name_download_file}")"

            if [ "${local_size_download_file}" -ge "$((server_size_download_file))" ]; then
                "${QUIET:-_print_center}" "justify" "File already present" "=" && _newline "\n"
                _log_in_file
                return 1
            else
                _print_center "justify" "File is partially" " present, resuming.." "-"
                range_download_file="Range: bytes=${local_size_download_file}-${server_size_download_file}"
            fi
        else
            [ "$((server_size_download_file))" -gt 0 ] && range_download_file="Range: bytes=0-${server_size_download_file}"
            _print_center "justify" "Downloading file.." "-"
        fi
    }

    case "${mime_download_file}" in
        "application/vnd.google-apps.document")
            _common_stuff || return 1
            __check_for_resume_download_with_curl || return 0
            ;;
        *)
            __check_for_resume_download_with_curl || return 0
            _common_stuff || return 1
            ;;
    esac

    # shellcheck disable=SC2086
    _curl -Ls \
        --header "${range_download_file}" \
        "${flag_download_file}" "${flag_value_download_file}" \
        "${url_download_file}" >> "${name_download_file}" &
    pid="${!}"

    if [ -n "${parallel_download_file}" ]; then
        wait "${pid}" 2>| /dev/null 1>&2
    else
        until [ -f "${name_download_file}" ] || ! kill -0 "${pid}" 2>| /dev/null 1>&2; do sleep 0.5; done

        _newline "\n\n"
        until ! kill -0 "${pid}" 2>| /dev/null 1>&2; do
            downloaded_download_file="$(_actual_size_in_bytes "${name_download_file}")"
            left_download_file="$((server_size_download_file - downloaded_download_file))"
            speed_download_file="$((downloaded_download_file - old_downloaded_download_file))"
            { [ "${speed_download_file}" -gt 0 ] && eta_download_file="$(_display_time "$((left_download_file / speed_download_file))")"; } || eta_download_file=""
            sleep 0.5
            _move_cursor 2
            ##################################################### Amount Downloaded ####################### Amount left to download ##################
            _print_center "justify" "Downloaded: $(_bytes_to_human "${downloaded_download_file}") " "| Left: $(_bytes_to_human "${left_download_file}")" "="
            ########################################### Speed of download ############### ETA ######################
            _print_center "justify" "Speed: $(_bytes_to_human "${speed_download_file}")/s " "| ETA: ${eta_download_file:-Unknown}" "-"
            old_downloaded_download_file="${downloaded_download_file}"
        done
    fi

    if [ "$(_actual_size_in_bytes "${name_download_file}")" -ge "$((server_size_download_file))" ]; then
        for _ in 1 2 3; do _clear_line 1; done
        "${QUIET:-_print_center}" "justify" "Downloaded" "=" && _newline "\n"
        rm -f -- "${name}.aria2"
    else
        "${QUIET:-_print_center}" "justify" "Error: Incomplete" " download." "=" 1>&2
        return 1
    fi
    _log_in_file "${name_download_file}" "${server_size_readable_download_file}" "${file_id_download_file}"
    return 0
}

###################################################
# A extra wrapper for _download_file function to properly handle retries
# also handle uploads in case downloading from folder
# Todo: write doc
###################################################
_download_file_main() {
    export DOWNLOADER DOCUMENT_FORMAT
    [ $# -lt 2 ] && printf "Missing arguments\n" && return 1
    unset line_download_file_main fileid_download_file_main name_download_file_main mime_download_file_main size_download_file_main parallel_download_file_main RETURN_STATUS sleep_download_file_main && retry_download_file_main="${RETRY:-0}"

    if [ "${1}" = parse ]; then
        line_download_file_main="${2:?}"
        parallel_download_file_main="${3}"

        # "root_folder_name|:_//_:|id|:_//_:|name|:_//_:|size|:_//_:|mime"
        root_download_file_main="${line_download_file_main%%"|:_//_:|"*}"

        fileid_download_file_main="${line_download_file_main##"${root_download_file_main}""|:_//_:|"}"
        fileid_download_file_main="${fileid_download_file_main%%"|:_//_:|"*}"

        name_download_file_main="${line_download_file_main##*"${fileid_download_file_main}""|:_//_:|"}"
        name_download_file_main="${name_download_file_main%%"|:_//_:|"*}"

        size_download_file_main="${line_download_file_main##*"${name_download_file_main}""|:_//_:|"}"
        size_download_file_main="${size_download_file_main%%"|:_//_:|"*}"

        mime_download_file_main="${line_download_file_main##*"|:_//_:|"}"
    else
        fileid_download_file_main="${2:?}"
        name_download_file_main="${3:?}"
        mime_download_file_main="${4}"

        size_download_file_main="${5}"
        size_download_file_main="$((size_download_file_main))"
    fi

    # just return if fileid or name is empty
    [ -z "${fileid_download_file_main:+${name_download_file_main}}" ] && return 0

    case "${mime_download_file_main}" in
        "application/vnd.google-apps."*)
            if [ -z "${DOCUMENT_FORMAT:+${DOCUMENT_FORMAT_ESCAPED}}" ]; then
                DOCUMENT_FORMAT="$(_get_export_mime ext "${mime_download_file_main}")"
                DOCUMENT_FORMAT_ESCAPED="$(_get_export_mime mime "${mime_download_file_main}")"
            fi
            name_download_file_main="${name_download_file_main}.${DOCUMENT_FORMAT}"
            ;;
        *) : ;;
    esac

    unset RETURN_STATUS && until [ "${retry_download_file_main}" -le 0 ] && [ -n "${RETURN_STATUS}" ]; do
        if [ -n "${parallel_download_file_main}" ]; then
            (
                [ "${1}" = parse ] && { cd -- "${root_download_file_main}" || return 1; }
                "_download_with_${DOWNLOADER}" "${fileid_download_file_main}" "${name_download_file_main}" "${mime_download_file_main}" "${size_download_file_main}" true 2>| /dev/null 1>&2
            ) && RETURN_STATUS=1 && break
        else
            (
                [ "${1}" = parse ] && { cd -- "${root_download_file_main}" || return 1; }
                "_download_with_${DOWNLOADER}" "${fileid_download_file_main}" "${name_download_file_main}" "${mime_download_file_main}" "${size_download_file_main}"
            ) && RETURN_STATUS=1 && break
        fi
        sleep "$((sleep_download_file_main += 1))" # on every retry, sleep the times of retry it is, e.g for 1st, sleep 1, for 2nd, sleep 2
        RETURN_STATUS=2 retry_download_file_main="$((retry_download_file_main - 1))" && continue
    done
    { [ "${RETURN_STATUS}" = 1 ] && printf "%b" "${parallel_download_file_main:+${RETURN_STATUS}\n}"; } || printf "%b" "${parallel_download_file_main:+${RETURN_STATUS}\n}" 1>&2
    return 0
}

###################################################
# Fetch folder info
# Recursively or single level
# Todo: write doc
###################################################
_fetch_folderinfo() {
    export EXTRA_LOG QUIET API_REQUEST_FUNCTION INCLUDE_FILES EXCLUDE_FILES VERBOSE SKIP_SUBDIRS
    parse_fetch_folderinfo="${1:?}"

    unset json_search_fetch_folderinfo json_search_fragment_fetch_folderinfo next_page_token_fetch_folderinfo \
        error_status_fetch_folderinfo success_status_fetch_folderinfo \
        files_id_fetch_folderinfo folders_id_fetch_folderinfo files_size_fetch_folderinfo \
        files_name_fetch_folderinfo folders_name_fetch_folderinfo files_mime_fetch_folderinfo \
        num_of_files_fetch_folderinfo num_of_folders_fetch_folderinfo

    if [ "${parse_fetch_folderinfo}" = "true" ]; then
        mode_fetch_folderinfo="${2:?_fetch_folderinfo: 2}"
        line_fetch_folderinfo="${3:?_fetch_folderinfo: 3}"
        files_list_fetch_folderinfo="${4:?_fetch_folderinfo: 4}" folders_list_fetch_folderinfo="${5:?_fetch_folderinfo: 5}"
        # parallel_fetch_folderinfo="${6}"
        # extracting data from this format "folder_id_fetch_folderinfo|:_//_:|folder_name|:_//_:|id|:_//_:|name"
        name_fetch_folderinfo="${line_fetch_folderinfo##*"|:_//_:|"}"

        _tmp_root_fetch_folderinfo="${line_fetch_folderinfo%"|:_//_:|"*}"
        _tmp_root_fetch_folderinfo="${_tmp_root_fetch_folderinfo%"|:_//_:|"*}"
        root_name_fetch_folderinfo="${_tmp_root_fetch_folderinfo#*"|:_//_:|"}"

        _tmp_id_fetch_folderinfo="${line_fetch_folderinfo%%"|:_//_:|""${name_fetch_folderinfo}"}"
        folder_id_fetch_folderinfo="${_tmp_id_fetch_folderinfo##*"|:_//_:|"}"
    else
        mode_fetch_folderinfo="${2:?_fetch_folderinfo: 2}"
        folder_id_fetch_folderinfo="${3:?_fetch_folderinfo: 3}"
        name_fetch_folderinfo="${4:?_fetch_folderinfo: 4}" root_name_fetch_folderinfo="${5:?_fetch_folderinfo: 5}"
        files_list_fetch_folderinfo="${6:?_fetch_folderinfo: 6}" folders_list_fetch_folderinfo="${7:?_fetch_folderinfo: 7}"
        # parallel_fetch_folderinfo="${8}"
    fi

    if [ "${root_name_fetch_folderinfo}" = "${PWD}" ]; then
        _newline "\n"
    else
        "${EXTRA_LOG}" "justify" "Root folder name: ${root_name_fetch_folderinfo##"${PWD}"/}" "="
    fi

    "${EXTRA_LOG}" "justify" "${name_fetch_folderinfo}" "="
    "${EXTRA_LOG}" "justify" "Fetching folder" " details.." "-"
    _search_error_message_fetch_folderinfo() {
        "${QUIET:-_print_center}" "justify" "Error: Cannot" ", fetch folder details." "="
        printf "%s\n" "${1:-}" && return 1
    }

    # do the first request with pagesize 1000, and fetch nextPageToken
    if json_search_fetch_folderinfo="$("${API_REQUEST_FUNCTION}" "files?q=%27${folder_id_fetch_folderinfo}%27+in+parents&fields=nextPageToken,files(name,size,id,mimeType)&pageSize=1000&orderBy=name")"; then
        # fetch next page jsons till next_page_token_fetch_folderinfo is available
        while :; do
            next_page_token_fetch_folderinfo="$(printf "%s\n" "${json_search_fragment_fetch_folderinfo:-${json_search_fetch_folderinfo}}" | _json_value nextPageToken 1 1 || :)"
            [ -z "${next_page_token_fetch_folderinfo}" ] && break
            json_search_fragment_fetch_folderinfo="$("${API_REQUEST_FUNCTION}" "files?q=%27${folder_id_fetch_folderinfo}%27+in+parents&fields=nextPageToken,files(name,size,id,mimeType)&pageSize=1000&orderBy=name&pageToken=${next_page_token_fetch_folderinfo}")" ||
                _search_error_message_fetch_folderinfo "${json_search_fragment_fetch_folderinfo}"

            # append the new fetched json to initial json
            json_search_fetch_folderinfo="${json_search_fetch_folderinfo}
${json_search_fragment_fetch_folderinfo}"
        done
    else
        # error message in case some thing goes wrong
        _search_error_message_fetch_folderinfo "${json_search_fetch_folderinfo}"
    fi && _clear_line 1

    # parse the fetched json and make a list containing files size, name, id and mimeType
    "${EXTRA_LOG}" "justify" "Preparing files list.." "="
    files_id_fetch_folderinfo="$(printf "%s\n" "${json_search_fetch_folderinfo}" | _json_value id all all)" || :
    files_size_fetch_folderinfo="$(printf "%s\n" "${json_search_fetch_folderinfo}" | _json_value size all all)" || :
    files_name_fetch_folderinfo="$(printf "%s\n" "${json_search_fetch_folderinfo}" | _json_value name all all)" || :
    files_mime_fetch_folderinfo="$(printf "%s\n" "${json_search_fetch_folderinfo}" | _json_value mimeType all all)" || :

    chmod +w+r -- "${files_list_fetch_folderinfo}"
    exec 5<< EOF
$(printf "%s\n" "${files_id_fetch_folderinfo}")
EOF
    exec 6<< EOF
$(printf "%s\n" "${files_size_fetch_folderinfo}")
EOF
    exec 7<< EOF
$(printf "%s\n" "${files_name_fetch_folderinfo}")
EOF
    exec 8<< EOF
$(printf "%s\n" "${files_mime_fetch_folderinfo}")
EOF
    while IFS= read -r id <&5 && read -r size <&6 && read -r name <&7 && read -r mime <&8; do
        [ -n "${id:+${name}}" ] &&
            printf "%s\n" "${root_name_fetch_folderinfo}/${name_fetch_folderinfo}|:_//_:|${id}|:_//_:|${name}|:_//_:|$((size))|:_//_:|${mime}"
    done >> "${files_list_fetch_folderinfo}"
    exec 5<&- && exec 6<&- && exec 7<&- && exec 8<&-
    _clear_line 1
    chmod -w+r -- "${files_list_fetch_folderinfo}"

    if [ -f "${name_fetch_folderinfo}" ]; then
        name_fetch_folderinfo="${name_fetch_folderinfo}$(_epoch)"
    fi
    mkdir -p -- "${root_name_fetch_folderinfo}/${name_fetch_folderinfo}"

    # parse the fetched json and make a list containing sub folders name and id
    "${EXTRA_LOG}" "justify" "Preparing sub folders list.." "="
    folders_id_fetch_folderinfo="$(printf "%s\n" "${json_search_fetch_folderinfo}" | grep '"mimeType":.*folder.*' -B2 | _json_value id all all)" || :
    folders_name_fetch_folderinfo="$(printf "%s\n" "${json_search_fetch_folderinfo}" | grep '"mimeType":.*folder.*' -B1 | _json_value name all all)" || :

    chmod +w+r -- "${folders_list_fetch_folderinfo}"
    exec 5<< EOF
$(printf "%s\n" "${folders_id_fetch_folderinfo}")
EOF
    exec 6<< EOF
$(printf "%s\n" "${folders_name_fetch_folderinfo}")
EOF
    _tmp_folders_list_fetch_folderinfo="$(while IFS= read -r id <&5 && read -r name <&6; do
        [ -n "${id:+${name}}" ] &&
            printf "%s\n" "${folder_id_fetch_folderinfo}|:_//_:|${root_name_fetch_folderinfo}/${name_fetch_folderinfo}|:_//_:|${id}|:_//_:|${name}"
    done)"
    printf "%s" "${_tmp_folders_list_fetch_folderinfo}" >> "${folders_list_fetch_folderinfo}"
    exec 5<&- && exec 6<&-
    chmod -w+r -- "${folders_list_fetch_folderinfo}"
    _clear_line 1

    for _ in 1 2; do _clear_line 1; done

    [ "${mode_fetch_folderinfo}" = "alt" ] || return 0

    if [ -z "${SKIP_SUBDIRS}" ] && [ -n "${folders_list_fetch_folderinfo}" ]; then
        while IFS= read -r line <&4 && { [ -n "${line}" ] || continue; }; do
            _fetch_folderinfo true "${mode_fetch_folderinfo}" "${line}" "${files_list_fetch_folderinfo}" "${folders_list_fetch_folderinfo}"
        done 4<< EOF
$(printf "%s\n" "${_tmp_folders_list_fetch_folderinfo}")
EOF
    fi

    return 0
}

_download_folder() {
    export EXTRA_LOG QUIET API_REQUEST_FUNCTION INCLUDE_FILES EXCLUDE_FILES TMPFILE VERBOSE SKIP_SUBDIRS NO_OF_PARALLEL_JOBS
    [ $# = 4 ] && printf "Missing arguments\n" && return 1
    mode_download_folder="${1}" folder_id_download_folder="${2}" name_download_folder="${3}" root_download_folder="${4:-${PWD}}" parallel_download_folder="${5}"
    unset error_status_download_folder success_status_download_folder num_of_files_download_folder num_of_folders_download_folder

    if [ "${mode_download_folder}" = "alt" ]; then
        files_list_download_folder="${TMPFILE}_files_list"
        folders_list_download_folder="${TMPFILE}_folders_list"
    else
        files_list_download_folder="${TMPFILE}_files_list_${folder_id_download_folder}"
        folders_list_download_folder="${TMPFILE}_folders_list_${folder_id_download_folder}"
    fi

    printf '' >| "${files_list_download_folder}"
    printf '' >| "${folders_list_download_folder}"

    _fetch_folderinfo false "${mode_download_folder}" "${folder_id_download_folder}" "${name_download_folder}" "${root_download_folder}" \
        "${files_list_download_folder}" "${folders_list_download_folder}" "${parallel_download_folder}"

    chmod +w+r -- "${files_list_download_folder}" "${folders_list_download_folder}"
    # include or exlude the files if -in or -ex flag was used, use grep
    [ -n "${INCLUDE_FILES}" ] && _tmp_filesinfo="$(grep -E "${INCLUDE_FILES}" "${files_list_download_folder}")" &&
        printf "%s\n" "${_tmp_filesinfo}" >> "${files_list_download_folder}"
    [ -n "${EXCLUDE_FILES}" ] && _tmp_filesinfo="$(grep -Ev "${EXCLUDE_FILES}" "${files_list_download_folder}")" &&
        printf "%s\n" "${_tmp_filesinfo}" >> "${files_list_download_folder}"
    chmod -w+r -- "${files_list_download_folder}" "${folders_list_download_folder}"

    num_of_files_download_folder="$(_count < "${files_list_download_folder}")"
    num_of_folders_download_folder="$(_count < "${folders_list_download_folder}")"

    { [ "${mode_download_folder}" = "alt" ] && _tmp_sum_download_folder="$((num_of_files_download_folder))"; } || _tmp_sum_download_folder="$((num_of_files_download_folder + num_of_folders_download_folder))"
    [ "$((_tmp_sum_download_folder))" -eq 0 ] &&
        for _ in 1 2; do _clear_line 1; done && _print_center "justify" "${name_download_folder}" " | Empty Folder" "=" && _newline "\n" && return 0

    _print_center "justify" \
        "${name_download_folder}" \
        "${num_of_files_download_folder:+ | ${num_of_files_download_folder} files}${num_of_folders_download_folder:+ | ${num_of_folders_download_folder} sub folders}" "="
    _newline "\n\n"

    if [ "$((num_of_files_download_folder))" -gt 0 ]; then
        if [ -n "${parallel_download_folder}" ]; then
            NO_OF_PARALLEL_JOBS_FINAL="$((NO_OF_PARALLEL_JOBS > num_of_files_download_folder ? num_of_files_download_folder : NO_OF_PARALLEL_JOBS))"

            [ -f "${TMPFILE}"SUCCESS ] && rm "${TMPFILE}"SUCCESS
            [ -f "${TMPFILE}"ERROR ] && rm "${TMPFILE}"ERROR

            # shellcheck disable=SC2016
            (xargs -P"${NO_OF_PARALLEL_JOBS_FINAL}" -I "{}" -n 1 "${_SHELL:-sh}" -c '
                eval "${SOURCE_UTILS}"
                _download_file_main parse "{}" true
            ' < "${files_list_download_folder}" 1>| "${TMPFILE}"SUCCESS 2>| "${TMPFILE}"ERROR) &
            pid="${!}"

            until [ -f "${TMPFILE}"SUCCESS ] || [ -f "${TMPFILE}"ERROR ]; do sleep 0.5; done

            _clear_line 1
            until ! kill -0 "${pid}" 2>| /dev/null 1>&2; do
                success_status_download_folder="$(($(_count < "${TMPFILE}"SUCCESS)))"
                error_status_download_folder="$(($(_count < "${TMPFILE}"ERROR)))"
                sleep 1
                if [ "$((success_status_download_folder + error_status_download_folder))" != "${TOTAL}" ]; then
                    printf '%s\r' "$(_print_center "justify" "Status" ": ${success_status_download_folder:-0} Downloaded | ${error_status_download_folder:-0} Failed" "=")"
                fi
                TOTAL="$((success_status_download_folder + error_status_download_folder))"
            done
            _newline "\n"
            success_status_download_folder="$(($(_count < "${TMPFILE}"SUCCESS)))"
            error_status_download_folder="$(($(_count < "${TMPFILE}"ERROR)))"
            _clear_line 1 && _newline "\n"
        else
            while IFS= read -r line <&4 && { [ -n "${line}" ] || continue; }; do
                _download_file_main parse "${line}"
                : "$((RETURN_STATUS < 2 ? (success_status_download_folder += 1) : (error_status_download_folder += 1)))"
                if [ -z "${VERBOSE}" ]; then
                    for _ in 1 2 3 4; do _clear_line 1; done
                fi
                _print_center "justify" "Status" ": ${success_status_download_folder:-0} Downloaded | ${error_status_download_folder:-0} Failed" "="
            done 4< "${files_list_download_folder}"
        fi
    fi

    for _ in 1 2; do _clear_line 1; done
    [ "$((success_status_download_folder))" -gt 0 ] && "${QUIET:-_print_center}" "justify" "Downloaded" ": $((success_status_download_folder))" "="
    [ "$((error_status_download_folder))" -gt 0 ] && "${QUIET:-_print_center}" "justify" "Failed" ": $((error_status_download_folder))" "="
    _newline "\n"

    [ "${mode_download_folder}" = "alt" ] && return 0

    if [ -z "${SKIP_SUBDIRS}" ] && [ "$((num_of_folders_download_folder))" -gt 0 ]; then
        while IFS= read -r line <&4 && { [ -n "${line}" ] || continue; }; do
            #  "folder_id|:_//_:|root_name|:_//_:|id|:_//_:|name"
            (
                id="${line%"|:_//_:|"*}"
                id="${id##*"|:_//_:|"}"

                name="${line##*"|:_//_:|"}"

                root="${line#*"|:_//_:|"}"
                root="${root%%"|:_//_:|"*}"

                _download_folder "${mode_download_folder}" "${id}" "${name}" "${root}" "${parallel:-}"
            )
        done 4< "${folders_list_download_folder}"
    fi

    (rm -f -- "${files_list_download_folder}" "${folders_list_download_folder}") &
    return 0
}

###################################################
# Log downloaded file info in case of -l / --log flag
# Todo: write doc
###################################################
_log_in_file() {
    export LOG_FILE_ID
    [ -z "${LOG_FILE_ID}" ] || [ -d "${LOG_FILE_ID}" ] && return 0
    # shellcheck disable=SC2129
    # https://github.com/koalaman/shellcheck/issues/1202#issuecomment-608239163
    {
        printf "%s\n" "Name: ${1}"
        printf "%s\n" "Size: ${2}"
        printf "%s\n\n" "ID: ${3}"
    } >> "${LOG_FILE_ID}"
}
