#!/usr/bin/env bash

#*******************************************************************************
#
# Bare Conductive Pi Cap Debian Package
# -------------------------------------
#
# picap-setup.sh - configures all aspects of Pi Cap installation
#                  can be re-run after install to clean up / reset
#
# Written by Szymon Kaliski.
#
# This work is licensed under a MIT license https://opensource.org/licenses/MIT
#
# Copyright (c) 2016, Bare Conductive
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
#*******************************************************************************

# let's halt on any error

set -e

# can't be run as root

if [ "$EUID" -eq 0 ]; then
  echo -e "This utility needs to be run as user to work."
  exit 1
fi

# consts

PI_VERSION=$(printf "from RPi import GPIO\nprint GPIO.RPI_INFO['TYPE']" | python)
REQUIRED_NODE_VERSION="6.7.0"

# ugly global variable

ASK_TO_REBOOT="no"
CURRENT_NODE_VERSION=""
DEFAULT_NODE_VERSION=""

# helpers

function ask_user_question {
  echo -e -n "$(tput setaf 6)$1 $(tput sgr0)[y/n] " | fold -w 80 -s
  read -r -e
  echo
}

# functions

function hardware_setup {
  echo "$(tput setaf 3)Pi Cap Setup Script$(tput sgr0)"
  echo
  echo "$(tput setaf 3)We're setting up hardware, so you may be asked for a sudo password.$(tput sgr0)"
  echo

  CONFIG="/boot/config.txt"
  BLACKLIST="/etc/modprobe.d/raspi-blacklist.conf"
  TARGET_SETTING="on"

  CURRENT_SETTING="off" # assume disabled
  if [ -e "$CONFIG" ] && grep -q -E "^(device_tree_param|dtparam)=([^,]*,)*i2c(_arm)?(=(on|true|yes|1))?(,.*)?$" $CONFIG; then
    CURRENT_SETTING="on"
  fi

  TARGET_SETTING="on"
  if [ "$TARGET_SETTING" != "$CURRENT_SETTING" ]; then
    ASK_TO_REBOOT="yes"
  fi

  sudo sed "$CONFIG" -i -r -e "s/^((device_tree_param|dtparam)=([^,]*,)*i2c(_arm)?)(=[^,]*)?/\1=$TARGET_SETTING/"

  if ! grep -q -E "^(device_tree_param|dtparam)=([^,]*,)*i2c(_arm)?=[^,]*" "$CONFIG"; then
    (printf "dtparam=i2c_arm=%s\n" "$TARGET_SETTING" | sudo tee -a "$CONFIG") > /dev/null 2>&1
  fi

  if ! [ -e "$BLACKLIST" ]; then
    sudo touch "$BLACKLIST"
  fi

  sudo sed "$BLACKLIST" -i -e "s/^\(blacklist[[:space:]]*i2c[-_]bcm2708\)/#\1/"
  sudo sed /etc/modules -i -e "s/^#[[:space:]]*\(i2c[-_]dev\)/\1/"

  if ! grep -q "^i2c[-_]dev" /etc/modules; then
    (printf "i2c-dev\n" | sudo tee -a /etc/modules) > /dev/null 2>&1
  fi

  sudo modprobe i2c-bcm2708
  sudo modprobe i2c-dev
}

function cp_examples {
  EXAMPLES_PATH="$HOME/PiCapExamples"

  ask_user_question "Would you like to copy example code into $EXAMPLES_PATH?"

  if [[ "$REPLY" =~ ^[Yy]$ ]]; then
    install-picap-examples "$EXAMPLES_PATH"

    echo "Sample code copied to $EXAMPLES_PATH."
  else
    echo "You can always copy them later using the $(tput setaf 3)install-picap-examples$(tput sgr 0) command."
  fi

  echo
}

function setup_hq_audio {
  ask_user_question "We recommend setting up high-quality audio, do you want to do this now?"

  if [[ "$REPLY" =~ ^[Yy]$ ]]; then
    CONFIG_PWM_COMMENT="# set high-quality PWM audio"
    CONFIG_PWM_LINE="audio_pwm_mode=2"
    CONFIG_FILE_PATH="/boot/config.txt"

    sudo sed -i -e "s/#$CONFIG_PWM_LINE/$CONFIG_PWM_LINE/g" "$CONFIG_FILE_PATH"
    sudo sed -i -e "\|$CONFIG_PWM_LINE|h; \${x;s|$CONFIG_PWM_LINE||;{g;t};a\\" -i -e "\n$CONFIG_PWM_COMMENT\n$CONFIG_PWM_LINE" -i -e "}" "$CONFIG_FILE_PATH"

    if amixer | grep PCM > /dev/null
    then
      amixer cset numid=3 1 > /dev/null
      amixer sset PCM,0 90% > /dev/null
      AMIXER_SUCCESS="yes"
    elif amixer | grep Headphone > /dev/null
    then
      amixer cset numid=2 1 > /dev/null
      amixer sset Headphone,0 90% > /dev/null
      AMIXER_SUCCESS="yes"
    fi

    ASK_TO_REBOOT="yes"

    if [ "$AMIXER_SUCCESS" == "yes" ]
    then
      echo "High Quality audio enabled."
    else
      echo "Error enabling High Quality audio. This program will continue, but audio may not be enabled."
    fi
    echo
  fi
}

function pi_zero_audio {
  if [[ "$PI_VERSION" =~ "Zero" ]]; then
    echo "$(tput setaf 3)Running on RPI Zero, mapping audio to Pi Cap for you...$(tput sgr0)"

    sudo DONT_REBOOT=1 map-audio-to-picap
    ASK_TO_REBOOT="yes"

    echo
  fi
}

function upsert_nvm_node {
  ask_user_question "Our Node.js examples require Node.js v$REQUIRED_NODE_VERSION. This has not been detected on your system.\
 We can install this using NVM (downloading it if necessary) while leaving your current version of Node.js untouched.\n\nWould you\
 like us to do this?\n\nIf you don't plan on using the Node.js examples, you can safely answer No.\nIf you want to manage versions of\
 Node.js yourself, you can safely answer No.\nIf you want to use the Node.js examples but would like us to make sure they \"just work\",\
 we would advise you to answer Yes."

  if [[ "$REPLY" =~ ^[Yy]$ ]]; then
    echo -n "Installing Node.js v$REQUIRED_NODE_VERSION... "

    # NVM wasn't detected or has been deleted
    if [[ ! -v NVM_DIR || ! -d "$NVM_DIR" ]]; then
      wget -qO- "https://raw.githubusercontent.com/creationix/nvm/v0.32.0/install.sh" | bash  > /dev/null 2>&1
      export NVM_DIR="/home/pi/.nvm"
    fi

    # ensure NVM is loaded
    [ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh" > /dev/null
    nvm install $REQUIRED_NODE_VERSION > /dev/null 2>&1

    if [[ -z "$DEFAULT_NODE_VERSION" ]] && [[ -z "$CURRENT_NODE_VERSION" ]]; then
      nvm alias default "$REQUIRED_NODE_VERSION" > /dev/null    # and make it default
    elif [[ -z "$DEFAULT_NODE_VERSION" ]]; then
      nvm alias default system > /dev/null                      # make sure default "node" calls are not affected by our actions
    else
      nvm alias default $DEFAULT_NODE_VERSION > /dev/null       # restore default node version
    fi

    ASK_TO_REBOOT="yes"

    echo "done."
    echo
  fi
}

function upsert_node {
  if [[ ! -v NVM_DIR || ! -d "$NVM_DIR" ]]; then                # NVM wasn't detected
    upsert_nvm_node
  else
    if ! type -t nvm ls > /dev/null; then
      [ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh"      # ensure NVM is loaded
    fi

    NVM_LS=$(nvm ls --no-colors)

    if ! echo $NVM_LS | grep -q $REQUIRED_NODE_VERSION; then    # NVM detected, but doesn't have the required version of node
      if nvm version default > /dev/null; then                  # make sure we only record a valid version, not "N/A"
        DEFAULT_NODE_VERSION=$(nvm version default)
      fi
      upsert_nvm_node
    fi
  fi
}

function setup_node {
  if ! hash node 2> /dev/null; then
    # no node at all
    upsert_node
  elif [[ ! $(dpkg --compare-versions $(node --version | tr -d [:alpha:]) "ge" $REQUIRED_NODE_VERSION) ]]; then
    # system node is not up-to-date
    CURRENT_NODE_VERSION=$(node --version)
    upsert_node
  fi
}

#install python packages from pip that aren't available on apt
function pip_install {
  if hash pip 2>/dev/null; then
    sudo pip install python-uinput
  else
    echo "We were unable to detect pip installed on your system, so python-uinput for Python 2 has not been installed. This means the picap-keyboard-py example won't work, but all the other examples will work."
  fi
  if hash pip3 2>/dev/null; then
    sudo pip3 install python-uinput
  else
    echo "We were unable to detect pip3 installed on your system, so python-uinput for Python 3 has not been installed. This means the picap-keyboard-py example won't work, but all the other examples will work."
  fi
}

# run main code

hardware_setup
setup_hq_audio
pi_zero_audio
cp_examples
setup_node
pip_install

# note about picap-intro

echo "Run $(tput setaf 3)picap-intro$(tput sgr 0) for a feature tour!"
echo

# reboot if needed

if [ "$ASK_TO_REBOOT" == "yes" ]; then
  echo "Important system-level things changed."
  echo "You'll need to reboot before this takes effect."

  ask_user_question "Would you like to do this now?"

  if [[ "$REPLY" =~ ^[Yy]$ ]]; then
    echo "$(tput setaf 1)Rebooting...$(tput sgr 0)"
    sudo reboot
  else
    echo "Run $(tput setaf 3)sudo reboot$(tput sgr 0) to restart."
    echo
  fi
fi

exit 0
