#!/bin/bash
# Lux Wine wrapper for RunImage container

shopt -s extglob

RED='\033[1;91m'
BLUE='\033[1;94m'
GREEN='\033[1;92m'
YELLOW='\033[1;33m'
RESETCOLOR='\033[1;00m'

# YC_S3="https://storage.yandexcloud.net"
GIT_REPO='https://github.com/VHSgunzo'
GIT_HF_REPO='https://huggingface.co/spaces/lux-wine'
# GIT_YC_REPO="$YC_S3/lux-wine"
LW_DIR="$HOME/.local/share/LuxWine"
MENU_APPS_DIR="$HOME/.local/share/applications"
LW_APPS_DIR="$MENU_APPS_DIR/LuxWineApps"
LW_CFG="$LW_DIR/luwine.wcfg"
TMP_LW_CFG="$LW_DIR/tmp/luwine.wcfg"
LWBIN_DIR="$LW_DIR/bin"
LWSRC="$LWBIN_DIR/lux-wine"
GIT_RAW='https://raw.githubusercontent.com/VHSgunzo/lux-wine/main'
GIT_LWSRC="$GIT_RAW/lux-wine"
GIT_HF_LWSRC="$GIT_HF_REPO/git/resolve/main/lux-wine"
# GIT_YC_LWSRC="$GIT_YC_REPO/git/lux-wine"
GIT_LWZIP="$GIT_REPO/lux-wine/archive/refs/heads/main.zip"
GIT_HF_LWZIP="$GIT_HF_REPO/git/resolve/main/main.zip"
# GIT_YC_LWZIP="$GIT_YC_REPO/main.zip"
GIT_LWRAP="$GIT_RAW/lwrap/lwrap"
GIT_HF_LWRAP="$GIT_HF_REPO/git/resolve/main/lwrap/lwrap"
# GIT_YC_LWRAP="$GIT_YC_REPO/git/lwrap/lwrap"
GIT_LWRUN="$GIT_REPO/lwrun/releases"
GIT_HF_LWRUN="${GIT_HF_REPO//\/spaces/}/lwrun/resolve/main/releases"
# YC_LWRUN="$YC_S3/lwrun"
HOME_ICONS="$HOME/.local/share/icons"
HOME_DESK_DIRS="$HOME/.local/share/desktop-directories"
HSTEAM_DESKF="$MENU_APPS_DIR/steam-lw.desktop"
RSTEAM_DESKF="$RUNROOTFS/usr/share/applications/steam.desktop"
F_RC="$HOME/.config/fish/config.fish"
B_RC="$HOME/.bashrc"
Z_RC="$HOME/.zshrc"
HBIN_DIR="$HOME/.local/bin"
LWRUN_LN="$HBIN_DIR/lwrun"
LWRAP_LN="$HBIN_DIR/lwrap"
LWRAP="$LWBIN_DIR/lwrap"
LWBASH="$LWBIN_DIR/bash"
LWRUN="$LWBIN_DIR/lwrun"
RUNIMAGE_LW="$LWBIN_DIR/runimage-lw"
LWRAP_DIR='/opt/lwrap'
LWRUNTIME="$LWRAP_DIR/runtime.tar.zst"
HLWDIRLN="$HOME/LuxWine"
LW_DEF_TMP="$LW_DIR/tmp"
LWRPIDFL="$LW_DEF_TMP/lwrpid"
LWEXEC="$LWBIN_DIR/lwexec"
HICOLOR_SIZES=(
    "512x512" "256x256" "192x192" "128x128"
    "96x96" "80x80" "72x72" "64x64" "48x48"
    "32x32" "24x24" "16x16"
)
LW_MIMETYPES=(
    'application/x-ms-dos-executable' 'application/x-wine-extension-msp'
    'application/x-msi' 'application/x-msdos-program' 'text/win-bat'
    'application/x-ms-shortcut' 'text/x-ms-regedit'
)

if [[ -n "$RUNSRC" && -d "$RUNROOTFS" ]] && \
   [[ -x "$LWRAP" && "$NO_EXT_LWRAP" != 1 ]]
    then
        NO_EXT_LWRAP=1 "$LWRAP" "$@"
        exit $?
fi
unset NO_EXT_LWRAP

CFG_CHK_UPDATE="$(grep '^CHK_UPDATE=.*$' "$LW_CFG" 2>/dev/null)"
[ -n "$CFG_CHK_UPDATE" ] && \
eval "$CFG_CHK_UPDATE"||\
CHK_UPDATE='3'

[ ! -n "$(tty|grep -v 'not a'|grep -Eo 'tty|pts')" ] && \
    NOT_TERM=1||NOT_TERM=0

error_msg() {
    echo -e "${RED}[ ERROR ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR"
    if [ "$NOT_TERM" == 1 ]
        then notify-send -a 'Lux Wine Error' "$@" 2>/dev/null &
    fi
}

info_msg() {
    if [ "$QUIET_MODE" != 1 ]
        then
            echo -e "${GREEN}[ INFO ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR"
            if [[ "$NOT_TERM" == 1 && "$NO_NOTIFY" != 1 ]]
                then notify-send -a 'Lux Wine Info' "$@" 2>/dev/null &
            fi
    fi
}

warn_msg() {
    if [ "$QUIET_MODE" != 1 ]
        then
            echo -e "${YELLOW}[ WARNING ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR"
            if [[ "$NOT_TERM" == 1 && "$NO_NOTIFY" != 1 ]]
                then notify-send -a 'Lux Wine Warning' "$@" 2>/dev/null &
            fi
    fi
}

check_path() {
    if [ "$1" == "$F_RC" ]
        then grep -om1 '^set -U fish_user_paths "$HOME/.local/bin"' "$1" &>/dev/null
        else grep -om1 '^export PATH=.*/.local/bin' "$1" &>/dev/null
    fi
}

add_path() {
    if [ "$1" == "$F_RC" ]
        then check_path "$1"||(mkdir -p "$(dirname "$1")" && echo -e '\nset -U fish_user_paths "$HOME/.local/bin"' >> "$1")
        else check_path "$1"||echo -e '\nexport PATH="$HOME/.local/bin:$PATH"' >> "$1"
    fi
}

ln_lwrap() { [[ -x "$LWRAP" && -x "$LWRAP_LN" ]]||(mkdir -p "$HBIN_DIR" && ln -sfr "$LWRAP" "$LWRAP_LN") ; }

make_install() {
    if [ "$1" == "force" ]
        then QUIET_MODE=1 uninstall_lw force
        else QUIET_MODE=1 uninstall_lw update
    fi
    [ -f 'lux-wine' ] && \
        local lwf='lux-wine'||\
        local lwf='bin/lux-wine'
    install -Dm755 "$lwf" "$LWSRC"
    if is_not_pts_home
        then
            grep -m1 '^Exec=".*"' -lr ./*|\
            xargs -d'\n' sed -i "s|^Exec=\".*\"|Exec=\"$LWRAP\"|g" 2>/dev/null
            if [ -f 'lwrap' ]
                then local lwrapf='lwrap'
            elif [ -f 'bin/lwrap' ]
                then local lwrapf='bin/lwrap'
            else local lwrapf='lwrap/lwrap'
            fi
            if [ -f 'lwexec' ]
                then local lwexecf='lwexec'
            elif [ -f 'bin/lwexec' ]
                then local lwexecf='bin/lwexec'
            else local lwexecf='lwrap/lwexec'
            fi
            if [ -x "$RUNSTATIC/bash" ]
                then
                    sed -i "1 s|^.*$|#!$LWBASH|" "$lwrapf"
                    sed -i "1 s|^.*$|#!$LWBASH|" "$lwexecf"
                    install -Dm755 "$RUNSTATIC/bash" "$LWBASH"
            fi
            install -Dm755 "$lwrapf" "$LWRAP"
            ln_lwrap
            install -Dm755 "$lwexecf" "$LWEXEC"
            install -Dm644 LuxWine.menu "$HOME/.config/menus/applications-merged/LuxWine.menu"
            if [ "$KDE_SESSION_VERSION" == 6 ]
                then install -Dm755 LuxWineService.desktop "$HOME/.local/share/kio/servicemenus/LuxWineService.desktop"
            elif [ "$KDE_SESSION_VERSION" == 5 ]
                then install -Dm755 LuxWineService.desktop "$HOME/.local/share/kservices5/ServiceMenus/LuxWineService.desktop"
            fi
            mkdir -p "$MENU_APPS_DIR"
            mkdir -p "$HOME_DESK_DIRS"
            cp -rf mime "$HOME/.local/share/mime"
            cp -rf applications "$MENU_APPS_DIR/LuxWine"
            cp -rf directories/* "$HOME_DESK_DIRS/"
            if [[ -d "$RUNROOTFS" && -f "$RSTEAM_DESKF" ]]
                then
                    cp -rf "$RSTEAM_DESKF" "$HSTEAM_DESKF"
                    sed -i "s|^Exec.*steam-runtime|Exec='$HBIN_DIR/steam-runtime'|g" "$HSTEAM_DESKF"
                    sed -i "s|^Name=Steam (Runtime)|Name=Steam (RunImage LW)|g" "$HSTEAM_DESKF"
                    HICNSTM="$HOME_ICONS/steam.png"
                    for hi_icon_size in ${HICOLOR_SIZES[@]}
                        do
                            HICONS_DIR="$HOME_ICONS/hicolor/$hi_icon_size/apps"
                            RSTEAM_ICON="$RUNROOTFS/usr/share/icons/hicolor/$hi_icon_size/apps/steam.png"
                            HSTEAM_ICON="$HICONS_DIR/steam.png"
                            if [[ -f "$RSTEAM_ICON" && ! -f "$HSTEAM_ICON" ]]
                                then
                                    mkdir -p "$HICONS_DIR"
                                    [ -L "$HSTEAM_ICON" ] && \
                                        rm -f "$HSTEAM_ICON"
                                    cp -rf "$RSTEAM_ICON" "$HSTEAM_ICON"
                            fi
                            if [[ -f "$RSTEAM_ICON" && ! -f "$HICNSTM" ]]
                                then
                                    mkdir -p "$HOME_ICONS"
                                    [ -L "$HICNSTM" ] && \
                                        rm -f "$HICNSTM"
                                    cp -rf "$RSTEAM_ICON" "$HICNSTM"
                            fi
                    done
            fi
            [ "$ENABLE_HOSTEXEC" == 1 ] && \
                local INSTALL_SHELL="$(hostexec echo '$SHELL')"||\
                local INSTALL_SHELL="$SHELL"
            case "$(basename "$INSTALL_SHELL")" in
                zsh) add_path "$Z_RC" ;;
                bash) add_path "$B_RC" ;;
                fish) add_path "$F_RC" ;;
            esac
            update-desktop-database -q "$MENU_APPS_DIR" &>/dev/null
            update-mime-database "$HOME/.local/share/mime" &>/dev/null
            for mimetype in "${LW_MIMETYPES[@]}"
                do xdg-mime default LuxWine.desktop "$mimetype" &>/dev/null
            done
    fi
    cp -rf registry_patch "$LW_DIR/"
    cp -rf LICENSE "$LW_DIR/"
    cp -rf themes "$LW_DIR/"
    cp -rf icons "$LW_DIR/"
    cp -rf gif "$LW_DIR/"
    cp -rf db "$LW_DIR/"
    if [ -f "$LWRUNTIME" ]
        then
            tar -xf "$LWRUNTIME" -C "$LW_DIR" && \
            [[ ! -f "$LW_CFG" && -f "$TMP_LW_CFG" ]] && \
                cp -f "$TMP_LW_CFG" "$LW_CFG"
    fi
    grep "$LWRUN_LN" -lr "$MENU_APPS_DIR"|\
    xargs -d'\n' sed -i "s|$LWRUN_LN|$LWRAP|g" 2>/dev/null
    grep "$LWRUN" -lr "$MENU_APPS_DIR"|\
    xargs -d'\n' sed -i "s|$LWRUN|$LWRAP|g" 2>/dev/null
}

mv_lwrun() {
    if [ -w "$1" ]
        then mv -f "$1" "$2"
        else [ -L "$2" ] && rm -f "$2"
            cp -f "$1" "$2"
    fi
}

is_not_pts_home() {
    [[ "$SANDBOX_HOME" != 1 && "$SANDBOX_HOME_DL" != 1 && ! -d "$SANDBOXHOMEDIR/lwrap" && \
    "$PORTABLE_HOME" != 1 && "$TMP_HOME" != 1 && "$TMP_HOME_DL" != 1 && ! -d "$PORTABLEHOMEDIR/lwrap" ]]
}

try_install_lwrun() {
    finalize_install() {
        chmod u+x "$LWRUN"
        ln_lwrun
        export LWRUN_INSTALLED=1
        info_msg "lwrun installed!"
        if [ ! -n "$TMP_LWRUN" ] && \
            is_net_conn
            then
                update_lwrap
                "$LWRAP" --install
        fi
        try_shutdown_lw && \
        return 0||return 1
    }
    if is_not_pts_home
        then
            REALP_LWRUN="$(readrealpath "$LWRUN")"
            if [[ "$RUNSRC" =~ "lwrun" && -f "$RUNSRCRPTH" && \
                "$RUNSRCRPTH" != "$LWRUN" && ! "$RUNSRCRPTH" =~ "Run" && \
                "$LWRUN_INSTALLED" != 1 ]]
                then
                    info_msg "Installing lwrun..."
                    mkdir -p "$LWBIN_DIR"
                    if mv_lwrun "$RUNSRCRPTH" "$LWRUN"
                        then finalize_install
                        else
                            error_msg "Failed to install lwrun!"
                            is_lwrun && \
                            return 1||exit 1
                    fi
            elif [[ "$RUNSRCRPTH" =~ "Run" && "$RUNSRCRPTH" != "$REALP_LWRUN" ]]
                then
                    mkdir -p "$LWBIN_DIR"
                    ln -sf "$RUNSRCRPTH" "$LWRUN"
                    ln_lwrun
                    return 0
            elif [[ ! -n "$TMP_LWRUN" && "$LWRUN_PKG" == 1 && \
                "$LWRUN_INSTALLED" != 1 ]]
                then finalize_install
            fi
    fi
}

ln_lwrun() {
    if is_lwrun
        then
            mkdir -p "$HBIN_DIR"
            REALP_LWRUN="$(readrealpath "$LWRUN")"
            if [ "$(readrealpath "$LWRUN_LN")" != "$REALP_LWRUN" ]
                then
                    info_msg "Update lwrun link..."
                    ln -sfr "$LWRUN" "$LWRUN_LN"
            fi
            for steam in {steam,steam-runtime,steam-native}
                do
                    if [ ! -f "$HBIN_DIR/$steam" ]
                        then
                            info_msg "Update $steam link..."
                            ln -sfr "$LWRUN" "$HBIN_DIR/$steam"
                    fi
            done
            if [ "$(readrealpath "$RUNIMAGE_LW")" != "$REALP_LWRUN" ]
                then
                    info_msg "Update runimage link..."
                    mkdir -p "$LWBIN_DIR"
                    ln -sfr "$LWRUN" "$RUNIMAGE_LW"
                    ln -sfr "$LWRUN" "$HBIN_DIR/runimage-lw"
            fi
    fi
}

uninstall_lw() {
    if [ "$1" == "force" ] || is_lw || is_lwrun
        then
            info_msg "Removing Lux Wine..."
            rm -rf "$HSTEAM_DESKF"
            rm -rf "$MENU_APPS_DIR/LuxWine"
            rm -rf "$HOME_DESK_DIRS/LuxWine"*
            rm -rf "$HOME/.config/menus/applications-merged/LuxWine.menu"
            rm -rf "$HOME/.local/share/kservices5/ServiceMenus/LuxWine"*
            rm -rf "$HOME/.local/share/kio/servicemenus/LuxWine"*
            if [ "$1" == "update" ]
                then
                    rm -rf "$LWSRC"
                    rm -rf "$LWRAP"
                    rm -rf "$LWBASH"
                    rm -rf "$LW_DIR/db"
                    rm -rf "$LW_DIR/gif"
                    rm -rf "$LW_DIR/icons"
                    rm -rf "$LW_DIR/themes"
                    rm -rf "$LW_DIR/LICENSE"
                    rm -rf "$LW_DIR/.lwcfgchksum"
                    rm -rf "$LW_DIR/registry_patch"
                else
                    rm -rf "$LW_DIR"
                    rm -rf "$HLWDIRLN"
                    rm -rf "$LWRUN_LN"
                    rm -rf "$LWRAP_LN"
                    rm -rf "$HBIN_DIR/runimage-lw"
                    rm -rf "$MENU_APPS_DIR/LuxWine"*
                    rm -rf "$HOME/Desktop/LuxWine.desktop"
                    rm_broken_link "$HBIN_DIR"
                    rm_broken_link "$HOME_ICONS"
            fi
    fi
    info_msg "Lux Wine removed!"
}

is_net_conn() {
    if is_exe_exist nc
        then nc -zw1 github.com 443 &>/dev/null
    elif is_exe_exist ping
        then ping -c 1 github.com &>/dev/null
    elif is_exe_exist curl
        then curl -Ifs github.com &>/dev/null
    elif is_exe_exist wget
        then wget -q --spider github.com &>/dev/null
    else return 1
    fi
}

exzip() {
    if is_exe_exist unzip
        then
            unzip "$1" -d "$2" &>/dev/null
    elif is_exe_exist 7z
        then
            7z x "$1" -o"$2" &>/dev/null
    elif is_exe_exist bsdtar
        then
            mkdir -p "$2"
            bsdtar -x -f "$1" -C "$2" &>/dev/null
    else
        error_msg "zip archivator not found!"
        exit 1
    fi
}

is_lw() { (is_not_pts_home && [[ -x "$LWSRC" && -x "$LWRAP" ]])||[ -x "$LWSRC" ] ; }

is_lwrun() { [ -x "$LWRUN" ] ; }

try_dl_lwzip() {
    local lwzipurl=(
#         "$GIT_YC_LWZIP"
        "$GIT_HF_LWZIP"
        "$GIT_LWZIP"
    )
    for url in "${lwzipurl[@]}"
        do
            try_dl "$url" "$TMP_LW.zip" && \
                return 0
    done
    return 1
}

install_lw() {
    install_local_lw() {
        if [ -d "/opt/lwrap" ]
            then
                info_msg "Installing Lux Wine from container..."
                (mkdir -p "$TMP_LW" && \
                cp -rf "/opt/lwrap"/!(runtime.tar.zst|prefix_backups) "$TMP_LW" && \
                cd "$TMP_LW" && \
                make_install "$1"
                rm_tmplw)
        fi
    }
    rm_tmplw() { [[ -d "$TMP_LW" || -f "$TMP_LW.zip" ]] && rm -rf "$TMP_LW"* ; }
    TMP_LW="/tmp/lux-wine.$RANDOM"
    if [ "$1" != "local" ] && \
        is_net_conn
        then
            info_msg "Installing Lux Wine..."
            if try_dl_lwzip
                then
                    (exzip "$TMP_LW.zip" "$TMP_LW" && \
                    cd "$TMP_LW/lux-wine-main" && \
                    make_install "$1"
                    rm_tmplw)
                else install_local_lw "$1"
            fi
        else install_local_lw "$1"
    fi
    if is_lw
        then info_msg "Lux Wine installed!"
        else
            error_msg "Failed to install Lux Wine!"
            exit 1
    fi
}

vers_parser() { grep -Po '\d+'|sed ':a;/$/N;s/\n//;ta' ; }

set_git_lw_version() {
    unset GIT_LW_VERSION
    local lwsrcusrls=(
#         "$GIT_YC_LWSRC"
        "$GIT_HF_LWSRC"
        "$GIT_LWSRC"
    )
    for url in "${lwsrcusrls[@]}"
        do
            GIT_LW_VERSION="$(NO_ARIA2C=1 NO_DL_GUI=1 NO_DL_REPEAT=1 \
            try_dl "$url" /dev/stdout 2>/dev/null|get_lw_version)"
            [ -n "$GIT_LW_VERSION" ] && return 0
    done
    return 1
}

get_lw_version() {
    if [ -n "$1" ]
        then grep -m1 'LW_VERSION' "$1" 2>/dev/null|vers_parser
        else grep -m1 'LW_VERSION'|vers_parser
    fi
}

try_dllwrap_mirror() {
    local lwrapurl=(
#         "$GIT_YC_LWRAP"
        "$GIT_HF_LWRAP"
        "$GIT_LWRAP"
    )
    for url in "${lwrapurl[@]}"
        do
            try_dl "$url" "$TMP_LWRAP" && \
                return 0
    done
    return 1
}

update_lwrap() {
    info_msg "Update lwrap..."
    TMP_LWRAP="${LWRAP}.new$BASHPID"
    if try_dllwrap_mirror
        then
            mv -f "$TMP_LWRAP" "$LWRAP"
            chmod +x "$LWRAP"
            ln_lwrap
        else
            error_msg "Failed to get lwrap!"
            return 1
    fi
}

update_lw() {
    if is_lw
        then
            info_msg "Checking the Lux Wine update..."
            set_git_lw_version
            LW_VERSION="$(get_lw_version "$LWSRC")"
            if [[ -n "$GIT_LW_VERSION" && -n "$LW_VERSION" ]]
                then
                    if [ "$LW_VERSION" != "$GIT_LW_VERSION" ]
                        then
                            if is_update "Lux Wine"
                                then
                                    info_msg "Lux Wine update..."
                                    if update_lwrap
                                        then "$LWRAP" --install||\
                                                exit 1
                                        else exit 1
                                    fi
                            fi
                        else
                            info_msg "The latest version is already installed!"
                            touch "$LWSRC"
                    fi
                else
                    error_msg "Failed to check for updates!"
                    return 1
            fi
        else
            error_msg "Lux Wine is not installed!"
            exit 1
    fi
}

get_lwrun_git_ver() {
    NO_ARIA2C=1 NO_DL_GUI=1 NO_DL_REPEAT=1 try_dl "$GIT_LWRUN/latest" \
        /dev/stdout 2>/dev/null|grep -m1 "Release v.*"|awk '{print$2}'
}

get_lwrun_hf_ver() {
    NO_ARIA2C=1 NO_DL_GUI=1 NO_DL_REPEAT=1 try_dl \
        "${GIT_HF_LWRUN/resolve/tree}" /dev/stdout \
        2>/dev/null|grep -Po "v\d+\.\d+\.\d+"|tail -1
}

# get_lwrun_yc_ver() {
#     NO_ARIA2C=1 NO_DL_GUI=1 NO_DL_REPEAT=1 try_dl \
#         "$YC_LWRUN" /dev/stdout 2>/dev/null|tr '<' '\n'|\
#         grep '^Key>'|sed 's|^Key>||g'|grep '^releases'|\
#         awk -F/ 'END {print$2}'
# }

set_git_lwrun_ver() {
#     for src in yc git hf
    for src in git hf
        do
            GIT_LWRUN_VERSION="$(get_lwrun_${src}_ver)"
            [ -n "$GIT_LWRUN_VERSION" ] && return 0
    done
    return 1
}

try_dllwrun_mirror() {
    local lwrunurl=(
#         "$YC_LWRUN/releases/$GIT_LWRUN_VERSION/lwrun"
        "$GIT_HF_LWRUN/$GIT_LWRUN_VERSION/lwrun"
        "$GIT_LWRUN/download/$GIT_LWRUN_VERSION/lwrun"
    )
    for url in "${lwrunurl[@]}"
        do
            try_dl "$url" "$TMP_LWRUN" && \
                return 0
    done
    return 1
}

try_dl_lwrun() {
    TMP_LWRUN="$LWRUN.new$BASHPID"
    info_msg "Downloading lwrun..."
    set_git_lwrun_ver
    if [ -n "$GIT_LWRUN_VERSION" ] && \
        try_dllwrun_mirror
       then
            info_msg "lwrun downloaded!"
            RUNSRCRPTH="$TMP_LWRUN" \
            RUNSRC="lwrun" try_install_lwrun &&
            return 0||return 1
        else
            error_msg "Failed to download lwrun!"
            [ -f "$TMP_LWRUN" ] && \
                rm -rf "$TMP_LWRUN"*
            exit 1
    fi
}

runimage_lw() {
    [ "$NOT_TERM" != 1 ] && \
        unset HOSTEXEC_IN_TERM||\
        HOSTEXEC_IN_TERM=(
            "xterm" "-fa" "Monospace"
            "-fs" "11" "-geometry" "130x45"
            "-bg" "black" "-fg" "white" \
            "-T" "Updating RunImage packages..." "-e"
        )
    if [ "$ENABLE_HOSTEXEC" == 1 ]
        then "${HOSTEXEC_IN_TERM[@]}" hostexec ptyspawn importenv '$RUNPID' \
                env DONT_NOTIFY=1 NO_RPIDSMON=1 "$RUNIMAGE_LW" "$@"
        else "$RUNIMAGE_LW" "$@"
    fi
}

yn_case() {
    while true
        do
            read -p "$(echo -e "${RED}$1 ${GREEN}(y/n) ${BLUE}> $RESETCOLOR")" yn
            case $yn in
                [Yy] ) return 0 ;;
                [Nn] ) return 1 ;;
            esac
    done
}

gui_question() {
    if is_exe_exist yad
        then yad --image="dialog-question" --button="NO:1" --button="YES:0" --title="$1" \
                --text="$2" --center --on-top --fixed --selectable-labels
    elif is_exe_exist zenity
        then zenity --question --title="$1" --no-wrap --text="$2"
    else return 1
    fi
    return $?
}

is_update() {
    [ "$FORCE_UPDATE" == 1 ] && \
        return 0
    local IS_UPD_TITLE="Update ${1}..."
    [ -n "$2" ] && \
        local IS_UPD_TEXT="$2"||\
        local IS_UPD_TEXT="$1 update is available!\nDo you want to update now?"
    if [ "$NOT_TERM" != 1 ]
        then yn_case "$IS_UPD_TEXT"||return 1
        else gui_question "$IS_UPD_TITLE" "$IS_UPD_TEXT"||return 1
    fi
    return $?
}

try_shutdown_lw() {
    if [ -n "$(pgrep -fa lux-wine|grep -om1 'LuxWine/bin')" ]
        then
            if [ "$FORCE_UPDATE" != 1 ]
                then
                    local qtext="You need to restart Lux Wine!\nDo you want to turn it off now?"
                    if [ "$NOT_TERM" != 1 ]
                        then yn_case "$qtext"
                        else gui_question "Restart Lux Wine..." "$qtext"
                    fi
            fi
            if [ "$?" == 0 ]
                then
                    info_msg "Shutdown Lux Wine..."
                    if [ -x "$LWSRC" ]
                        then "$LWSRC" -exit
                        else return 1
                    fi
                else return 1
            fi
    fi
    return 0
}

no_color() { sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2};?)?)?[mGK]//g" ; }

update_runimage() {
    if is_update "RunImage" "Do you want to check updates for RunImage packages?"
        then
            if (runimage_lw --rU && try_shutdown_lw)
                then return 0
                else return 1
            fi
        else
            touch "$LWRUN"
            return 1
    fi
}

lwrap_init() {
    if [ "$ENABLE_HOSTEXEC" == 1 ]
        then hostexec ptyspawn importenv '$RUNPID' "$LWRAP" -init
        else "$LWRAP" -init
    fi
}

update_lwrun() {
    if is_lwrun
        then
            local ret=1
            info_msg "Checking the lwrun update..."
            if [ "$NO_RUNPKG_UPDATE" != 1 ]
                then
                    update_runimage
                    ret=$?
                    [ "$ret" == 0 ] && \
                        lwrap_init
            fi
            return $ret
        else
            error_msg "lwrun is not installed!"
            exit 1
    fi
}

is_exe_exist() { command -v "$@" &>/dev/null ; }

which_exe() { command -v "$@" ; }

check_url_stat_code() {
    set -o pipefail
    if is_exe_exist curl
        then curl -sL -o /dev/null -I -w "%{http_code}" "$@" 2>/dev/null
    elif is_exe_exist wget
        then wget --no-check-certificate --server-response \
                --spider "$@"|& awk '/^  HTTP/{print$2}'|tail -1
    else return 1
    fi
}

is_url() {
    [ ! -n "$1" ] && \
        return 1
    if [ -n "$2" ]
        then [ "$(check_url_stat_code "$1")" == "$2" ]
        else [ "$(check_url_stat_code "$1")" == "200" ]
    fi
}

try_dl() {
    err_no_downloader() {
        error_msg "Downloader not found!"
        exit 1
    }
    rm_fail_dl() {
        [ -f "$FILEDIR/$FILENAME" ] && \
            rm -rf "$FILEDIR/$FILENAME" \
            "$FILEDIR/$FILENAME"*.aria2
    }
    dl_ret() {
        if [ "$1" != 0 ]
            then
                rm_fail_dl
                dl_repeat && \
                try_dl "$URL" "$FILEDIR/$FILENAME"||\
                return 1
            else return 0
        fi
    }
    dl_repeat() {
        [ "$NO_DL_REPEAT" == 1 ] && \
            return 1
        DL_REP_TITLE="Download interrupted!"
        DL_REP_TEXT="Failed to download: $FILENAME from $(echo "$URL"|awk -F/ '{print$3"/"$4}') \nWould you like to repeat it?"
        if [[ "$NOT_TERM" != 1 || "$NO_DL_GUI" == 1 ]]
            then
                yn_case "$DL_REP_TEXT"||return 1
        elif is_exe_exist yad
            then
                yad --image="dialog-error" --button="CANCEL:1" --center \
                    --button="REPEAT:0" --title="$DL_REP_TITLE" \
                    --text="$DL_REP_TEXT" --on-top --fixed
        elif is_exe_exist zenity
            then
                zenity --question --title="$DL_REP_TITLE" --no-wrap \
                    --text="$DL_REP_TEXT"
        else return 1
        fi
    }
    if [ -n "$1" ]
        then
            URL="$1"
            if [ -n "$2" ]
                then
                    if [ -d "$2" ]
                        then
                            FILEDIR="$2"
                            FILENAME="$(basename "$1")"
                        else
                            FILEDIR="$(dirname "$2")"
                            FILENAME="$(basename "$2")"
                    fi
                else
                    FILEDIR="."
                    FILENAME="$(basename "$1")"
            fi
            if is_url "$URL"
                then
                    WGET_ARGS=(--no-check-certificate -t 3 -T 5 -w 0.5 "$URL" -O "$FILEDIR/$FILENAME")
                    [ ! -d "$FILEDIR" ] && \
                        mkdir -p "$FILEDIR"
                    if [[ "$NOT_TERM" == 1 && "$NO_DL_GUI" != 1 ]] && \
                        (is_exe_exist yad||is_exe_exist zenity)
                        then
                            set -o pipefail
                            dl_progress() {
                                [[ "$URL" =~ '&key=' ]] && \
                                    local URL="$(echo "$URL"|sed "s|\&key=.*||g")"
                                [[ "$URL" =~ '&' && ! "$URL" =~ '&amp;' ]] && \
                                    local URL="$(echo "$URL"|sed "s|\&|\&amp;|g")"
                                if is_exe_exist yad
                                    then
                                        yad --progress --percentage=0 --text="Download:\t$FILENAME\n$URL" \
                                            --auto-close --no-escape --selectable-labels --auto-kill \
                                            --center --on-top --fixed --no-buttons --undecorated --skip-taskbar
                                elif is_exe_exist zenity
                                    then
                                        zenity --progress --text="Connecting to $URL" --width=650 --height=40 \
                                            --auto-close --no-cancel --title="Download: $FILENAME"
                                else return 1
                                fi
                            }
                            dl_progress_pulsate() {
                                local ret=1
                                [[ "$URL" =~ '&key=' ]] && \
                                    local URL="$(echo "$URL"|sed "s|\&key=.*||g")"
                                [[ "$URL" =~ '&' && ! "$URL" =~ '&amp;' ]] && \
                                    local URL="$(echo "$URL"|sed "s|\&|\&amp;|g")"
                                if is_exe_exist yad
                                    then
                                        local yad_args=(
                                            --progress --pulsate --text="Download:\t$FILENAME\n$URL"
                                            --width=650 --height=40 --undecorated --skip-taskbar
                                            --no-buttons --text-align center --auto-close --auto-kill
                                            --center --fixed --on-top --no-escape --selectable-labels
                                        )
                                        "$@" &
                                        local exec_pid="$!"
                                        if [[ -n "$exec_pid" && -d "/proc/$exec_pid" ]]
                                            then
                                                (while [ -d "/proc/$exec_pid" ]
                                                    do echo -e "#\n" ; sleep 0.1 2>/dev/null
                                                done)|yad "${yad_args[@]}" &>/dev/null &
                                                local yad_pid="$!"
                                                wait "$exec_pid" &>/dev/null
                                                ret="$?"
                                                kill "$yad_pid" &>/dev/null
                                        fi
                                elif is_exe_exist zenity
                                    then
                                        "$@"|zenity --progress --pulsate --text="$URL" --width=650 --height=40 \
                                            --auto-close --no-cancel --title="Download: $FILENAME"
                                        ret="$?"
                                fi
                                return "$ret"
                            }
                            if [ "$NO_ARIA2C" != 1 ] && \
                                is_exe_exist aria2c
                                then
                                    aria2c --no-conf -R -x 13 -s 13 --allow-overwrite --summary-interval=1 -o \
                                        "$FILENAME" -d "$FILEDIR" "$URL"|grep --line-buffered 'ETA'|\
                                        sed -u 's|(.*)| &|g;s|(||g;s|)||g;s|\[||g;s|\]||g'|\
                                        awk '{print$3"\n#Downloading at "$3,$2,$5,$6;system("")}'|\
                                    dl_progress
                            elif is_exe_exist curl
                                then
                                    curl -R --progress-bar --insecure --fail -L "$URL" -o \
                                        "$FILEDIR/$FILENAME" |& tr '\r' '\n'|sed '0,/100/{/100/d;}'|\
                                        sed -ur 's|[# ]+||g;s|.*=.*||g;s|.*|#Downloading at &\n&|g'|\
                                    dl_progress
                            elif is_exe_exist wget2
                                then
                                    dl_progress_pulsate wget2 "${WGET_ARGS[@]}"
                            elif is_exe_exist wget
                                then
                                    wget "${WGET_ARGS[@]}"|& tr '\r' '\n'|\
                                        sed -u 's/.* \([0-9]\+%\)\ \+\([0-9,.]\+.\) \(.*\)/\1\n#Downloading at \1\ ETA: \3/; s/^20[0-9][0-9].*/#Done./'|\
                                    dl_progress
                            else
                                err_no_downloader
                            fi
                            dl_ret "${PIPESTATUS[0]}"||return 1
                        else
                            if [ "$NO_ARIA2C" != 1 ] && is_exe_exist aria2c
                                then
                                    aria2c --no-conf -R -x 13 -s 13 --allow-overwrite -d "$FILEDIR" -o "$FILENAME" "$URL"
                            elif is_exe_exist curl
                                then
                                    curl -R --progress-bar --insecure --fail -L "$URL" -o "$FILEDIR/$FILENAME"
                            elif is_exe_exist wget2
                                then
                                    wget2 -q --force-progress "${WGET_ARGS[@]}"
                            elif is_exe_exist wget
                                then
                                    wget -q --show-progress "${WGET_ARGS[@]}"
                            else
                                err_no_downloader
                            fi
                            dl_ret "$?"||return 1
                    fi
                else
                    error_msg "$FILENAME not found in $(echo "$URL"|awk -F/ '{print$3"/"$4}')"
                    return 1
            fi
        else
            error_msg "Specify download URL!"
            return 1
    fi
}

try_set_lwrpid() { lwrpid="$(cat "$LWRPIDFL" 2>/dev/null)" ; }

rm_broken_link() { find -L "$1" -type l -exec rm -rf {} \; 2>/dev/null ; }

readrealpath() {
    if is_exe_exist readlink
        then readlink -f "$@" 2>/dev/null
    elif is_exe_exist realpath
        then realpath "$@" 2>/dev/null
    else return 1
    fi
}

print_help() {
    HLPHOSTNAME="$(uname -a|awk '{print$2}')"
    [[ "$RUNSRC" =~ "lwrun" ]] && \
        HLPEXENAME="lwrun"||\
        HLPEXENAME="lwrap"
    echo -e "
    ${RED}Usage:
        $RED┌──[$GREEN$RUNUSER$YELLOW@$BLUE${RUNHOSTNAME}$RED]─[$GREEN$PWD$RED]
        $RED└──╼ \$$GREEN $HLPEXENAME ${BLUE}{args}

        ${BLUE}--lwrap-help $GREEN                   Show this usage info
        ${BLUE}--install    $YELLOW{force|local}$GREEN      Re/Install Lux Wine and lwrun
        ${BLUE}--update     $GREEN                   Update Lux Wine, lwrun and container packages
        ${BLUE}--uninstall  $YELLOW{force|update}$GREEN     Install Lux Wine and lwrun
        "
}

RUNSRCRPTH="$(readrealpath "$RUNSRC")"

case "$1" in
    --lwrap-help) print_help
                  exit ;;
    --uninstall) uninstall_lw "$2"
                 exit $? ;;
    --install) try_install_lwrun
               is_lwrun||try_dl_lwrun
               install_lw "$2"
               exit $? ;;
    --update) FORCE_UPDATE=1
              update_lw
              update_lwrun
              exit $? ;;
esac

if [[ -n "$RUNSRC" && -d "$RUNROOTFS" ]]
    then
        try_install_lwrun
        is_lw||install_lw
        if [[ "$CHK_UPDATE" != 0 || "$FORCE_UPDATE" == 1 ]] && \
            is_net_conn
            then
                if [[ ! -x "$(find "$LWSRC" -mtime -$CHK_UPDATE \
                    -print 2>/dev/null)" || "$FORCE_UPDATE" == 1 ]]
                    then update_lw
                fi
                if is_not_pts_home && \
                   [[ ! -x "$(find "$LWRUN" -mtime -$CHK_UPDATE \
                    -print 2>/dev/null)" || "$FORCE_UPDATE" == 1 ]]
                    then update_lwrun && exit $?
                fi
        fi
        if [ "$LWRUN_INSTALLED" == 1 ]
            then "$LWSRC" -init
            else
                try_set_lwrpid
                if ! [[ -n "$lwrpid" && -f "/tmp/.bwinf.$lwrpid" && -d "/proc/$lwrpid" ]]
                    then
                        LWEXECFLDIR="/tmp/.lwexec.$RUNPID"
                        mkdir -p "$LW_DEF_TMP"
                        echo "$RUNPID" > "$LWRPIDFL" 2>/dev/null
                        (JOBNUMFL="$LWEXECFLDIR/job"
                        mkdir -p "$LWEXECFLDIR" 2>/dev/null
                        mkfifo "$JOBNUMFL" 2>/dev/null
                        unset jobnum
                        while [[ -d "/proc/$RUNPID" && -d "$LWEXECFLDIR" ]]
                            do
                                jobnum=$(( $jobnum + 1 ))
                                execjobdir="$LWEXECFLDIR/$jobnum"
                                execenvfl="$execjobdir/env"
                                execjobfl="$execjobdir/exec"
                                execjoboutfl="$execjobdir/out"
                                execjobstatfl="$execjobdir/stat"
                                mkdir "$execjobdir" 2>/dev/null
                                mkfifo "$execenvfl" 2>/dev/null
                                mkfifo "$execjobfl" 2>/dev/null
                                mkfifo "$execjoboutfl" 2>/dev/null
                                mkfifo "$execjobstatfl" 2>/dev/null
                                tee <<<"$jobnum" "$JOBNUMFL" &>/dev/null
                                if [ -e "$execjobfl" ]
                                    then
                                        (OLD_PATH="$PATH"
                                        OLD_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
                                        source "$execenvfl" && cd "$PWD"
                                        export PATH="$PATH:$OLD_PATH"
                                        export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$OLD_LD_LIBRARY_PATH"
                                        cat "$execjobfl" 2>/dev/null|"$RUNSTATIC/bash" &>"$execjoboutfl" &
                                        execjobpid=$!
                                        tee <<<"$execjobpid" "$execjobstatfl" &>/dev/null
                                        wait $execjobpid 2>/dev/null
                                        execstat=$?
                                        tee <<<"$execstat" "$execjobstatfl" &>/dev/null) &
                                fi
                        done) &
                fi
                "$LWSRC" "$@"
                [ -d "$LWEXECFLDIR" ] && \
                    rm -rf "$LWEXECFLDIR"
                [ -f "$LWRPIDFL" ] && \
                    rm -f "$LWRPIDFL"
        fi
    else
        try_set_lwrpid
        if [[ "$FORCE_UPDATE" != 1 && -x "$LWEXEC" && -x "$LWSRC" ]] && \
           [[ -n "$lwrpid" && -f "/tmp/.bwinf.$lwrpid" && -d "/proc/$lwrpid" ]]
            then
                LWEXECFLDIR="/tmp/.lwexec.$lwrpid" \
                NOT_TERM="$NOT_TERM" "$LWEXEC" "$LWSRC" "$@"
        elif [ -x "$LWRUN_LN" ]
            then "$LWRUN_LN" "$@"
        elif is_lwrun
            then "$LWRUN" "$@"
        elif [ -x "$(which_exe lwrun)" ]
            then "$(which_exe lwrun)" "$@"
        else
            if is_net_conn
                then
                    update_lwrap
                    try_dl_lwrun && \
                    "$LWRUN"
                else
                    error_msg "lwrun not found, download and install it first!"
                    exit 1
            fi
        fi
fi
exit $?
