#!/bin/bash

# Original script: https://github.com/adafruit/Raspberry-Pi-Installer-Scripts/blob/3f690b22562532043511db41612a413ddb79def6/adafruit-pitft.sh

if [ $(id -u) -ne 0 ]; then
	echo "Installer must be run as root."
	echo "Try 'sudo $0'"
	exit 1
fi

UPDATE_DB=false

############################ CALIBRATIONS ############################
# For TSLib
POINTERCAL_35r0="181 5535 -1233392 8414 -54 -2101452 65536"
POINTERCAL_35r90="-8366 40 33311824 -44 5641 -1241260 65536"
POINTERCAL_35r180="46 -5510 21796950 -8419 71 33201648 65536"
POINTERCAL_35r270="8546 20 -2351776 -24 -5609 22071332 65536"

# for PIXEL desktop
TRANSFORM_35r0="0.02644844 1.09212689 -0.05913211 1.09379104 -0.00933442 -0.05932366 0 0 1"
TRANSFORM_35r90="-1.0785622 0.00306008 1.05346097 0.00458963 1.08934868 -0.05384451 0 0 1"
TRANSFORM_35r180="-0.00942871 -1.09373643 1.05284711 -1.09157968 0.00689662 1.05683189 0 0 1"
TRANSFORM_35r270="1.09554746 -0.00161413 -0.06123539 -0.00698696 -1.09622346  1.04912691 0 0 1"

warning() { 
	echo WARNING : $1
}

############################ Script assisters ############################

# Given a list of strings representing options, display each option
# preceded by a number (1 to N), display a prompt, check input until
# a valid number within the selection range is entered.
selectN() {
	for ((i=1; i<=$#; i++)); do
		echo $i. ${!i}
	done
	echo
	REPLY=""
	while :
	do
		echo -n "SELECT 1-$#: "
		read
		if [[ $REPLY -ge 1 ]] && [[ $REPLY -le $# ]]; then
			return $REPLY
		fi
	done
}


function print_version() {
    echo "RPI-MON2 Config Utility"
    exit 1
}

function print_help() {
    echo "Usage: $0 "
    echo "    -h            Print this help"
    echo "    -v            Print version information"
    echo "    -u [homedir]  Specify path of primary user's home directory (defaults to /home/pi)"
    exit 1
}

group=ADAFRUIT
function info() {
    system="$1"
    group="${system}"
    shift
    FG="1;32m"
    BG="40m"
    echo -e "[\033[${FG}\033[${BG}${system}\033[0m] $*"
}

function bail() {
    FG="1;31m"
    BG="40m"
    echo -en "[\033[${FG}\033[${BG}${group}\033[0m] "
    if [ -z "$1" ]; then
        echo "Exiting due to error"
    else
        echo "Exiting due to error: $*"
    fi
    exit 1
}

function ask() {
    # http://djm.me/ask
    while true; do

        if [ "${2:-}" = "Y" ]; then
            prompt="Y/n"
            default=Y
        elif [ "${2:-}" = "N" ]; then
            prompt="y/N"
            default=N
        else
            prompt="y/n"
            default=
        fi

        # Ask the question
        read -p "$1 [$prompt] " REPLY

        # Default?
        if [ -z "$REPLY" ]; then
            REPLY=$default
        fi

        # Check if the reply is valid
        case "$REPLY" in
            Y*|y*) return 0 ;;
            N*|n*) return 1 ;;
        esac
    done
}


# Given a filename, a regex pattern to match and a replacement string,
# perform replacement if found, else append replacement to end of file.
# (# $1 = filename, $2 = pattern to match, $3 = replacement)
reconfig() {
	grep $2 $1 >/dev/null
	if [ $? -eq 0 ]; then
		# Pattern found; replace in file
		sed -i "s/$2/$3/g" $1 >/dev/null
	else
		# Not found; append (silently)
		echo $3 | sudo tee -a $1 >/dev/null
	fi
}


############################ Sub-Scripts ############################

# update /boot/config.txt with appropriate values
function update_configtxt() {
    if [ ! -f /boot/config.txt.bu ]; then
        cp /boot/config.txt /boot/config.txt.bu
    fi

    if grep -q "pishop-tft-helper" "/boot/config.txt"; then
        echo "Already have an pishop-tft-helper section in /boot/config.txt."
        echo "Removing old section..."
        sed -i -e "/^# --- added by pishop-tft-helper/,/^# --- end pishop-tft-helper/d" /boot/config.txt
    fi

    overlay="dtoverlay=piscreen,rotate=${pitftrot},speed=24000000,fps=30"
    date=`date`

    cat >> /boot/config.txt <<EOF
# --- added by pishop-tft-helper $date ---
dtparam=spi=on
dtparam=i2c1=on
dtparam=i2c_arm=on
$overlay
# --- end pishop-tft-helper $date ---
EOF
}

function update_pointercal() {
    echo $(eval echo "\$POINTERCAL_$pitfttype$pitftrot") > /etc/pointercal
}

function install_console() {
    echo "Set up main console turn on"
    if ! grep -q 'fbcon=map:10 fbcon=font:VGA8x8' /boot/cmdline.txt; then
        echo "Updating /boot/cmdline.txt"
        sed -i 's/rootwait/rootwait fbcon=map:10 fbcon=font:VGA8x8/g' "/boot/cmdline.txt"
    else
        echo "/boot/cmdline.txt already updated"
    fi

    echo "Turning off console blanking"
    # pre-stretch this is what you'd do:
    if [ -e /etc/kbd/config ]; then
      sed -i 's/BLANK_TIME=.*/BLANK_TIME=0/g' "/etc/kbd/config"
    fi
    # as of stretch....
    # removing any old version
    sed -i -e '/^# disable console blanking.*/d' /etc/rc.local
    sed -i -e '/^sudo sh -c "TERM=linux setterm -blank.*/d' /etc/rc.local
    sed -i -e "s|^exit 0|# disable console blanking on PiTFT\\nsudo sh -c \"TERM=linux setterm -blank 0 >/dev/tty0\"\\nexit 0|" /etc/rc.local

    reconfig /etc/default/console-setup "^.*FONTFACE.*$" "FONTFACE=\"Terminus\""
    reconfig /etc/default/console-setup "^.*FONTSIZE.*$" "FONTSIZE=\"6x12\""

    echo "Setting raspi-config to boot to console w/o login..."
    (cd ~pi && raspi-config nonint do_boot_behaviour B2)
}


function uninstall_console() {
    echo "Removing console fbcon map from /boot/cmdline.txt"
    sed -i 's/rootwait fbcon=map:10 fbcon=font:VGA8x8/rootwait/g' "/boot/cmdline.txt"
    echo "Screen blanking time reset to 10 minutes"
    if [ -e "/etc/kbd/config" ]; then
      sed -i 's/BLANK_TIME=0/BLANK_TIME=10/g' "/etc/kbd/config"
    fi
    sed -i -e '/^# disable console blanking.*/d' /etc/rc.local
    sed -i -e '/^sudo sh -c "TERM=linux.*/d' /etc/rc.local

    echo "Setting raspi-config to boot to desktop w/o login..."
    (cd ~pi && raspi-config nonint do_boot_behaviour B4)
}

progress() {
    count=0
    until [ $count -eq $1 ]; do
        echo -n "..." && sleep 1
        ((count++))
    done
    echo
}

function install_fbcp() {
    if [ ! -f /usr/local/bin/fbcp ]; then
        echo "Updating apt indexes..."
        sudo apt-get update 1> /dev/null || { warning "Apt failed to update indexes!" && exit 1; }

        echo "Installing required packages..."
        apt-get install -y cmake curl 1> /dev/null  || { warning "Apt failed to install software!" && exit 1; }

        echo "Downloading rpi-fbcp..."
        curl -sLO https://github.com/adafruit/rpi-fbcp/archive/master.zip

        echo "Uncompressing rpi-fbcp..."
        rm -rf /tmp/rpi-fbcp-master
        unzip master.zip 1> /dev/null  || { warning "Failed to uncompress fbcp!" && exit 1; }
        cd rpi-fbcp-master
        mkdir build
        cd build

        echo "Building rpi-fbcp..."
        cmake ..  1> /dev/null  || { warning "Failed to cmake fbcp!" && exit 1; }
        make  1> /dev/null  || { warning "Failed to make fbcp!" && exit 1; }

        echo "Installing rpi-fbcp..."
        install fbcp /usr/local/bin/fbcp
        
        cd ~
        rm -rf /tmp/rpi-fbcp-master
    fi

    if [ ! -f /boot/config.fbcp ]; then
        cp /boot/config.txt /boot/config.fbcp
    fi

    # Add fbcp to /rc.local:
    echo "Add fbcp to /etc/rc.local..."
    grep fbcp /etc/rc.local >/dev/null
    if [ $? -eq 0 ]; then
        # fbcp already in rc.local, but make sure correct:
        sed -i "s|^.*fbcp.*$|/usr/local/bin/fbcp \&|g" /etc/rc.local >/dev/null
    else
        #Insert fbcp into rc.local before final 'exit 0'
        sed -i "s|^exit 0|/usr/local/bin/fbcp \&\\nexit 0|g" /etc/rc.local >/dev/null
    fi

    # Disable overscan compensation (use full screen):
    raspi-config nonint do_overscan 1

    # Set up HDMI parameters:
    echo "Configuring boot/config.txt for forced HDMI"
    reconfig /boot/config.txt "^.*hdmi_force_hotplug.*$" "hdmi_force_hotplug=1"
    reconfig /boot/config.txt "^.*hdmi_group.*$" "hdmi_group=2"
    reconfig /boot/config.txt "^.*hdmi_mode.*$" "hdmi_mode=87"

    # if there's X11 installed...
    if [ -e /etc/lightdm ]; then
        if [ "${pitfttype}" == "35r" ]; then
            echo "Using x1.5 resolution"
            SCALE=1.5
        else
            echo "Using x2 resolution"
            SCALE=2.0
        fi
    else
        echo "Using native resolution"
        SCALE=1
    fi

    WIDTH=`python3 -c "print(int(${WIDTH_VALUES[PITFT_SELECT-1]} * ${SCALE}))"`
    HEIGHT=`python3 -c "print(int(${HEIGHT_VALUES[PITFT_SELECT-1]} * ${SCALE}))"`
    reconfig /boot/config.txt "^.*hdmi_cvt.*$" "hdmi_cvt=${WIDTH} ${HEIGHT} 60 1 0 0 0"

    if [ "${pitftrot}" == "90" ] || [ "${pitftrot}" == "270" ]; then
        # dont rotate HDMI on 90 or 270
        reconfig /boot/config.txt "^.*display_hdmi_rotate.*$" ""
    fi

    if [ "${pitftrot}" == "0" ]; then
        reconfig /boot/config.txt "^.*display_hdmi_rotate.*$" "display_hdmi_rotate=1"
        # this is a hack but because we rotate HDMI we have to 'unrotate' the TFT!
        pitftrot=90
        update_configtxt || bail "Unable to update /boot/config.txt"
        pitftrot=0
    fi

    if [ "${pitftrot}" == "180" ]; then
        reconfig /boot/config.txt "^.*display_hdmi_rotate.*$" "display_hdmi_rotate=3"
        # this is a hack but because we rotate HDMI we have to 'unrotate' the TFT!
        pitftrot=90
        update_configtxt || bail "Unable to update /boot/config.txt"
        pitftrot=180
    fi

}

function uninstall_fbcp() {
    # Remove fbcp from /etc/rc.local:
    echo "Remove fbcp from /etc/rc.local..."
    sed -i -e '/^.*fbcp.*$/d' /etc/rc.local

    # Enable overscan compensation
    raspi-config nonint do_overscan 0

    # Set up HDMI parameters:
    echo "Configuring boot/config.txt for default HDMI"
    if [ -f /boot/config.fbcp ]; then
        rm /boot/config.txt && mv /boot/config.fbcp /boot/config.txt
    else
        reconfig /boot/config.txt "^.*hdmi_force_hotplug.*$" "hdmi_force_hotplug=0"
        sed -i -e '/^hdmi_group=2.*$/d' /boot/config.txt
        sed -i -e '/^hdmi_mode=87.*$/d' /boot/config.txt
        sed -i -e '/^hdmi_cvt=.*$/d' /boot/config.txt
    fi
}

function update_xorg() {
	matrix=$(eval echo "\$TRANSFORM_$pitfttype$pitftrot")
	transform="Option \"TransformationMatrix\" \"${matrix}\""
        cat > /usr/share/X11/xorg.conf.d/20-calibration.conf <<EOF
Section "InputClass"
        Identifier "ADS7846 Touchscreen Calibration"
        MatchProduct "ADS7846 Touchscreen"
        MatchDevicePath "/dev/input/event*"
        Driver "libinput"
        ${transform}
EndSection
EOF
}

function install_fbturbo() {
    cat > /usr/share/X11/xorg.conf.d/99-fbtft.conf <<EOF
Section "Device"  
  Identifier "myfb"
  Driver "fbturbo"
  Option "fbdev" "/dev/fb1"
EndSection
EOF
}

function uninstall_fbturbo() {
    rm -f /usr/share/X11/xorg.conf.d/99-fbtft.conf
}

####################################################### MAIN

echo "This script downloads and installs"
echo "TFT Support using userspace touch"
echo "controls and a DTO for display drawing."
echo "one of several configuration files."
echo "Run time of up to 5 minutes. Reboot required!"
echo

PITFT_SELECT=4

echo "Select rotation:"
selectN "90 degrees (landscape - USBs to RIGHT)" \
        "180 degrees (portait - USBs at BOTTOM)" \
        "270 degrees (landscape - USBs to LEFT)" \
        "0 degrees (portait - USBs at TOP)"
PITFT_ROTATE=$?
if [ $PITFT_ROTATE -gt 4 ]; then
    exit 1
fi

echo

PITFT_ROTATIONS=("90" "180" "270" "0")
PITFT_TYPES=("28r" "22" "28c" "35r")
WIDTH_VALUES=(320 320 320 480)
HEIGHT_VALUES=(240 240 240 320)
HZ_VALUES=(64000000 64000000 64000000 32000000)

args=$(getopt -uo 'hvri:o:b:u:' -- $*)
[ $? != 0 ] && print_help
set -- $args

for i
do
    case "$i"
    in
        -h)
            print_help
            ;;
        -v)
            print_version
            ;;
    esac
done

# check init system (technique borrowed from raspi-config):
info TFT 'Checking init system...'
if command -v systemctl > /dev/null && systemctl | grep -q '\-\.mount'; then
  echo "Found systemd"
  SYSTEMD=1
elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then
  echo "Found sysvinit"
  SYSTEMD=0
else
  bail "Unrecognised init system"
fi

if grep -q boot /proc/mounts; then
    echo "/boot is mounted"
else
    echo "/boot must be mounted. if you think it's not, quit here and try: sudo mount /dev/mmcblk0p1 /boot"
    if ask "Continue?"; then
        echo "Proceeding."
    else
        bail "Aborting."
    fi
fi

pitfttype=${PITFT_TYPES[$PITFT_SELECT-1]}
pitftrot=${PITFT_ROTATIONS[$PITFT_ROTATE-1]}

info TFT "Updating /boot/config.txt..."
update_configtxt || bail "Unable to update /boot/config.txt"

info TFT "Updating default calibrations..."
update_pointercal || bail "Unable to update /etc/pointercal"

echo
if [ -e /etc/lightdm ] && ask "Show the GUI on the TFT display?"; then
    update_xorg || bail "Unable to update Xorg calibration"
    uninstall_console || bail "Unable to configure console"

    echo
    if ask "Use HDMI Mirroring? (lower FPS but supports more software)"; then
        info TFT "Disabling fbturbo..."
        uninstall_fbturbo || bail "Failed to remove fbturbo config"

        info TFT "Enabling FBCP..."
        install_fbcp || bail "Unable to configure fbcp"
    else
        info TFT "Disabling FBCP..."
        uninstall_fbcp  || bail "Unable to uninstall fbcp"

        info TFT "Enabling fbturbo..."
        install_fbturbo || bail "Failed to update fbturbo config"
    fi
else 
    info TFT "Disabling fbturbo..."
    uninstall_fbturbo || bail "Failed to remove fbturbo config"

    info TFT "Disabling FBCP..."
    uninstall_fbcp  || bail "Unable to uninstall fbcp"

    echo
    if ask "Show the console on the TFT display?"; then
        info TFT "Updating console to TFT..."
        install_console || bail "Unable to configure console"
    else
        info TFT "Making sure console doesn't use TFT"
        uninstall_console || bail "Unable to configure console"
    fi
fi

info TFT "Success!"
echo
echo "Settings take effect on next boot."
echo
echo -n "REBOOT NOW? [y/N] "
read
if [[ ! "$REPLY" =~ ^(yes|y|Y)$ ]]; then
	echo "Exiting without reboot."
	exit 0
fi
echo "Reboot started..."
reboot
exit 0
