#!/bin/bash

detect_installs() {
    #OctoPi will be the most common so do a search for that:
    if [ -f "/etc/octopi_version" ]; then
        echo "OctoPi installation detected."
        echo "Adding standard OctoPi instance to instance list."
        echo "instance:octoprint port:5000 udev:false" >> /etc/octoprint_instances
        echo "octoexec: /home/$user/oprint/bin/octoprint" >> /etc/octoprint_deploy
        echo "octopip: /home/$user/oprint/bin/pip" >> /etc/octoprint_deploy
        echo "haproxy: true" >> /etc/octoprint_deploy
        echo "octopi: true" >> /etc/octoprint_deploy
        echo "Adding systemctl and reboot to sudo"
        echo "$user ALL=NOPASSWD: /usr/bin/systemctl" > /etc/sudoers.d/octoprint_systemctl
        echo "$user ALL=NOPASSWD: /usr/sbin/reboot" > /etc/sudoers.d/octoprint_reboot
        INSTANCE=octoprint
        apt-get update
        deb_packages
        #rename
        
        #detect
        echo "If you plan to have multiple printers on your Pi it is helpful to assign printer udev rules."
        echo "This will make sure the correct printer is associated with each OctoPrint instance."
        echo "This can also be done in the Utility menu at a later time."
        get_settings
        if prompt_confirm "${green}Would you like to generate a udev rule now?${white}"; then
            echo "Unplug your printer from the USB connection now."
            if prompt_confirm "${green}Ready to begin printer auto-detection?${white}"; then
                detect_printer
                printer_udev false
                printer_udev true
                udevadm control --reload-rules
                udevadm trigger
                sudo -u $user $OCTOEXEC config set serial.port /dev/octo_$INSTANCE
                sudo -u $user $OCTOEXEC config append_value serial.additionalPorts "/dev/octo_$INSTANCE"
                #convert UDEV to true
                sed -i "s/udev:false/udev:true/" /etc/octoprint_instances
                systemctl restart $INSTANCE
            fi
            
        fi
        #streamer_install
        echo "streamer: camera-streamer" >> /etc/octoprint_deploy
        main_menu
    fi
    
    echo "Searching home directory for existing OctoPrint venv/binary....."
    octopresent=$(find /home/$user/ -type f -executable -print | grep "bin/octoprint")
    if [ -n "$octopresent" ]; then
        echo "OctoPrint binary found at $octopresent"
        echo "Did you try and setup OctoPrint in another way?"
        echo "${red}This may cause issues!${white}"
        : '
        PS3="${green}Select option number: ${white}"
        options=("Use existing binary" "Install most recent OctoPrint" "More information")
        select opt in "${options[@]}"
        do
            case $opt in
                "Use existing binary")
                    OCTOEXEC=$octopresent
                    break
                ;;
                "Install most recent OctoPrint")
                    OCTOEXEC=thing
                    break
                ;;
                "More information")
                    exit 1
                ;;
                *) echo "invalid option $REPLY";;
            esac
        done
        '
    else
        echo "No OctoPrint binary found in the current user's home directory. Doing complete install."
        FULLINSTALL=1
    fi
    FULLINSTALL=1
    echo "Looking for existing OctoPrint systemd files....."
    #get any service files that have bin/octoprint
    readarray -t syspresent < <(fgrep -l bin/octoprint /etc/systemd/system/*.service)
    prepare
}

#https://askubuntu.com/questions/39497
deb_packages() {
    #All extra packages needed can be added here for deb based systems. Only available will be selected.
    apt-cache --generate pkgnames \
    | grep --line-regexp --fixed-strings \
    -e make \
    -e v4l-utils \
    -e python-is-python3 \
    -e python3-venv \
    -e python3.9-venv \
    -e python3.10-venv \
    -e python3.11-venv \
    -e python3.11-dev \
    -e virtualenv \
    -e python3-dev \
    -e build-essential \
    -e python3-setuptools \
    -e libyaml-dev \
    -e python3-pip \
    -e cmake \
    -e libjpeg8-dev \
    -e libjpeg62-turbo-dev \
    -e gcc \
    -e g++ \
    -e libevent-dev \
    -e libjpeg-dev \
    -e libbsd-dev \
    -e ffmpeg \
    -e uuid-runtime\
    -e ssh\
    -e libffi-dev\
    -e haproxy\
    -e libavformat-dev\
    -e libavutil-dev\
    -e libavcodec-dev\
    -e libcamera-dev\
    -e libcamera-tools\
    -e libcamera-v4l2\
    -e liblivemedia-dev\
    -e v4l-utils\
    -e pkg-config\
    -e xxd\
    -e build-essential\
    -e libssl-dev\
    -e rsync\
    | xargs apt-get install -y
    
    #pacakges to REMOVE go here
    apt-cache --generate pkgnames \
    | grep --line-regexp --fixed-strings \
    -e brltty \
    | xargs apt-get remove -y
    
}

dnf_packages() {
    #untested
    dnf install -y \
    gcc \
    python3-devel \
    cmake \
    libjpeg-turbo-devel \
    libbsd-devel \
    libevent-devel \
    haproxy \
    openssh \
    openssh-server \
    libffi-devel \
    libcamera-devel \
    v4l-utils \
    xxd \
    openssl-devel \
    rsync
    
}

pacman_packages() {
    pacman -S --noconfirm --needed \
    make \
    cmake \
    python \
    python-virtualenv \
    libyaml \
    python-pip \
    libjpeg-turbo \
    python-yaml \
    python-setuptools \
    libffi \
    ffmpeg \
    gcc \
    libevent \
    libbsd \
    openssh \
    haproxy \
    v4l-utils \
    rsync
}

zypper_packages() {
    zypper in -y \
    gcc \
    python3-devel \
    cmake \
    libjpeg-devel \
    libbsd-devel \
    libevent-devel \
    haproxy \
    openssh \
    openssh-server \
    libffi-devel \
    v4l-utils \
    xxd \
    libopenssl-devel \
    rsync
    
}

user_groups() {
    
    echo 'Adding current user to dialout and video groups.'
    usermod -a -G dialout,video $user
    
    if [ $INSTALL -eq 4 ]; then
        usermod -a -G uucp,video $user
    fi
}

prepare () {
    echo
    echo
    
    PS3="${green}Installation type: ${white}"
    local options=("Ubuntu 20+, Mint, Debian, Raspberry Pi OS" "Fedora/CentOS" "ArchLinux" "openSUSE" "Quit")
    select opt in "${options[@]}"
    do
        case $opt in
            "Ubuntu 20+, Mint, Debian, Raspberry Pi OS")
                INSTALL=2
                break
            ;;
            "Fedora/CentOS")
                INSTALL=3
                break
            ;;
            "ArchLinux")
                INSTALL=4
                break
            ;;
            "openSUSE")
                INSTALL=5
                break
            ;;
            "Quit")
                exit 1
            ;;
            *) echo "invalid option $REPLY";;
        esac
    done
    
    if prompt_confirm "Ready to begin?"; then
        
        #CHOICE HERE between new_install or directly to haproxy/streamer based on if existing binary is used
        if [ -n "$FULLINSTALL" ]; then
            new_install
        else
            old_install
        fi
        
    fi
    main_menu
}

old_install() {
    echo "octoexec:$octopresent" >> /etc/octoprint_deploy
    user_groups
    haproxy_install
    streamer_install
    #add existing instance(s) to /etc/octoprint_instances
}

new_install() {
    user_groups
    OCTOEXEC=/home/$user/OctoPrint/bin/octoprint
    echo "Adding systemctl and reboot to sudo"
    echo "$user ALL=NOPASSWD: /usr/bin/systemctl" > /etc/sudoers.d/octoprint_systemctl
    echo "$user ALL=NOPASSWD: /usr/sbin/reboot" > /etc/sudoers.d/octoprint_reboot
    echo "This will install necessary packages, install OctoPrint and setup an instance."
    #install packages
    #All DEB based
    PYVERSION="python3"
    if [ $INSTALL -eq 2 ]; then
        apt-get update > /dev/null
        PYV=$(python3 -c"import sys; print(sys.version_info.minor)")
        #if [ $PYV -gt 11 ]; then
        #    PYVERSION='python3.11'
        #fi
        deb_packages
    fi
    
    #Fedora35/CentOS
    if [ $INSTALL -eq 3 ]; then
        echo "Fedora and variants have SELinux enabled by default."
        echo "This causes a fair bit of trouble for running OctoPrint."
        echo "You have the option of disabling this now."
        if prompt_confirm "${green}Disable SELinux?${white}"; then
            sed -i s/^SELINUX=.*$/SELINUX=disabled/ /etc/selinux/config
            echo "${magenta}You will need to reboot after system preparation.${white}"
        fi
        systemctl enable sshd.service
        PYV=$(python3 -c"import sys; print(sys.version_info.minor)")
        if [ $PYV -gt 11 ]; then
            dnf -y install python3.11-devel
            PYVERSION='python3.11'
        fi
        dnf_packages
    fi
    
    #ArchLinux
    if [ $INSTALL -eq 4 ]; then
        pacman_packages
    fi
    
    if [ $INSTALL -eq 5 ]; then
        zypper_packages
        systemctl enable sshd.service
    fi
    
    echo "Enabling ssh server..."
    systemctl enable ssh.service
    echo "Installing OctoPrint virtual environment in /home/$user/OctoPrint"
    #make venv
    sudo -u $user $PYVERSION -m venv /home/$user/OctoPrint
    #update pip
    sudo -u $user /home/$user/OctoPrint/bin/pip install --upgrade pip
    #pre-install wheel
    sudo -u $user /home/$user/OctoPrint/bin/pip install wheel
    #install oprint
    sudo -u $user /home/$user/OctoPrint/bin/pip install OctoPrint

    #limits fix, remove when OctoPrint 1.11.0 is released
    #sudo -u $user /home/$user/OctoPrint/bin/pip install limits==4.7.2
    
    #Check to verify that OctoPrint binary is installed
    if [ -f "/home/$user/OctoPrint/bin/octoprint" ]; then
        echo "${cyan}OctoPrint apppears to have been installed successfully${white}"
    else
        echo "${red}WARNING! WARNING! WARNING!${white}"
        echo "OctoPrint has not been installed correctly."
        echo "Please answer Y to remove everything and try running prepare system again."
        remove_everything
        exit
    fi
    
    haproxy_install
    streamer_install
    
    #These will retreived as settings
    echo "octoexec: /home/$user/OctoPrint/bin/octoprint" >> /etc/octoprint_deploy
    echo "octopip: /home/$user/OctoPrint/bin/pip" >> /etc/octoprint_deploy
    
    #Create first instance
    echo
    echo
    echo
    echo
    echo "${cyan}It is time to create your first OctoPrint instance!!!${white}"
    new_instance true
    echo
    echo
    if prompt_confirm "Would you like to install recommended plugins now?"; then
        plugin_menu
    fi
    
}

haproxy_install() {

    echo
    echo
    echo 'You have the option of setting up haproxy.'
    echo 'This binds instances to a name on port 80 instead of having to type the port.'
    echo
    echo
    if prompt_confirm "Use haproxy?"; then
        echo 'haproxy: true' >> /etc/octoprint_deploy
        #Check if using improved haproxy rules
        #echo 'haproxynew: true' >> /etc/octoprint_deploy
        systemctl stop haproxy
        #get haproxy version
        HAversion=$(haproxy -v | sed -n 's/^.*version \([0-9]\).*/\1/p')
        mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.orig
        if [ $HAversion -gt 1 ]; then
            cp $SCRIPTDIR/haproxy2x.basic /etc/haproxy/haproxy.cfg
        else
            cp $SCRIPTDIR/haproxy1x.basic /etc/haproxy/haproxy.cfg
        fi
        systemctl start haproxy
        systemctl enable haproxy
    else
        systemctl stop haproxy
        systemctl disable haproxy
    fi
    
    echo
    echo
    echo
}

streamer_install() {
    PS3="${green}Which video streamer you would like to install?: ${white}"
    options=("ustreamer (recommended)" "camera-streamer" "None/Skip")
    select opt in "${options[@]}"
    do
        case $opt in
            "mjpeg-streamer")
                VID=1
                break
            ;;
            "ustreamer (recommended)")
                VID=2
                break
            ;;
            "camera-streamer")
                VID=4
                break
            ;;
            "None/Skip")
                VID=3
                break
            ;;
            *) echo "invalid option $REPLY";;
        esac
    done
    
    #If we run this function directly, clean up streamer setting before installing
    get_settings
    sed -i "/streamer/d" /etc/octoprint_deploy
    
    if [ $VID -eq 1 ]; then
        rm -rf /home/$user/mjpg_streamer 2>/dev/null
        #install mjpg-streamer, not doing any error checking or anything
        echo 'Installing mjpeg-streamer'
        sudo -u $user git -C /home/$user/ clone https://github.com/jacksonliam/mjpg-streamer.git mjpeg
        #apt -y install
        sudo -u $user make -C /home/$user/mjpeg/mjpg-streamer-experimental > /dev/null
        
        sudo -u $user mv /home/$user/mjpeg/mjpg-streamer-experimental /home/$user/mjpg-streamer
        sudo -u $user rm -rf /home/$user/mjpeg
        if [ -f "/home/$user/mjpg-streamer/mjpg_streamer" ]; then
            echo "Streamer installed successfully"
        else
            echo "${red}WARNING! WARNING! WARNING!${white}"
            echo "Streamer has not been installed correctly."
            if prompt_confirm "Try installation again?"; then
                streamer_install
            fi
        fi
        echo 'streamer: mjpg-streamer' >> /etc/octoprint_deploy
    fi
    
    if [ $VID -eq 2 ]; then
        rm -rf /home/$user/ustreamer 2>/dev/null
        #install ustreamer
        sudo -u $user git -C /home/$user clone --depth=1 https://github.com/pikvm/ustreamer
        sudo -u $user make -C /home/$user/ustreamer > /dev/null
        if [ -f "/home/$user/ustreamer/ustreamer" ] || [ -f "/home/$user/ustreamer/ustreamer.bin" ]; then
            echo "Streamer installed successfully"
        else
            echo "${red}WARNING! WARNING! WARNING!${white}"
            echo "Streamer has not been installed correctly."
            if prompt_confirm "Try installation again?"; then
                streamer_install
            fi
        fi
        if [ -f "/home/$user/ustreamer/ustreamer.bin" ]; then
            sudo -u $user ln -s /home/$user/ustreamer/ustreamer.bin /home/$user/ustreamer/ustreamer
        fi
        echo 'streamer: ustreamer' >> /etc/octoprint_deploy
    fi
    
    if [ $VID -eq 4 ]; then
        rm -rf /home/$user/camera-streamer 2>/dev/null
        #install camera-streamer
        sudo -u $user git -C /home/$user clone https://github.com/ayufan-research/camera-streamer.git --recursive
        sudo -u $user make -C /home/$user/camera-streamer > /dev/null
        if [ -f "/home/$user/camera-streamer/camera-streamer" ]; then
            echo "Streamer installed successfully"
        else
            echo "${red}WARNING! WARNING! WARNING!${white}"
            echo "Streamer has not been installed correctly."
            if prompt_confirm "Try installation again?"; then
                streamer_install
            fi
        fi
        echo 'streamer: camera-streamer' >> /etc/octoprint_deploy
    fi
    
    if [ $VID -eq 3 ]; then
        echo 'streamer: none' >> /etc/octoprint_deploy
        echo "Good for you! Cameras are just annoying anyway."
    fi
    
}

firstrun_install() {
    echo
    echo
    echo 'The first instance can be configured at this time.'
    echo 'This includes setting up the admin user and finishing the startup wizards.'
    echo
    echo
    if prompt_confirm "Do you want to setup your admin user now?"; then
        while true; do
            echo 'Enter admin user name (no spaces): '
            read OCTOADMIN
            if [ -z "$OCTOADMIN" ]; then
                echo -e "No admin user given! Defaulting to: \033[0;31moctoadmin\033[0m"
                OCTOADMIN=octoadmin
            fi
            if ! has-space "$OCTOADMIN"; then
                break
            else
                echo "Admin user name must not have spaces."
            fi
        done
        echo "Admin user: ${cyan}$OCTOADMIN${white}"
        
        while true; do
            echo 'Enter admin user password (no spaces): '
            read OCTOPASS
            if [ -z "$OCTOPASS" ]; then
                echo -e "No password given! Defaulting to: ${cyan}fooselrulz${white}. Please CHANGE this."
                OCTOPASS=fooselrulz
            fi
            
            if ! has-space "$OCTOPASS"; then
                break
            else
                echo "Admin password cannot contain spaces"
            fi
            
        done
        echo "Admin password: ${cyan}$OCTOPASS${white}"
        sudo -u $user $OCTOEXEC --basedir $BASE user add $OCTOADMIN --group admins --password $OCTOPASS
    fi
    
    if [ -n "$OCTOADMIN" ]; then
        echo
        echo
        echo "The script can complete the first run wizards now."
        echo "For more information on these, see the OctoPrint website."
        echo "It is standard to accept this, as no identifying information is exposed through their usage."
        echo
        echo
        if prompt_confirm "Complete first run wizards now?"; then
            sudo -u $user $OCTOEXEC --basedir $BASE config set server.firstRun false --bool
            sudo -u $user $OCTOEXEC --basedir $BASE config set server.seenWizards.backup null
            sudo -u $user $OCTOEXEC --basedir $BASE config set server.seenWizards.corewizard 4 --int
            sudo -u $user $OCTOEXEC --basedir $BASE config set server.onlineCheck.enabled true --bool
            sudo -u $user $OCTOEXEC --basedir $BASE config set server.pluginBlacklist.enabled true --bool
            sudo -u $user $OCTOEXEC --basedir $BASE config set plugins.tracking.enabled true --bool
            sudo -u $user $OCTOEXEC --basedir $BASE config set printerProfiles.default _default
        fi
    fi
    
    echo "Restarting instance....."
    systemctl restart $INSTANCE
}

