#!/bin/sh
reloadpath="$0"
#
# nOpacity Theme Presets for OSDServer on localhost
#

# Global user settings
setupdir=/var/lib/vdr
presetdir=$setupdir/plugins/skinnopacity/presets
restart=0 # 0=no, 1=yes

# Some basic tests
[ -d "$presetdir" ] || mkdir -p "$presetdir"
[ -d "$presetdir" ] || exit 1
[ -x "$reloadpath" ] || exit 1

# Some generic stuff for handling a connection
true=0
false=1

function error() {
    # Fatal error. Send quit command, close FIFO and terminate netcat
    [ "${reply2xx[0]}" != 202 ] && SendCmd Quit

    exec 3>&-
    exec 4>&-

    kill $pid

    exit 1
}

function ConnectServer() {
    # Connect to the OSDServer

    # Set up temporary fifo and open as file descriptor 3 and 4
    mkfifo --mode=700 /tmp/pipe-in$$ /tmp/pipe-out$$
    exec 3<> /tmp/pipe-in$$
    exec 4<> /tmp/pipe-out$$
    rm /tmp/pipe-in$$ /tmp/pipe-out$$

    # Connect to server using the fifo
    {
        netcat $1 $2

        # In case of connection loss:
        echo 499 disconnected
        echo 202 Good Bye.
    } <&3 >&4 &
    pid=$!

    # Sending to the server: use >&3
    # Receive from the server: use <&4
}


function ReadReply() {
    # Read a complete server reply until 2xx return code,
    # and store replies in each category by number
    reply2xx=()
    reply3xx=()
    reply4xx=()
    reply5xx=()
    reply6xx=()

    while read -r code line <&4 ; do
        echo "< $code $line"
        # screen echo

        case $code in
            2*)     IFS=$' \t\n\r' reply2xx=($code "$line")
                    ;;
            3*)     IFS=$' \t\n\r' reply3xx=($code $line)
                    ;;
            4*)     IFS=$' \t\n\r' reply4xx=($code "$line")
                    ;;
            5*)     IFS=$' \t\n\r' reply5xx=($code "$line")
                    ;;
            6*)     IFS=$' \t\n\r' reply6xx=($code "$line")
                    ;;
        esac
        [ -n "${reply2xx[0]}" ] && break
    done

    [ -n "${reply4xx[0]}" ] && return $false
    return $true
}

function SendCmd() {
    # Send a command and read the reply

    echo "> $*"
    # screen echo

    echo "$*" >&3
    # network send

    ReadReply
}

function IsEvent() {
    # Helper to check reply for a certain event

    [ "${reply3xx[0]}" != 300 ] && return $false
    [ "${reply3xx[1]}" != "$1" ] && return $false
    [ "${reply3xx[2]}" != "$2" ] && return $false

    return $true
}


function QuoteString() {
    # Quote arbitrary string for use in '' and ""
    local str="${!1}"

    str="${str//'\'/\\\\}"
    str="${str//'\\'/\\\\}"
    # work around bash bug: double quoted '\'

    str="${str//\'/$'\\\''}"
    # This is bogus, anyone knows something better to replace ' by \' ?

    str="${str//\"/\\\"}"
    str="${str//$'\r'/\\r}"
    str="${str//$'\n'/\\n}"
    str="${str//$'\t'/\\t}"

    eval "$1=\$str"
}

function UnquoteString() {
    # Unquote string
    local str="${!1}"

    str="${str//\\r/$'\r'}"
    str="${str//\\n/$'\n'}"
    str="${str//\\t/$'\t'}"
    str="${str//\\\"/\"}"
    str="${str//\\\'/\'}"
    str="${str//\\\\/\\}"

    eval "$1=\$str"
}


# Helper functions
function CreatePreset() {
    osdskin=$(vdr-dbus-send /Setup setup.Get string:'OSDSkin' | grep variant | cut -f2 -d '"')
    if [ "$osdskin" == "nOpacity" ]; then
        echo "OSDSkin = $osdskin" > "$presetdir/$osdtheme.preset"
        osdtheme=$(vdr-dbus-send /Setup setup.Get string:'OSDTheme' | grep variant | cut -f2 -d '"')
        echo "OSDTheme = $osdtheme"  >> "$presetdir/$osdtheme.preset"
        cat "$setupdir/setup.conf" | grep "skinnopacity." >> "$presetdir/$osdtheme.preset"
    else
        SendCmd "Message -warn -seconds 5 'nOpacity ist nicht aktiviert! OSDSkin: $osdskin'" || return $false
    fi
}

function ResetSkin() {
    msg='Setze nOpacity zurück ...'
    [ "$restart" == "1" ] && msg='Setze nOpacity zurück und starte VDR neu ...'
    SendCmd "Message -status '$msg" || return $false
    vdr-dbus-send /Setup setup.Del string:'skinnopacity.*'
    vdr-dbus-send /Setup setup.Set string:'OSDSkin' variant:string:'nOpacity'
    vdr-dbus-send /Setup setup.Set string:'OSDTheme' variant:string:'default'
    vdr-dbus-send /Skin skin.SetSkin string:'nOpacity'
    SendCmd "Message -statusclear" || return $false
    if [ "$restart" != "1" ]; then
        SendCmd "Message -warn -seconds 5 'Der VDR muss jetzt neugestartet werden!'" || return $false
#        vdr-dbus-send /Remote remote.HitKeys array:string:'Setup','Ok','Down','Down','Ok' # first we have to load skin defaults!
#        SendReload
    else
        RestartVdr
    fi
}

function LoadPreset() {
    preset=$1
    msg="Lade Preset \\'$preset\\'"
    [ "$restart" == "1" ] && msg="Lade Preset \\'$preset\\' und starte VDR neu ... "
    SendCmd "Message -status '$msg'" || return $false
    # backup current settings
    last="last.preset"
    [ "$preset" == "last" ] && last="lastlast.preset"
    osdskin=$(vdr-dbus-send /Setup setup.Get string:'OSDSkin' | grep variant | cut -f2 -d '"')
    osdtheme=$(vdr-dbus-send /Setup setup.Get string:'OSDTheme' | grep variant | cut -f2 -d '"')
    echo "OSDSkin = $osdskin" > "$presetdir/$last"
    echo "OSDTheme = $osdtheme"  >> "$presetdir/$last"
    [ "$osdskin" == "nOpacity" ] && cat "$setupdir/setup.conf" | grep "skinnopacity." >> "$presetdir/$last"
    # reload skin
    while read line; do
        opt=$(echo $line| tr -d " " | cut -f1 -d "=")
        val=$(echo $line| tr -d " " | cut -f2 -d "=")
        vdr-dbus-send /Setup setup.Set string:"$opt" variant:string:"$val"
    done < "$presetdir/$preset.preset"
    [ "$preset" == "last" ] && mv -f "$presetdir/$last" "$presetdir/last.preset"
    SendCmd "Message -statusclear" || return $false
    if [ "$restart" != "1" ]; then
#        SendCmd "Message -warn -seconds 5 'Der VDR muss jetzt neugestartet werden!'" || return $false
        vdr-dbus-send /Remote remote.HitKeys array:string:'Setup','Ok','Down','Down'
    else
        RestartVdr
    fi
}

function RestartVdr() {
    SendCmd "Message 'Neustart ...'" || return $false
    sudo /sbin/initctl restart vdr
}

function SendReload() {
    echo "$reloadpath" |at now
}

# Menu functions
function RenamePreset() {
    # create submenu
    preset=$1
    SendCmd "enterlocal" || return $false
    # Preserve global variable space, so we can re-use 'menu'
    SendCmd "menu=New Menu 'Preset umbenennen'" || return $false
    SendCmd "menu.SetColumns 15" || return $false
    SendCmd "menu.EnableEvent keyOk close" || return $false
    SendCmd "rename=menu.AddNew EditStrItem 'Name' '$preset'" || return $false
    SendCmd "_focus.addsubmenu menu" || return $false
    SendCmd "menu.Show" || return $false

    while true; do
        SendCmd "menu.SleepEvent" || return $false
        if IsEvent menu keyOk ; then
            SendCmd "rename.GetValue -quoted" || return $false
            [ "${reply5xx[0]}" != 500 ] && return $false
            newpreset="${reply5xx[1]}"
            mv -f "$presetdir/$preset.preset" "$presetdir/$newpreset.preset"
            SendCmd "menu.SendState osBack" || return $false
            SendCmd "delete menu" || return $false
            SendCmd "leavelocal" || return $false
            return $true
        fi
        if IsEvent menu close ; then
            SendCmd "delete menu" || return $false
            SendCmd "leavelocal" || return $false
            return $true
        fi
    done
}

function ShowNews() {
    # create menu
    title="nOpacity Theme Presets"
    [ "$restart" == "1" ] && title="nOpacity Theme Presets (Auto-Neustart ist aktiv)"
    SendCmd "menu=New Menu '$title'" || return $false
    SendCmd "menu.SetColorKeyText -red 'Neustarten'" || return $false
    SendCmd "menu.SetColorKeyText -blue 'Hilfe'" || return $false
    SendCmd "menu.SetColumns 15" || return $false
    SendCmd "menu.EnableEvent keyMenu keyBack keyRed close" || return $false
    # items
    SendCmd "backup=menu.AddNew OsdItem 'Preset für den aktuellen Theme erstellen'" || return $false
    SendCmd "backup.EnableEvent keyOk keyBlue focus" || return $false
    SendCmd "reset=menu.AddNew OsdItem 'nOpacity defaults laden'" || return $false
    SendCmd "reset.EnableEvent keyOk keyBlue focus" || return $false
    SendCmd "menu.AddNew OsdItem -unselectable 'Theme Presets:'" || return $false
    # preset items
    arr=""; for file in $presetdir/*.preset ; do [ -r "$file" ] && arr="$arr $(echo $(basename $file) | cut -f1 -d '.')";  done
    for pre in $arr ; do
        SendCmd "$pre=menu.AddNew OsdItem '  - $pre'" || return $false
        SendCmd "$pre.EnableEvent keyOk keyGreen keyYellow keyBlue focus" || return $false
    done

    # do it...
    SendCmd "menu.Show" || return $false
    while true ; do
        SendCmd "menu.SleepEvent" || return $false
        # menu / buttons
        if IsEvent menu close ; then
            return $true
        fi
        if IsEvent menu keyRed ; then
            RestartVdr
        fi
        # backup / create
        if IsEvent "backup" keyOk ; then
            SendCmd "Message 'Erstelle Preset...'" || return $false
            CreatePreset && SendReload
            return $true
        fi
        if IsEvent "backup" focus ; then
            SendCmd "menu.SetColorKeyText -green  ''" || return $false
            SendCmd "menu.SetColorKeyText -yellow ''" || return $false
            SendCmd "menu.Show" || return $false
        fi
        if IsEvent "backup" keyBlue ; then
            SendCmd "Message -seconds 5 'Erstelle ein Preset mit OK oder verlasse das Menü mit BACK'" || return $false
        fi
        # reset
        if IsEvent "reset" keyOk ; then
            ResetSkin || return $false
        fi
        if IsEvent "reset" focus ; then
            SendCmd "menu.SetColorKeyText -green  ''" || return $false
            SendCmd "menu.SetColorKeyText -yellow ''" || return $false
            SendCmd "menu.Show" || return $false
        fi
        if IsEvent "reset" keyBlue ; then
            SendCmd "Message -seconds 5 'Lade nOpacity defaults mit OK oder verlasse das Menü mit BACK'" || return $false
        fi
        # presets
        for pre in $arr ; do
            if IsEvent "$pre" keyOk ; then
                LoadPreset $pre || return $false
            fi
            if IsEvent "$pre" keyYellow ; then
                SendCmd "Message 'Lösche Preset \'$pre\' ...'" || return $false
                rm -f "$presetdir/$pre.preset" && SendReload
                return $true
            fi
            if IsEvent "$pre" keyGreen ; then
                RenamePreset "$pre" && SendReload
                return $true
            fi
            if IsEvent "$pre" focus ; then
                SendCmd "menu.SetColorKeyText -green  'Umbennenen'" || return $false
                SendCmd "menu.SetColorKeyText -yellow 'Löschen'" || return $false
                SendCmd "menu.Show" || return $false
            fi
            if IsEvent "$pre" keyBlue ; then
                SendCmd "Message -seconds 5 'Aktiviere ein Preset mit OK oder verlasse das Menü mit BACK'" || return $false
            fi
        done

    done
}


###############
#  Main Code  #
###############

ConnectServer localhost 2010
# Connect to the server process

ReadReply || error
# Read server welcome

SendCmd "Version 0.1" || error
# Identify to server with protocol version

ShowNews || error
# Do it...

SendCmd Quit
# ... and good bye

exec 3>&-
exec 4>&-
# close FIFOs
