#!/bin/bash

# These global variables can be overridden by config
# Name of the pony
PONY=random
# What info to show (must have a function defined as ponyget_* to work)
INFO=(User Hostname IP Distro Kernel Uptime Load Shell Packages RAM Swap Disk)
# File system type to show disk usage (default/empty=all) (see df for specific values)
FSTYPE=
# Interface to get the IP address from
IP_INTERFACE="eth0"

function ponyget_Shell()
{
    echo "$SHELL"
}

function ponyget_User()
{
    whoami
}

function ponyget_Distro()
{
    lsb_release -isr | paste "-d " - -
}

function pccolor()
{
    local color="32";
    if [ "$1" -gt 66 ]
    then
        color="31"
    elif [ "$1" -gt 33 ]
    then
        color="33"
    fi
    echo -e "\x1b[$color;1m"
}

function ponyget_RAM()
{
    local ramtable=$(free -h | head -n -1)
    local used=$(echo "$ramtable" | tail -n 1 | sed -r "s/ +/\t/g"  | cut -f 3)
    local total=$(echo "$ramtable" | sed -n 2p | sed -r "s/ +/\t/g"  | cut -f 2)

    ramtable=$(free -m | head -n -1)
    local used_M=$(echo "$ramtable" | tail -n 1 | sed -r "s/ +/\t/g"  | cut -f 3)
    local total_M=$(echo "$ramtable" | sed -n 2p | sed -r "s/ +/\t/g"  | cut -f 2)
    let percent="$used_M * 100 / $total_M"


    echo -e "$(pccolor $percent)$used\x1b[0m / $total"
}

function ponyget_Swap()
{
    local swaptable=$(free -h | grep Swap)
    local used=$(echo "$swaptable" | sed -r "s/ +/\t/g"  | cut -f 3)
    local total=$(echo "$swaptable" | sed -r "s/ +/\t/g"  | cut -f 2)

    swaptable=$(free -m | grep Swap)
    local used_M=$(echo "$swaptable" | sed -r "s/ +/\t/g"  | cut -f 3)
    local total_M=$(echo "$swaptable" | sed -r "s/ +/\t/g"  | cut -f 2)
    let percent="$used_M * 100 / $total_M"


    echo -e "$(pccolor $percent)$used\x1b[0m / $total"
}

function ponyget_Kernel()
{
    uname -r -m
}

function ponyget_Hostname()
{
    hostname
}

function ponyget_CPU()
{
    cat /proc/cpuinfo | grep "model name" | head -n 1 | sed -r "s/model name\s: //"
}

function ponyget_CPU_Usage()
{
    printf %.1f%% "$(top -b -n1 | grep "Cpu(s):" | sed -r -e "s/^[^0-9]+//" -e "s/[^0-9]+,\s+/ + /g" -e "s/[^0-9]+$//" | cut -d ' ' -f 1-5 | bc)"
}

function ponyget_Uptime()
{
    uptime | grep -oE "up.*user" | \
        sed -r -e "s/up\s*(.+),\s*[0-9]+\s*user/\1/" -e "s/\s+/ /g"
}

function ponyget_Load()
{
    uptime | sed -r -e "s/.*load average:\s*//"
}

function ponyget_Packages()
{
    if which dpkg &>/dev/null
    then
        dpkg --get-selections | grep -v deinstall | wc -l
    elif which rpm &>/dev/null
    then
        rpm -qa | wc -l
    elif which pacman &>/dev/null
    then
        pacman -Q | wc -l
    fi
}

function ponyget_Disk()
{
    local dfoption=$FSTYPE
    [ "$dfoption" ] && dfoption="-t $FSTYPE"
    local diskusage=$(df -lh $dfoption --total | tail -n 1 | sed -r "s/ +/\t/g" )
    local used=$(echo "$diskusage" | cut -f 3)
    local total=$(echo "$diskusage" | cut -f 2)
    local percent=$(echo "$diskusage"  | cut -f 5 | sed s/%// )

    echo -e "$(pccolor $percent)$used\x1b[0m / $total"
}

function ponyget_Containers()
{
    local active="$(lxc-ls --active | wc -l)"
    local total="$(lxc-ls | wc -l)"
    local color=32
    if [ "$active" -lt "$total" ]
    then
        color=31
    fi
    echo -e "\x1b[$color;1m$active\x1b[0m / $total active"
}

function ponyget_IP()
{
    [ -z "$1" ] && inet="inet" || inet="$1"
    ip -o addr | grep -vE "lo\s+inet" | grep -F "$IP_INTERFACE" | grep -Po "$inet\s+\K[^/]+" | xargs echo
}

function ponyget_IPv6()
{
    ponyget_IP inet6
}

function bold()
{
    echo -en "\x1b[1m${*}\x1b[22m"
}

function underline()
{
    echo -en "\x1b[4m${*}\x1b[24m"
}

function title()
{
    echo
    bold ${*}
    echo
}

function help()
{
    title NAME
    echo -e "\t$(bold $0) - show a pony and some system information"

    title SYNOPSIS
    echo -e "\t$(bold $0) [$(bold --pony) $(underline pony)|$(bold -p)$(underline pony)] [$(bold --info) $(underline id)|$(bold -i)$(underline id)...]"
    echo -e "\t$(bold $0) $(bold help)|$(bold --help)|$(bold -h)"

    title OPTIONS
    echo -e "\t$(bold --pony) $(underline pony), $(bold -p)$(underline pony)"
    echo -e "\t\tSelect a pony (default: $PONY)."
    echo
    echo -e "\t$(bold --info) $(underline id), $(bold -i)$(underline id)"
    echo -e "\t\tShow the given info (default: ${INFO[@]})."
    echo -e "\t\tThis option supports multiples IDs separated by commas, spaces or colons."
    echo -e "\t\tAvailable IDs:"
    declare -F | grep ponyget_ | sed "s/declare -f ponyget_/\t\t * /"
    echo
    echo -e "\t$(bold --list), $(bold --list-ponies)"
    echo -e "\t\tShows a list of possible values for $(bold --pony)."

    title CONFIGURATION
    echo -e "\tYou can override $(bold PONY) and $(bold INFO) in the config files."
    echo -e "\tConfiguration files:"
    echo -e "\t * $(underline PREFIX)$(bold /share/ascii-pony/systempony.conf) (system)"
    echo -e "\t * $(bold ~/.systempony) (user)"

    echo
}

function list_ponies()
{
    ponydir=$(get_data_file "rendered/ansi/")
    echo random
    find "$ponydir" -name '*.ansi' -exec basename {} .ansi \; | sort
}

function select_info()
{
    INFO=($(echo "${*}" | column -t -s:,))
}

SELFDIR=$(dirname $(readlink -se "${BASH_SOURCE[0]}"))
function get_data_file()
{
    if [ -e "$SELFDIR/$1" ]
    then
        # Not installed
        echo "$SELFDIR/$1"
    elif [ -e "$SELFDIR/../share/ascii-pony/$1" ]
    then
        # Installed with PREFIX=$SELFDIR/..
        echo "$SELFDIR/../share/ascii-pony/$1"
    fi
}

# Returns the number of displayed characters, ignoring color codes
function strlen_color()
{
    echo -n "$1" | sed -r 's/\x1b\[[0-9;]+m//g' | wc -c
}

# Truncates a string
function truncate_color()
{
    local length="$(strlen_color "$1")"
    local target="$2"
    if [ "$length" -gt "$target" ]
    then
        let cut="$target-$length"
        echo -n "$1" | head -c $cut
        return
    fi
    echo "$1"
}

# Read global config
globalconfig=$(get_data_file systempony.conf)
if [ -r "$globalconfig" ]
then
    source "$globalconfig"
fi
# Read user config
if [ -r ~/.systempony ]
then
    source ~/.systempony
fi

# Read parameters
while [ "$1" ]
do
    case "$1" in
        --help|-h|help)
            help
            exit 0
            ;;
        --list|--list-ponies)
            list_ponies
            exit 0
            ;;
        --pony|-p)
            shift
            PONY="$1"
            ;;
        -p=*|--pony=*)
            PONY="$(echo "$1" | sed -r "s/^(-p|--pony)=//")"
            ;;
        --info|-i)
            infostring=""
            while [ "$2" ] && ! echo "$2" | grep -q -e "-"
            do
                infostring="$infostring $2"
                shift
            done
            select_info "$infostring"
            ;;
        -i=*|--info=*)
            select_info "$(echo "$1" | sed -r "s/^(-i|--info)=//")"
            ;;
    esac
    shift
done

# Evaluate info
info_values=()
let info_key_max_length=0
let info_val_max_length=0
function addinfo()
{
    info_values+=("${2}")
    local key_length=$(echo "$1" | wc -c)
    local val_length=$(echo "${2}" | wc -c)
    [ $key_length -gt $info_key_max_length ] && info_key_max_length=$key_length;
    [ $val_length -gt $info_val_max_length ] && info_val_max_length=$val_length;
}
for info in ${INFO[*]}
do
    if [ "$(type -t ponyget_${info})" = "function" ]
    then
        addinfo $info "$(ponyget_${info})"
    else
        addinfo $info "unsupported"
    fi
done

if [ -f "$PONY" ]
then
    ponyfile="$PONY"
elif [ "$PONY" = nopony ]
then
    ponyfile=/dev/null
else
    ponydir=$(get_data_file "rendered/ansi/")
    ponyfile="$ponydir/$PONY.ansi"
    if [ -n "$ponydir" -a '(' \! -f "$ponyfile" -o "$PONY" = random ')' ]
    then
        ponyfile="$(find "$ponydir" -name '*.ansi' | shuf | head -n 1)"
    fi
fi


declare -A info_firstx # Number of characters before the system info output
info_firstx[applejack-nohat]=64
info_firstx[applejack]=70
info_firstx[bigmac]=42
info_firstx[celestia]=76
info_firstx[cadance]=55
info_firstx[derpy]=61
info_firstx[fluttershy]=67
info_firstx[great-and-powerful]=68
info_firstx[luna]=67
info_firstx[lyra]=61
info_firstx[pinkie-pie]=61
info_firstx[rainbow-dash]=61
info_firstx[rainbow]=61
info_firstx[rarity]=61
info_firstx[rose]=61
info_firstx[trixie]=61
info_firstx[twilight-alicorn]=61
info_firstx[twilight-unicorn]=61
info_firstx[vinyl-scratch-glasses]=69
info_firstx[vinyl-scratch-noglasses]=69

declare -A info_firsty # Number of lines before the system info output
info_firsty[luna]=18
info_firsty[rarity]=11
info_firsty[trixie]=16

if [ -f "$ponyfile" ]
then
    lines=$(cat "$ponyfile" | wc -l) # cat to avoid printing file name
    let info_index=0
    COLUMNS=$(tput cols || echo 1024)


    if [ "${info_firstx[$PONY]}" ]
    then
        info_x=${info_firstx[$PONY]}
    else
        info_x=80
    fi

    if [ "${info_firsty[$PONY]}" ]
    then
        start_line=${info_firsty[$PONY]}
    else
        let start_line=($lines-${#INFO[@]})/2
    fi



    let current_line=1
    while IFS= read -r  line
    do
        if [ $info_index -lt ${#INFO[@]} -a $current_line -ge $start_line ]
        then
            let msgsize="$COLUMNS - $info_x - $info_key_max_length - 4"
            line="$(truncate_color "$line" $info_x)"
            printf "%s \x1b[31;1m%-${info_key_max_length}s\x1b[0m: %s %s\n" \
                "$line$backspaces" \
                "${INFO[$info_index]}" \
                "$(truncate_color "${info_values[$info_index]}" $msgsize)"
            let info_index++
        else
            echo -n "$line"
            echo -e "\x1b[0m"
        fi
        let current_line++
    done < "$ponyfile"
else
    let info_index=0
    while [ $info_index -lt ${#INFO[@]} ]
    do
        printf "\x1b[31;1m%-${info_key_max_length}s\x1b[0m: %s\n" \
            "${INFO[$info_index]}" \
            "${info_values[$info_index]}"
        let info_index++
    done
fi