#!/bin/bash
SOURCE="$0"
source /usr/lib/elive-tools/functions
EL_REPORTS="1"
el_make_environment
. gettext.sh
TEXTDOMAIN="elive-tools"
export TEXTDOMAIN

# Lock system (good one) {{{
lockfile="/tmp/.$(basename $0)-${USER}.lock"

exit_ok(){
    rm -f "$lockfile"
}
exit_error(){
    rm -f "$lockfile"
}

if ! [[ -n "$IGNORE_LOCK" ]] ; then
    if [[ -r "$lockfile" ]] ; then
        PROCCESS="$(cat $lockfile)"
    else
        PROCCESS=" "
    fi
    if (ps up $PROCCESS) 1>/dev/null 2>&1 ; then
        echo -e "E: $(basename "$0" ) already running"
        exit
    else
        echo $$ > "$lockfile"
    fi

    # SET the lock file
    echo "$$" > "$lockfile"
fi

# traps needs to be after the lock verification, in order to not remove it when we are already running
trap "exit_ok" EXIT
trap "exit_error" 1 3 5 6 14 15 ERR TERM


# end lock system }}}
#
asound_cards="/proc/asound/cards"
#asound_cards="/tmp/asoundcards.txt" # only for betatesting with fake list cards

reconfigure_applications(){
    local name mic num
    # vokoscreen default mic
    if [[ -s "$HOME/.config/vokoscreen/vokoscreen.conf" ]] ; then
        if grep -qs "^pcm\.mic" "$HOME/.asoundrc" ; then
            while read -ru 3 line
            do
                if [[ "$line" = "pcm.mic"* ]] ; then
                    _a=1
                fi
                if ((_a)) ; then
                    if echo "$line" | grep -qsE "^\s*card " ; then
                        mic="$( echo "$line" | grep -qsE "^\s*card " | sed -e 's|^.*card ||g' )"
                    fi
                fi
                if [[ -n "$mic" ]] ; then
                    el_debug "mic is set to another card: $mic"
                    break
                fi
            done 3<<< "$( cat "$HOME/.asoundrc")"
        else
            mic="$( grep "^defaults\.pcm\.card" "$HOME/.asoundrc" | sed -e 's|^.*defaults.pcm.card ||g' | sed -e '/^$/d' | tail -1 )"
            el_debug "mic is set to default card: $mic"
        fi

        # configure
        if [[ -n "$mic" ]] ; then
            num="$( cat "$asound_cards" | grep -E "\[${mic}\s*\]" | sed -e '/^$/d' | head -1 | awk '{print $1}' )"
            name="$( cat "$asound_cards" | grep -E "\[${mic}\s*\]" | sed -e '/^$/d' | head -1 | sed -e 's|^.* - ||g' )"
            if [[ -n "$name" ]] && [[ -n "$num" ]] ; then
                sed -i -e "s|NameCaptureCard=.*|NameCaptureCard=\"[hw:${num},0] ${name}\"|g" "$HOME/.config/vokoscreen/vokoscreen.conf"
            fi
        fi
    fi
}

select_card_multiple(){
    local _id _name _description menu
    # list cards, per priority
    unset menu

    while read -ru 3 line
    do
        if [[ "$line" != *"]:"* ]] ; then
            continue
        fi

        _id="$( echo "$line" | awk '{print $1}' )"
        _name="$( echo "$line" | sed -e 's|\]:.*$||g' -e 's|^.*\[||g' )"
        # remove extra leading blank chars
        read -r _name <<< "$_name"
        el_debug "name = '$_name'"
        el_debug "id = '$_id'"

        _description="${line##*- }"
        # remove extra leading blank chars
        read -r _description <<< "$_description"
        el_debug "description = '$_description'"


        if [[ "$_name" ]] && [[ -n "$_description" ]] ; then

            # skip unwanted ones
            case "$_name" in
                Modem|Dummy|system)
                    el_debug "skipping $_name because is not a useful card"
                    continue
                    ;;
            esac
            if [[ "$_name" = "ThinkPadEC" ]] && [[ "$_description" = "ThinkPad Console Audio Control" ]] ; then
                el_debug "skipping ThinkPadEC because is not a useful one"
                continue
            fi

            menu+=("$( echo "$_name" )")
            menu+=("$( echo "$_description" )")
        fi
    done 3<<< "$( cat "$asound_cards" | psort -- -p "EWX" -p "PCH" -p "USB" -p "DAC" -p "Intel" -p "SB16" -p "CS4236" -p "Generic$" | grep -v "at 0x.*irq" )"
    # note: this psort is not very important since it's only going to be used for menu

    # set auto mode unless we have an USB/DAC audio card, also because we may want the mic from elsewhere
    if [[ "${#menu[@]}" -eq 2 ]] && ! ((has_usb_audio)) ; then
    #if [[ "${#menu[@]}" -eq 2 ]] ; then
        selection="$( echo "${menu[0]}" | sed -e '/^$/d' | head -1 )"
        el_debug "only one card found: $selection | switching to auto mode"
        is_auto_mode=1
    else
        selection="$( $guitool --list --width=400 --height=240 --column="$( eval_gettext "Identifier" )" --column="$( eval_gettext "Description" )" --text="$( eval_gettext "Select the desired audio card that you want to use as default" )" "${menu[@]}" || echo cancel )"
        el_debug "User selected audio card: $selection"
    fi

    # remove extra leading blank chars
    read -r selection <<< "$selection"
    # bullseye and up works with ID instead of name
    if ((is_buster)) || ((is_wheezy)) ; then
        selection="$selection"
    else
        selection="$( grep -E "\[\s*${selection}\s*\]" "$asound_cards" | sed -e '/^$/d' | awk '{print $1}' | head -1 )"
    fi

    if [[ "${selection}" = "cancel" ]] ; then
        return 1
    fi
}

main(){
    # pre {{{
    local list_cards number_cards selection guitool line is_auto_mode is_quiet_mode

    case "$( cat /etc/debian_version )" in
        11.*|"bullseye"*)
            is_bullseye=1
            ;;
        10.*|"buster"*)
            is_buster=1
            ;;
        7.*|"wheezy"*)
            is_wheezy=1
            ;;
        *)
            # by default, normal mode:
            true
            ;;
    esac

    if el_pulseaudio check ; then
        is_pulseaudio=1
    fi

    # }}}

    # NOTE: this is a temporal tool, a lot of improvements will be made about this, so don't try to improve this one

    guitool="/usr/bin/zenity --window-icon=/usr/share/icons/gnome/256x256/apps/logo-elive.png"

    # bullseye and up works with ID instead of name
    #if ((is_buster)) || ((is_wheezy)) ; then
        #list_cards="$(cat "$asound_cards" | grep "^.*[[:digit:]].*\[.*\]:" | grep -v "at 0x.*irq" | sed -e 's|\]:.*$||g' -e 's|^.*\[||g')"
    #else
        #list_cards="$(cat "$asound_cards" | grep "^.*[[:digit:]].*\[.*\]:" | grep -v "at 0x.*irq" | awk '{print $1}' )"
    #fi
    list_cards="$(cat "$asound_cards" | grep "^.*[[:digit:]].*\[.*\]:" | grep -v "at 0x.*irq" | sed -e 's|\]:.*$|\]|g' )"

    if grep -qsE "\[(USB|DAC)\s*]" "$asound_cards" ; then
        has_usb_audio=1
    fi

    if [[ "$( cat "$asound_cards" | grep -vE "\[(ThinkPadEC|NVidia|midi|MIDI|Dummy|system|Modem)" | grep -E "\[.*\]" | wc -l )" -gt 1 ]]  ; then
        el_debug "there is multiple cards found"
        has_multiple_cards=1
    fi

    # if our first argument is the card name to use, change the list of cards to use this one
    # try to be smart determining cards that we know that they are valid
    for arg in "$@"
    do
        if [[ "$arg" = "--smart" ]] ; then
            # deprecated feature: we always want it to be smart!, unless we don't use --auto
            #is_smart_mode=1
            shift
        fi
        if [[ "$arg" = "--auto" ]] ; then
            is_auto_mode=1
            shift
        fi
        if [[ "$arg" = "--quiet" ]] ; then
            is_quiet_mode=1
            QUIET="--quiet"
            shift
        fi
        if [[ "$arg" = "--no-messages" ]] ; then
            is_nomessages=1
            shift
        fi
        # if first argument is the name of the card that we want to use itself
        #if [[ -n "$arg" ]] && [[ "$arg" != -* ]] ; then
            #if echo "$list_cards" | grep -qs -- "$arg" ; then
                #list_cards="$arg"
            #fi
        #fi
        if [[ "$arg" = "--help" ]] ; then
            echo -e "Usage: $(basename $0) without arguments allows you to select the audio card to use"
            echo -e "--smart: performs a smart way to detect the correct audio card to use"
            echo -e "--auto: automatically selects the audio card to use"
            echo -e "--quiet: silent mode, not interactive at all"
            echo -e "--nomessages: do not show messages"
            echo -e "NAME: this allows to configure the audio card to the given parameter name of the audio card to use"
            exit
        fi
    done

    # no cards found
    if [[ -z "$list_cards" ]] ; then
        rm -f "${HOME}/.asoundrc"

        # reconfigure alsa.conf to defaults to correctly work, only if is not a number value
        if [[ "$UID" = 0 ]] ; then
            sed -i "s|^defaults.ctl.card.*$|defaults.ctl.card 0|g" /usr/share/alsa/alsa.conf
            sed -i "s|^defaults.pcm.card.*$|defaults.pcm.card 0|g" /usr/share/alsa/alsa.conf
        fi

        el_debug "no audio cards found"

        $guitool --warning --text="$( eval_gettext "No audio cards were detected on your computer. We suggest trying a different kernel version to see if it includes drivers for your audio card." )"

        exit
    fi

    number_cards="$( echo -e "$list_cards" | wc -l )"

    # only one card found
    if [[ "$number_cards" -eq "1" ]] ; then
        # bullseye and up works with ID instead of name
        if ((is_buster)) || ((is_wheezy)) ; then
            selection="$( echo "$list_cards" | sed -e 's|\].*$||g' -e 's|^.*\[||g')"
        else
            selection="$( echo "$list_cards" | awk '{print $1}' )"
        fi
        # remove extra leading blank chars
        read -r selection <<< "$selection"

        el_debug "only one card found, using $selection"
    else
        # more than one card found
        if ((is_auto_mode)) ; then

            #always kill pulseaudio first, otherwise we cannot list the audio cards
            if ((is_pulseaudio)) ; then
                el_pulseaudio stop
            fi

            el_dependencies_check "psort"

            # detect the optimal card based in their number of tracks
            unset array_cards
            while read -ru 3 line ; do
                rm -f "${HOME}/.asoundrc"
                [[ -z "$line" ]] && continue

                id="$( echo "$line" | awk '{print $1}' )"
                name="$( echo "$line" | sed -e 's|\].*$||g' -e 's|^.*\[||g')"
                read -r name <<< "$name"

                # note: this is needed to configure the amixer next command, based on the while loop psort
                if ((is_buster)) || ((is_wheezy)) ; then
                    echo "defaults.ctl.card ${name}" >> "${HOME}/.asoundrc"
                    echo "defaults.pcm.card ${name}" >> "${HOME}/.asoundrc"
                else
                    # bullseye and up works with ID instead of name
                    echo "defaults.ctl.card ${id}" >> "${HOME}/.asoundrc"
                    echo "defaults.pcm.card ${id}" >> "${HOME}/.asoundrc"
                fi


                # set a preferenced result
                if [[ "$selection" = DAC ]] || grep -qsE "\s*${selection}\s*\[\s*DAC\s*\]" "$asound_cards" ; then
                    preferenced="DAC"
                fi

                # make an array of the number of tracks :: name card
                array_cards="$( echo -e "${array_cards}" ; LC_ALL=C amixer 2>/dev/null | grep -i "Simple mixer control" | wc -l ) :: $name"
                el_debug "Tracks for $name\n$( LC_ALL=C amixer 2>/dev/null | grep -i "Simple mixer control" )"

            done 3<<< "$( echo "$list_cards" | sed -e '/^$/d'  )"

            array_cards="$( echo "${array_cards}" | sed -e '/^$/d' | sort -g )"

            # select the card that has most tracks
            # first detect the max number of tracks
            selection_number="$( echo "${array_cards}" | sed -e '/^$/d' | sort -ug | tac | psort -- -p ":: ThinkPadEC" -p ":: modem" -p ":: NVidia" -p ":: midi" -p ":: MIDI" -p ":: Webcam" -p ":: Dummy" -p ":: system" -p ":: Device" -p ":: HDMI" -p ":: Generic" | sed -e 's| :: .*$||g' -e '/^$/d' | head -n 1 )"

            # now pick the card with same max tracks by prior, like if we have MID and ThinkPadEC both as 2 (pulseaudio?) like in Venus computer
            selection="$( echo "${array_cards}" | sed -e '/^$/d' | sort -ug | grep -F "${selection_number} :: " | psort -- -p ":: ThinkPadEC" -p ":: modem" -p ":: NVidia" -p ":: midi" -p ":: MIDI" -p ":: Webcam" -p ":: Dummy" -p ":: system" -p ":: Device" -p ":: HDMI" -p ":: Generic" | sed -e 's|^.* :: ||g' -e '/^$/d' | tail -n 1 )"


            if [[ "$preferenced" = "DAC" ]] ; then
                # bullseye and up works with ID instead of name
                if ((is_buster)) || ((is_wheezy)) ; then
                    selection="DAC"
                else
                    selection="$( grep -E "\[\s*DAC\s*\]" "$asound_cards" | sed -e '/^$/d' | awk '{print $1}' | head -1 )"
                fi
                #fi
            else
                el_debug "we selected the card '$selection' from the list. From these 'amount-of-tracks :: card' results:\n$( echo "$array_cards" | sort -u )"
            fi

            # update: this message became useless especially after using pulseaudio
            #if [[ "$( echo "${array_cards}" | sort -g | grep -vE "^(1|2|3|4) ::" | sed '/^$/d' | wc -l )" -gt 1 ]] && ! ((is_nomessages)) ; then
                #$guitool --warning --text="$( eval_gettext "Seems like you have multiple audio cards, Elive has a smart way to detect the correct one to use. You can also reconfigure it manually from the applications menus of Elive." )"
            #fi

        else
            if ! select_card_multiple ; then
                if [[ -s "$HOME/.asoundrc" ]] ; then
                    # exit because is interactive and user canceled
                    exit
                else
                    $guitool --warning --text="$( eval_gettext "No audio card selected; nothing will be configured. Run this command to let Elive choose the best option:" ): $(basename $0) --auto"
                    exit
                    #is_auto_mode=1
                fi
            fi
        fi
    fi

    # cleanup, new conf
    rm -f "${HOME}/.asoundrc"

    # user's conf
    if [[ -e "$DHOME/.shared-home" ]] ; then
        if $guitool --question --text="$( eval_gettext "Your user-home directory is shared with another system, if you try to configure your audio card it may not work in the other system. In that case, you will need to remove the '.asoundrc' file later. Do you want to continue?" )" ; then
            if ((is_buster)) || ((is_wheezy)) ; then
                echo "defaults.ctl.card ${selection}" >> "${HOME}/.asoundrc"
                echo "defaults.pcm.card ${selection}" >> "${HOME}/.asoundrc"
            else
                id="$( echo "$list_cards" | grep -Ew "$selection" | sed -e 's|\[.*$||g' )"
                read -r id <<< "$id"
                echo "defaults.ctl.card ${id}" >> "${HOME}/.asoundrc"
                echo "defaults.pcm.card ${id}" >> "${HOME}/.asoundrc"
            fi
        fi
    else
        if ((is_buster)) || ((is_wheezy)) ; then
            echo "defaults.ctl.card ${selection}" >> "${HOME}/.asoundrc"
            echo "defaults.pcm.card ${selection}" >> "${HOME}/.asoundrc"
        else
            id="$( echo "$list_cards" | grep -Ew "$selection" | sed -e 's|\[.*$||g' )"
            read -r id <<< "$id"
            echo "defaults.ctl.card ${id}" >> "${HOME}/.asoundrc"
            echo "defaults.pcm.card ${id}" >> "${HOME}/.asoundrc"
        fi
    fi

    # reconfigure alsa.conf to our audio card
    if [[ "$UID" = 0 ]] && ! echo "$selection" | grep -qs "^[[:digit:]]*$" ; then
        if ((is_buster)) || ((is_wheezy)) ; then
            sed -i "s|^defaults.ctl.card.*$|defaults.ctl.card ${selection}|g" /usr/share/alsa/alsa.conf
            sed -i "s|^defaults.pcm.card.*$|defaults.pcm.card ${selection}|g" /usr/share/alsa/alsa.conf
        else
            id="$( echo "$list_cards" | grep -Ew "$selection" | sed -e 's|\[.*$||g' )"
            read -r id <<< "$id"
            sed -i "s|^defaults.ctl.card.*$|defaults.ctl.card ${id}|g" /usr/share/alsa/alsa.conf
            sed -i "s|^defaults.pcm.card.*$|defaults.pcm.card ${id}|g" /usr/share/alsa/alsa.conf
        fi
    fi


    # set microphone default
    if ! [[ -e "$DHOME/.shared-home" ]] ; then

        if ((is_auto_mode)) ; then
            if ((has_multiple_cards)) ; then

                if ((is_pulseaudio)) ; then
                    el_pulseaudio stop
                fi

                # backup for the loop
                cp -f "$HOME/.asoundrc" "$HOME/.asoundrc.bak"

                unset array_cards
                while read -ru 3 line ; do
                    rm -f "${HOME}/.asoundrc"
                    [[ -z "$line" ]] && continue

                    # note: this is needed to configure the amixer next command, based on the while loop psort
                    echo "defaults.ctl.card ${line}" >> "${HOME}/.asoundrc"
                    echo "defaults.pcm.card ${line}" >> "${HOME}/.asoundrc"

                    # add this card only if has a mic available
                    if LC_ALL=C amixer 2>/dev/null | grep -qsi "Simple mixer control.*'.*Mic" ; then
                        el_debug "the card $line is a good candidate for the extra microphone configuration"
                        array_cards="$( echo -e "${array_cards}" ; LC_ALL=C amixer 2>/dev/null | grep -Fi "Simple mixer control" | wc -l ) :: $line"
                        el_debug "Tracks for $line\n$( LC_ALL=C amixer 2>/dev/null | grep -i "Simple mixer control" )"
                    fi

                done 3<<< "$( echo "$list_cards" | sed -e '/^$/d'  )"

                array_cards="$( echo "${array_cards}" | sed -e '/^$/d' | sort -g )"

                # restore
                mv -f "$HOME/.asoundrc.bak" "$HOME/.asoundrc"

                # select the card that has most tracks
                # first detect the max number of tracks
                selection_number="$( echo "${array_cards}" | sort -g | sed -e 's| :: .*$||g' -e '/^$d/d' | psort -- -p "\[ThinkPadEC" -p "\[NVidia" -p "midi" -p "MIDI" -p "\[VX-5000" -p "\[VX5000" -p "\[Webcam" -p "\[Dummy" -p "\[Device" -p "\[HDMI" -p "Generic" -p "system" -p "Modem" | tail -1 )"

                # now pick the card with same max tracks by prior, like if we have MID and ThinkPadEC both as 2 (pulseaudio?) like in Venus computer
                selection="$( echo "${array_cards}" | sed -e '/^$/d' | sort -ug | grep -F "${selection_number} :: " | psort -- -p ":: ThinkPadEC" -p ":: modem" -p ":: NVidia" -p ":: midi" -p ":: MIDI" -p ":: Webcam" -p ":: Dummy" -p ":: system" -p ":: Device" -p ":: HDMI" -p ":: Generic" | sed -e 's|^.* :: ||g' -e '/^$/d' | tail -n 1 )"

                mic="$selection"
            fi
        else
            if ((has_multiple_cards)) || ((has_usb_audio)) ; then

                if ! $guitool --question --text="$( eval_gettext "Do you want to use the same audio card for the microphone?" )" ; then

                    select_card_multiple
                    mic="$selection"
                fi
            fi
        fi

        # append (important) mic conf
        if [[ -n "$mic" ]] ; then
            el_debug "configuring a different mic source to $mic"
            # bullseye and up works with ID instead of name
            if ((is_buster)) || ((is_wheezy)) ; then
                mic="$mic"
            else
                mic="$( grep -E "\[\s*${mic}\s*\]" "$asound_cards" | awk '{print $1}' | sed -e '/^$/d' | tail -1 )"
            fi

            cat >> "${HOME}/.asoundrc" << EOF

pcm.mic
{
    type hw
    card ${mic}
}

pcm.!default
{
    type asym
    playback.pcm
    {
        type plug
        slave.pcm "dmix"
    }
    capture.pcm
    {
        type plug
        slave.pcm "mic"
    }
}
EOF
            # syntax

        fi


        # TODO: remove --smart option, we ALWAYS want it to be smart! unless we don't want --auto

        # TODO: include a way to detect if mic is working, etc... maybe more easy to implement it on the C future mixer code
        #$guitool --info --text="$( eval_gettext "If you experience noise in your speakers, or your microphone doesn't capture anything, just play with the settings in your audio card mixer. Sometimes you need to enable the capture mode or set it to the microphone for make it working, and sometimes the microphone is repeated to your audio card giving you echo or noise, you can solve those problems trying different settings" )" || true


        reconfigure_applications

        # ALWAYS reconfigure audios (and mic capture and all) after to have configured a new card
        # we need to create the PCM channel! it doesn't exist until we do it
        timeout 5 aplay /dev/null 2>/dev/null
        if ((is_pulseaudio)) ; then
            el_pulseaudio start
        fi

        LC_ALL=C sleep 0.2

        if ! ((is_quiet_mode)) ; then
            # normal run by gui should always want to have volumes configured
            rm -f "${HOME}/.config/setvolume"
            ( setvolume $QUIET defaults & )

            $guitool --info --text="$( eval_gettext "Your audio card is ready, you can adjust the volume using keyboard shortcuts, and if those don't work, you can create your own, there's also a volume app in the Sound menu, or you can use the mouse wheel on the audio gadget on your desktop." )" || true
        fi

    fi
}

#
#  MAIN
#
main "$@"

# vim: set foldmethod=marker :


