#!usr/bin/ash

run_hook() {
    local dir_home flag_tmp mount mount_id mount_path mounts_null \
        mounts_tmp mounts_zram mount_tmp mount_tmp ps_default ps_input \
        ps_timeout ram ram_min ram_pref s zram zram_max zram_min
    #global fsck_root mount_handler root zram_device zram_mount

    sleep 2
    source /etc/ramroot.conf

    # set mounts:
    for mount in $root:/ $mounts_zram; do
        flag_tmp=true
        for mount_tmp in $mounts_null; do
            if [ "$mount" = "$mount_tmp" ] || \
            [ "${mount#*:}" = "$mount_tmp" ]; then
                flag_tmp=false
            fi
        done
        for mount_tmp in $mounts_tmp; do
            if [ "$mount" = "$mount_tmp" ] || \
            [ "${mount#*:}" = "$mount_tmp" ]; then
                flag_tmp=false
            fi
        done
        if [ "$flag_tmp" = true ]; then
            mounts_tmp="$mounts_tmp$mount "
        fi
    done
    mounts_zram="$mounts_tmp"

    # RETURN: root in mounts_null:
    if [ "${mounts_zram%% *}" != "$root:/" ]; then
        return 0
    fi
    printf '\e[1;32m==> \e[1;37mChecking memory resources ...\n'

    # check mounts_zram:
    for mount in $mounts_zram; do
        mount_id="$(resolve_device "${mount%:*}")"
        mount_path="${mount#*:}"
        # FAIL: mount not found:
        if [ "$mount_id" = "$mount_path" ] || \
        [ -z "$mount_id" ] || [ -z "$mount_path" ]; then
            printf '\e[1;31m==> FAILED: \e[1;37m%s %s\e[0;37m\n' \
                'ramroot mount not found:' "$mount"
            sleep 2
            return 1
        fi
    done

    # set prompt:
    if (echo "$ps_default" | grep -Ei '^(y|yes)$' &>/dev/null); then
        ps_default='y'
    else
        ps_default='n'
    fi
    if (! echo "$ps_timeout" | grep -Ei \
    '^[1-9]+[0-9]*$' &>/dev/null); then
        ps_timeout=8
    elif [ $ps_timeout -lt 3 ]; then
        ps_timeout=3
    elif [ $ps_timeout -gt 32 ]; then
        ps_timeout=32
    fi

    # set sizes:
    if (! echo "$ram_min" | grep -E '^[1-9][0-9]*$' &>/dev/null); then
        ram_min=750
    fi
    if (! echo "$ram_pref" | grep -E '^[1-9][0-9]*$' &>/dev/null); then
        ram_pref=4000
    fi
    if (! echo "$zram_min" | grep -E '^[1-9][0-9]*$' &>/dev/null); then
        zram_min=250
    fi
    if (! echo "$zram_max" | grep -E '^[1-9][0-9]*$' &>/dev/null); then
        zram_max=1000
    fi
    if [ $ram_min -ge $ram_pref ]; then
        ram_pref=$ram_min
    fi
    if [ $zram_min -ge $zram_max ]; then
        zram_min=$zram_max
    fi

    # get available ram:
    ram="$(($(free | awk '/Mem/ {print int($2)}')/1024))"

    # get zram size:
    for mount in $mounts_zram; do
        sleep 1
        mount_id="$(resolve_device "${mount%:*}")"
        mount_path="${mount#*:}"
        poll_device "$mount_id" 20
        mount "$mount_id" /local_root
        # FAIL: unable to mount:
        if [ $? -ne 0 ]; then
            printf '\e[1;31m==> FAILED: \e[1;37m%s %s\e[0;37m\n' \
                'ramroot unable to mount:' "${mount%:*}"
            sleep 2
            return 1
        fi
        zram=$((zram+$(df -m /local_root/ | \
            awk 'FNR==2 {print int($3)}')))
        umount /local_root
    done
    # 10% free space reserved for root:
    zram=$((zram*110/100))

    printf '\e[1;34m -> \e[1;37maval: %dM\n\e[1;34m -> ' $ram
    printf '\e[1;37mreqd: %dM\n' $((zram+zram_min+ram_min))
    # WARM: not enough ram
    if [ $((ram-ram_min-zram-zram_min)) -le 0 ]; then
        printf '\e[1;33m==> SKIPPED: \e[1;37m%s\e[0;37m\n' \
            'ramroot: not enough ram'
        sleep 2
        return 0
    # calculate zram size:
    elif [ $((ram-ram_pref-zram-zram_min)) -le 0 ]; then
        zram=$((zram+zram_min))
    elif [ $((ram-ram_pref-zram-zram_max)) -le 0 ]; then
        zram=$((ram-ram_pref))
    else
        zram=$((zram+zram_max))
    fi

    # prompt for input:
    printf "\e[1;34m::> \e[1;37mLoad root file system to zram? "
    if [ "$ps_default" = 'y' ]; then
        printf '[Y/n] '
    else
        printf '[y/N] '
    fi
    # visual countdown:
    s=1
    while [ $s -lt $ps_timeout ]; do
        printf '.'
        s=$((s+1))
    done
    printf ' '
    s=0
    while [ $s -lt $ps_timeout ]; do
        read -rsn1 -t1 ps_input
        if [ $? -eq 0 ]; then
            s=$ps_timeout
        fi
        printf '\b\b '
        s=$((s+1))
    done
    ps_input="${ps_input:-$ps_default}"
    if [ "$ps_input" != 'y' ] && [ "$ps_input" != 'Y' ]; then
        printf 'no\n'
        return 0
    fi
    printf 'yes\n'

    # make zram device:
    if [ ! -b "/dev/zram0" ]; then
        modprobe zram
        # FAIL: zram module error:
        if [ $? -ne 0 ]; then
            printf '\e[1;31m==> FAILED: \e[1;37m%s\e[0;37m\n' \
                'error loading zram module'
            sleep 2
            return 1
        fi
        sleep 1
    fi
    sleep 1
    zram_device="$(zramctl -f -s ${zram}M -a lzo)"
    # FAIL: error initializing zram device:
    if [ $? -ne 0 ]; then
        printf '\e[1;31m==> FAILED: \e[1;37m%s\e[0;37m\n' \
            'error initializing zram device'
        sleep 2
        return 1
    fi
    mkfs.ext4 -q "$zram_device"
    # FAIL: error formatting zram device:
    if [ $? -ne 0 ]; then
        printf '\e[1;31m==> FAILED: \e[1;37m%s\e[0;37m\n' \
            'error formatting zram device'
        sleep 2
        return 1
    fi
    mount -o discard "$zram_device" /zram_root
    # FAIL: error mounting zram device:
    if [ $? -ne 0 ]; then
        printf '\e[1;31m==> FAILED: \e[1;37m%s\e[0;37m\n' \
            'error mounting zram device'
        sleep 2
        return 1
    fi
    if [ "$flag_quiet" = true ]; then
        printf '\e[0;30m'; clear
    fi

    # copy root to zram:
    for mount in $mounts_zram; do
        sleep 1
        mount_id="$(resolve_device "${mount%:*}")"
        mount_path="${mount#*:}"
        if [ "$flag_quiet" != true ]; then
            printf '\e[1;32m==> \e[1;37mLoading %s %s\e[0;37m\n' \
                "$mount_path" 'to zram ...'
        fi
        mount "$mount_id" /local_root
        mkdir -p "/zram_root$mount_path"
        cp -a /local_root/. "/zram_root$mount_path"
        umount /local_root
    done

    # modify /etc/fstab:
    if [ -f /zram_root/etc/fstab ]; then
        for mount in $mounts_zram; do
            mount_path="${mount#*:}"
            sed -Ei "s|^(\s*[^\s]+\s+${mount_path}\s+.*)$|#\1|g;" \
                /zram_root/etc/fstab
        done
        for mount in $mounts_null; do
            mount_path="${mount#*:}"
            sed -Ei -e "s|^(\s*[^\s]+\s+${mount_path}\s+.*)$|#\1|g;" \
                -e "s|^(\s*${mount_path}/[^\s]+\s+.*)$|#\1|g;" \
                /zram_root/etc/fstab
        done
    fi

    # copy /etc/ramroot.z files:
    if [ -d /zram_root/etc/ramroot.z ]; then
        cp -a --remove-destination /zram_root/etc/ramroot.z/. /zram_root
    fi
    # copy /home/<user>/.ramroot.z files:
    for dir_home in /zram_root/home/*; do
    if [ -d "$dir_home/.ramroot.z" ]; then
        cp -a --remove-destination "$dir_home/.ramroot.z/." "$dir_home"
    fi; done
    if [ "$flag_quiet" = true ]; then
        printf "\\033[H\\033[2J\\033[0;30m\\033[?1c\n" > \
            /zram_root/etc/issue
    fi

    # unmount zram device:
    umount /zram_root

    # set new mount_handler:
    zram_mount() {
        mount "$zram_device" "$1"
    }
    fsck_root() {
        :
    }
    mount_handler=zram_mount
    export zram_device
}
