#!/bin/bash

VERSION="0.2-retrodebian"
PATH=$PATH:/usr/sbin:/sbin
LC_ALL=C
LANG=C

USE_COLOR=1
SHOW_ASCII=1

ESC="$(printf '\033')"
C_RESET="${ESC}[0m"
C_BOLD="${ESC}[1m"
C_RED="${ESC}[31m"
C_BLUE="${ESC}[34m"
C_WHITE="${ESC}[37m"
C_GREEN="${ESC}[32m"
C_BGREEN="${ESC}[1;32m"
C_CYAN="${ESC}[36m"

if [ "$USE_COLOR" != "1" ]; then
    C_RESET=""
    C_BOLD=""
    C_RED=""
    C_BLUE=""
    C_WHITE=""
fi


trim() {
    echo "$1" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//'
}


strip_ansi() {
    echo "$1" | sed 's/'"$ESC"'\\[[0-9;]*m//g'
}


repeat_char() {
    ch="$1"
    count="$2"
    out=""

    while [ "$count" -gt 0 ] 2>/dev/null; do
        out="${out}${ch}"
        count="$(expr "$count" - 1)"
    done

    echo "$out"
}


get_term_cols() {
    TERM_COLS=80

    if type tput >/dev/null 2>&1; then
        cols="$(tput cols 2>/dev/null)"
        case "$cols" in
            ''|*[!0-9]*)
                ;;
            *)
                if [ "$cols" -gt 0 ] 2>/dev/null; then
                    TERM_COLS="$cols"
                    return
                fi
                ;;
        esac
    fi

    if type stty >/dev/null 2>&1; then
        cols="$(stty size 2>/dev/null | awk '{print $2}')"
        case "$cols" in
            ''|*[!0-9]*)
                ;;
            *)
                if [ "$cols" -gt 0 ] 2>/dev/null; then
                    TERM_COLS="$cols"
                    return
                fi
                ;;
        esac
    fi
}


get_user_host() {
    if [ -n "$USER" ]; then
        F_USER="$USER"
    else
        F_USER="$(id -un 2>/dev/null)"
    fi

    if [ -z "$F_USER" ]; then
        F_USER="user"
    fi

    F_HOST="$(hostname 2>/dev/null)"
    if [ -z "$F_HOST" ]; then
        F_HOST="host"
    fi

    F_TITLE="${C_RED}${C_BOLD}${F_USER}${C_RESET}@${C_RED}${C_BOLD}${F_HOST}${C_RESET}"
}


get_os() {
    F_OS="Linux"

    if [ -f /etc/debian_version ]; then
        debv="$(cat /etc/debian_version 2>/dev/null)"
        debv="$(trim "$debv")"

        if [ -f /etc/issue ]; then
            issue="$(head -n 1 /etc/issue 2>/dev/null)"
            issue="$(echo "$issue" | sed 's/\\n//g; s/\\l//g')"
            issue="$(trim "$issue")"

            case "$issue" in
                Debian*|Ubuntu*)
                    F_OS="$issue"
                    ;;
                *)
                    if [ -n "$debv" ]; then
                        F_OS="Debian GNU/Linux $debv"
                    else
                        F_OS="Debian GNU/Linux"
                    fi
                    ;;
            esac
        else
            if [ -n "$debv" ]; then
                F_OS="Debian GNU/Linux $debv"
            else
                F_OS="Debian GNU/Linux"
            fi
        fi
    fi

    arch="$(uname -m 2>/dev/null)"
    arch="$(trim "$arch")"
    if [ -n "$arch" ]; then
        F_OS="${F_OS} ${arch}"
    fi
}

get_host_model() {
    F_HOSTMODEL=""

    if [ -r /sys/devices/virtual/dmi/id/board_vendor ] || [ -r /sys/devices/virtual/dmi/id/board_name ]; then
        bv="$(cat /sys/devices/virtual/dmi/id/board_vendor 2>/dev/null)"
        bn="$(cat /sys/devices/virtual/dmi/id/board_name 2>/dev/null)"
        F_HOSTMODEL="$(trim "$bv $bn")"
    fi

    if [ -z "$F_HOSTMODEL" ] && [ -r /sys/devices/virtual/dmi/id/product_name ]; then
        pn="$(cat /sys/devices/virtual/dmi/id/product_name 2>/dev/null)"
        pv="$(cat /sys/devices/virtual/dmi/id/product_version 2>/dev/null)"
        F_HOSTMODEL="$(trim "$pn $pv")"
    fi
}


get_kernel() {
    ks="$(uname -s 2>/dev/null)"
    kr="$(uname -r 2>/dev/null)"
    F_KERNEL="$(trim "$ks $kr")"
}


get_uptime() {
    F_UPTIME=""

    if [ -r /proc/uptime ]; then
        secs="$(awk '{print int($1)}' /proc/uptime 2>/dev/null)"

        if [ -n "$secs" ]; then
            d="$(expr "$secs" / 86400)"
            h="$(expr \( "$secs" % 86400 \) / 3600)"
            m="$(expr \( "$secs" % 3600 \) / 60)"

            out=""

            if [ "$d" -gt 0 ] 2>/dev/null; then
                if [ "$d" -eq 1 ] 2>/dev/null; then
                    out="1 day"
                else
                    out="$d days"
                fi
            fi

            if [ "$h" -gt 0 ] 2>/dev/null; then
                if [ -n "$out" ]; then
                    out="${out}, "
                fi
                if [ "$h" -eq 1 ] 2>/dev/null; then
                    out="${out}1 hour"
                else
                    out="${out}${h} hours"
                fi
            fi

            if [ "$m" -gt 0 ] 2>/dev/null; then
                if [ -n "$out" ]; then
                    out="${out}, "
                fi
                out="${out}${m} min"
            fi

            if [ -z "$out" ]; then
                out="${secs} sec"
            fi

            F_UPTIME="$out"
        fi
    fi
}


get_packages() {
    F_PACKAGES=""

    if type dpkg-query >/dev/null 2>&1; then
        cnt="$(dpkg-query -W -f='x\n' 2>/dev/null | wc -l | awk '{print $1}')"
        cnt="$(trim "$cnt")"
        if [ -n "$cnt" ]; then
            F_PACKAGES="$cnt (dpkg)"
        fi
    fi
}


get_shell() {
    F_SHELL=""

    shn="$SHELL"
    if [ -z "$shn" ]; then
        shn="/bin/sh"
    fi

    base="$(basename "$shn" 2>/dev/null)"
    if [ -z "$base" ]; then
        base="sh"
    fi

    F_SHELL="$base"

    case "$base" in
        bash)
            if [ -n "$BASH_VERSION" ]; then
                bv="$(echo "$BASH_VERSION" | sed 's/-.*//')"
                F_SHELL="$base $bv"
            fi
            ;;
    esac
}


get_resolution() {
    F_RESOLUTION=""

    if [ -n "$DISPLAY" ]; then
        if type xrandr >/dev/null 2>&1; then
            F_RESOLUTION="$(xrandr 2>/dev/null | awk '
                / connected/ && /[0-9]+x[0-9]+/ {
                    for (i = 1; i <= NF; i++) {
                        if ($i ~ /[0-9]+x[0-9]+\+/) {
                            gsub(/\+.*/, "", $i)
                            print $i
                            exit
                        }
                    }
                }
            ')"
        fi

        if [ -z "$F_RESOLUTION" ] && type xdpyinfo >/dev/null 2>&1; then
            F_RESOLUTION="$(xdpyinfo 2>/dev/null | awk '/dimensions:/ {print $2; exit}')"
        fi
    fi
}


get_de() {
    F_DE=""

    if [ -n "$DESKTOP_SESSION" ]; then
        F_DE="$DESKTOP_SESSION"
    elif [ -n "$XDG_CURRENT_DESKTOP" ]; then
        F_DE="$XDG_CURRENT_DESKTOP"
    elif [ -n "$GNOME_DESKTOP_SESSION_ID" ]; then
        F_DE="GNOME"
    elif [ -n "$KDE_FULL_SESSION" ]; then
        F_DE="KDE"
    fi

    case "$F_DE" in
        gnome*|GNOME*)
            F_DE="GNOME"
            ;;
        xfce*|XFCE*)
            F_DE="Xfce"
            ;;
        lxde*|LXDE*)
            F_DE="LXDE"
            ;;
        kde*|KDE*)
            F_DE="KDE"
            ;;
        fluxbox*|Fluxbox*)
            F_DE="Fluxbox"
            ;;
        openbox*|Openbox*)
            F_DE="Openbox"
            ;;
    esac
}

get_wm() {
    F_WM=""

    if [ -n "$DISPLAY" ]; then
        if type xprop >/dev/null 2>&1; then
            wid="$(xprop -root _NET_SUPPORTING_WM_CHECK 2>/dev/null | awk '{print $NF}')"
            if [ -n "$wid" ]; then
                F_WM="$(xprop -id "$wid" -f _NET_WM_NAME 8t _NET_WM_NAME 2>/dev/null | sed 's/.*= //' | sed 's/^"//' | sed 's/"$//')"
            fi
        fi

        if [ -z "$F_WM" ]; then
            F_WM="$(ps -e 2>/dev/null | egrep 'fluxbox|openbox|xfwm4|metacity|kwin|icewm|fvwm|blackbox|enlightenment' | head -n 1 | awk '{print $NF}')"
        fi
    fi
}


get_cpu() {
    F_CPU=""
    F_CPU_NAME=""

    cpu=""
    speed=""
    cores=""

    if [ -r /proc/cpuinfo ]; then
        cpu="$(awk -F ': ' '
            /model name/ { print $2; exit }
            /cpu[[:space:]]*:/ { print $2; exit }
            /Hardware/ { print $2; exit }
            /Processor/ { print $2; exit }
        ' /proc/cpuinfo 2>/dev/null)"

        speed="$(awk -F ': ' '/cpu MHz/ { printf "%d", $2; exit }' /proc/cpuinfo 2>/dev/null)"
        cores="$(grep -c '^processor' /proc/cpuinfo 2>/dev/null)"
    fi

    cpu="$(trim "$cpu")"
    cpu="$(echo "$cpu" | sed 's/(TM)//g; s/(R)//g; s/  */ /g')"
    cpu="$(trim "$cpu")"

    if [ -n "$cpu" ]; then
        F_CPU_NAME="$cpu"
    fi

    out="$cpu"

    if [ -n "$cores" ] && [ -n "$out" ]; then
        out="${out} (${cores})"
    fi

    if [ -n "$speed" ] && [ -n "$out" ]; then
        if [ "$speed" -ge 1000 ] 2>/dev/null; then
            ghz_major="$(expr "$speed" / 1000)"
            ghz_minor="$(expr \( "$speed" % 1000 \) / 100)"
            out="${out} @ ${ghz_major}.${ghz_minor}GHz"
        else
            out="${out} @ ${speed}MHz"
        fi
    fi

    F_CPU="$out"
}


get_gpu() {
    F_GPU=""

    if type lspci >/dev/null 2>&1; then
        F_GPU="$(lspci 2>/dev/null | egrep 'VGA compatible controller|Display controller|3D controller' | head -n 1 | sed 's/^[0-9A-Fa-f:.]* //')"
        F_GPU="$(trim "$F_GPU")"
        F_GPU="$(echo "$F_GPU" | sed 's/Corporation//g; s/ Inc\.//g; s/\[//g; s/\]//g; s/  */ /g')"
        F_GPU="$(trim "$F_GPU")"
    fi
}


get_memory() {
    F_MEMORY=""

    mem_total=0
    mem_free=0
    mem_buffers=0
    mem_cached=0
    mem_avail=0

    if [ -r /proc/meminfo ]; then
        while read a b c; do
            case "$a" in
                MemTotal:) mem_total="$b" ;;
                MemFree:) mem_free="$b" ;;
                Buffers:) mem_buffers="$b" ;;
                Cached:) mem_cached="$b" ;;
                MemAvailable:) mem_avail="$b" ;;
            esac
        done < /proc/meminfo
    fi

    if [ "$mem_total" -gt 0 ] 2>/dev/null; then
        if [ "$mem_avail" -gt 0 ] 2>/dev/null; then
            mem_used="$(expr "$mem_total" - "$mem_avail")"
        else
            mem_used="$(expr "$mem_total" - "$mem_free" - "$mem_buffers" - "$mem_cached")"
        fi

        mem_used_mib="$(expr "$mem_used" / 1024)"
        mem_total_mib="$(expr "$mem_total" / 1024)"

        F_MEMORY="${mem_used_mib} MiB / ${mem_total_mib} MiB"
    fi
}


get_swap() {
    F_SWAP=""

    swap_total=0
    swap_free=0

    if [ -r /proc/meminfo ]; then
        while read a b c; do
            case "$a" in
                SwapTotal:) swap_total="$b" ;;
                SwapFree:) swap_free="$b" ;;
            esac
        done < /proc/meminfo
    fi

    if [ "$swap_total" -gt 0 ] 2>/dev/null; then
        swap_used="$(expr "$swap_total" - "$swap_free")"
        swap_used_mib="$(expr "$swap_used" / 1024)"
        swap_total_mib="$(expr "$swap_total" / 1024)"
        F_SWAP="${swap_used_mib} MiB / ${swap_total_mib} MiB"
    fi
}


get_root_disk() {
    F_DISK=""

    if type df >/dev/null 2>&1; then
        F_DISK="$(df -hP / 2>/dev/null | awk 'NR == 2 { print $3 " / " $2 " (" $5 "), " $4 " free" }')"
        F_DISK="$(trim "$F_DISK")"
    fi
}

build_ascii_block() {
    out="$1"

    : > "$out"

    if [ "$SHOW_ASCII" != "1" ]; then
        return
    fi

    cat > "$out" <<EOF
${C_RED}       _,met\$\$\$\$\$gg.
${C_RED}    ,g\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$P.
${C_RED}  ,g\$\$P"        """Y\$\$.".
${C_RED} ,\$\$P'              \`\$\$\$.
${C_RED}',\$\$P       ,ggs.     \`\$\$b:
${C_RED}\`d\$\$'     ,\$P"'   .    \$\$\$
${C_RED} \$\$P      d\$'     ,    \$\$P
${C_RED} \$\$:      \$\$.   -    ,d\$\$'
${C_RED} \$\$;      Y\$b._   _,d\$P'
${C_RED} Y\$\$.    \`.\`"Y\$\$\$\$P"'
${C_RED} \`\$\$b      "-.__
${C_RED}  \`Y\$\$
${C_RED}   \`Y\$\$.
${C_RED}     \`\$\$b.
${C_RED}       \`Y\$\$b.
${C_RED}          \`"Y\$b._
${C_RED}              \`""""${C_RESET}
${C_GREEN}        RetroDebian${C_RESET}
EOF
}


write_info_line() {
    file="$1"
    key="$2"
    val="$3"

    if [ -n "$val" ]; then
        echo "${C_CYAN}${C_BOLD}${key}${C_RESET}: $val" >> "$file"
    fi
}


build_info_block() {
    out="$1"

    : > "$out"

    echo "$F_TITLE" >> "$out"

    title_plain="$(strip_ansi "$F_TITLE")"
    title_len="$(echo "$title_plain" | awk '{print length($0)}')"
    underline="$(repeat_char "-" "$title_len")"
    echo "$underline" >> "$out"
    echo "" >> "$out"

    write_info_line "$out" "OS" "$F_OS"
    write_info_line "$out" "RetroDebian" "$F_RETRODEBIAN"
    write_info_line "$out" "Host" "$F_HOSTMODEL"
    write_info_line "$out" "Kernel" "$F_KERNEL"
    write_info_line "$out" "Uptime" "$F_UPTIME"
    write_info_line "$out" "Packages" "$F_PACKAGES"
    write_info_line "$out" "Shell" "$F_SHELL"
    write_info_line "$out" "Resolution" "$F_RESOLUTION"
    write_info_line "$out" "DE" "$F_DE"
    write_info_line "$out" "WM" "$F_WM"
    write_info_line "$out" "CPU" "$F_CPU"
    write_info_line "$out" "GPU" "$F_GPU"
    write_info_line "$out" "Memory" "$F_MEMORY"
    write_info_line "$out" "Swap" "$F_SWAP"
    write_info_line "$out" "Disk" "$F_DISK"
}

render_output() {
    left="/tmp/retrodebian-fetch-left.$$"
    right="/tmp/retrodebian-fetch-right.$$"

    trap 'rm -f "$left" "$right"' 0 1 2 3 15

    build_ascii_block "$left"
    build_info_block "$right"
    get_term_cols

    if [ "$SHOW_ASCII" = "1" ] && [ "$TERM_COLS" -ge 76 ] 2>/dev/null; then
        left_width="$(awk '
            {
                n = length($0)
                if (n > max) {
                    max = n
                }
            }
            END {
                if (max < 1) {
                    max = 1
                }
                print max
            }
        ' "$left")"

        gap=3
        pad_width="$(expr "$left_width" + "$gap")"

        exec 3<"$left"
        exec 4<"$right"

        left_done=0
        right_done=0

        while :; do
            if [ "$left_done" -eq 0 ]; then
                if IFS= read -r l <&3; then
                    :
                else
                    l=""
                    left_done=1
                fi
            else
                l=""
            fi

            if [ "$right_done" -eq 0 ]; then
                if IFS= read -r r <&4; then
                    :
                else
                    r=""
                    right_done=1
                fi
            else
                r=""
            fi

            if [ "$left_done" -eq 1 ] && [ "$right_done" -eq 1 ] && [ -z "$l" ] && [ -z "$r" ]; then
                break
            fi

            printf "%-${pad_width}s%s\n" "$l" "$r"
        done

        exec 3<&-
        exec 4<&-
    else
        if [ "$SHOW_ASCII" = "1" ]; then
            cat "$left"
            echo ""
        fi
        cat "$right"
    fi

    rm -f "$left" "$right"
    trap - 0 1 2 3 15
}

usage() {
    echo "retrodebian-fetch $VERSION"
    echo "Usage: $0 [--stdout] [--off] [--help] [--version]"
    exit 0
}


parse_args() {
    while [ -n "$1" ]; do
        case "$1" in
            --stdout)
                USE_COLOR=0
                SHOW_ASCII=0
                C_RESET=""
                C_BOLD=""
                C_RED=""
                C_BLUE=""
                C_WHITE=""
                ;;
            --off)
                SHOW_ASCII=0
                ;;
            --help)
                usage
                ;;
            --version)
                echo "$VERSION"
                exit 0
                ;;
        esac
        shift
    done
}


main() {
    parse_args "$@"

    get_user_host
    get_os
    get_host_model
    get_kernel
    get_uptime
    get_packages
    get_shell
    get_resolution
    get_de
    get_wm
    get_cpu
    get_gpu
    get_memory
    get_swap
    get_root_disk

    render_output
}

main "$@"