#!/bin/bash

#################################################################################
# Enabling Raspberry Pi to run SmartThings direct-connected device applications
#                Master setup and configure bash script
#                           Version 0.20210406
#
# Copyright 2020 Todd A. Austin
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.                        
#
#################################################################################

# Global static variables
VERSION=".20210406"
rpimodel=""
osrelease=0
startdir=""

rpipkgdir="$HOME/rpi-st-device"
sdkpkgdir="$HOME/st-device-sdk-c"
stepsfile="$rpipkgdir/.stepstat"
devjsonfile="$sdkpkgdir/example/device_info.json"
onbjsonfile="$sdkpkgdir/example/onboarding_config.json"

todo="[to-do]"
done="[done]"

modellist=("a02082" "a22082" "a32082" "a020d3" "a03111" "b03111" "c03111" "b03112" "c03111" "c03112" "9000c1")

initstepst=("$todo" "$todo" "$todo" "$todo" "$todo" "$todo" "$todo" "$todo")
stepst=()
dispstepst=()
menuselect=""
keyresp=""
serialnum=""
jsonvalue=""

# Main menu display and input
showmenu() {

 local i=0
 local instr=""
 local numtest='^[0-9]+$'
 local goodinput=""

 for item in "${stepst[@]}"; do
  if [ $item == $todo ]; then
   dispstepst[i]="\e[93m$item\e[0m"
  else
   if [ $item == $done ]; then
    dispstepst[i]="\e[92m$item\e[0m"
   else
    dispstepst[i]="\e[0m$item"
   fi
  fi
  i=$((i+1))
 done

 echo -e "\e[0m"
 echo -e "\t======================================================="
 echo -e "\t                         \e[1m\e[97mMENU\e[0m"
 echo -e "\t======================================================="
 echo -e "\t 1. Install Pi enablement package \t\t${dispstepst[0]}"
 echo -e "\t 2. Install software dependencies \t\t${dispstepst[1]}"
 echo -e "\t 3. Install Core SDK \t\t\t\t${dispstepst[2]}"
 echo -e "\t 4. Build Core SDK \t\t\t\t${dispstepst[3]}"
 echo -e "\t 5. Register devices in Developer Workspace \t${dispstepst[4]}"
 echo -e "\t 6. Build example device app \t\t\t${dispstepst[5]}"
 echo -e "\t 7. Configure Pi for SoftAP \t\t\t${dispstepst[6]}"
 echo -e "\t 8. On-board example device app\t\t\t${dispstepst[7]}"
 echo -e "\t======================================================="
 echo -en "\n\t\e[95mEnter a step number or q to quit:\e[0m  "

 goodinput="no"
 while [ "$goodinput" == "no" ]; do
  read instr

  if [ "$instr" == "q" ]; then goodinput="yes"; fi

  if [[ $instr =~ $numtest ]]; then
    if [[ $instr -ge 1  && $instr -le 8 ]]; then goodinput="yes"; fi
  fi
 done
 echo
 menuselect=$instr

}

# Write out step status file
updatestatfile() {

  if [ "${stepst[0]}" == "$done" ]; then
    echo "${stepst[@]}" > $stepsfile
  fi  
 return 0
}

getyesno() {

 local keyin=""

 while [[ "$keyin" != "y" && "$keyin" != "n" ]]
 do
  read -rsn1 keyin
 done

 echo -e "$keyin\n"
 keyresp=$keyin

}

# Parse json file for item/value
# Input $1=json filename, $2=item to search for; sets jsonvalue to found value
getjsonitem() {
  
  filen=$1
  srchitem=$2
  local output
  local jsonarray=()
  local itemarr=()
  local item
  local savIFS
  local founditem
  local fflag=0
    
  output=$(cat $filen)
  readarray jsonarray <<< $output
  
  for item in "${jsonarray[@]}"; do
    if [[ "$item" == *"$srchitem"* ]]; then
      savIFS=$IFS
      IFS=':'
      read -a itemarr <<< $item
      IFS=$savIFS
      founditem="${itemarr[1]}"
      fflag=1
    fi
  done

  if [ $fflag -eq 1 ]; then
    jsonvalue=${founditem#*'"'}
    jsonvalue=${jsonvalue%'"'*}
    return 0
  else
    return 1
  fi

}

# Execute git clone for given package URL
clonepkg() {

  step=$1
  URL=$2
  
  savIFS=$IFS
  IFS='/'
  read -a path <<< "$URL"

  IFS='.'
  read -a dname <<< "${path[4]}"
  IFS=$savIFS
  PKGDIR=$HOME/${dname[0]}

  cd "$HOME"
  output=$(git clone "$URL" 2>&1)
  errnum=$?

  if [ $errnum -eq 0 ]
    then

      # Confirm that the respository directory now exists

      if [ -d $PKGDIR ]; then
        echo -e "\n\t\e[92mInstallation successful\e[0m\n"
        stepst[step]=$done
        
        if [ $step -eq 0 ]; then
        
          echo -e "\n\n\e[96mPLEASE RESTART mastersetup NOW (cd ~/rpi-st-device && ./mastersetup)\e[0m\n"
          updatestatfile
          exit 0
        fi
        
      else
        echo -e "\n\t\e[91mSomething went wrong: path to package not found\e[0m\n"
      fi

    else
      if [[ "$output" == *"already exists"* ]]
        then
          stepst[step]=$done
        
          echo -e "\t\e[0m  >> It looks like the package is already installed\n"
          echo -en "\t\e[96m  >> Do you want to pull the latest available files? (y/n): \e[0m"
          getyesno
          echo

          if [ $keyresp == "y" ]; then

            cd $PKGDIR
            
            if [[ "$URL" =~ "st-device-sdk-c" ]]; then
              output=$(git pull origin master)
            else
              output=$(git pull origin main)
            fi
            
            echo $output
            errnum=$?

            if [ $errnum -eq 0 ]; then
              if [ $step -eq 0 ]; then
              
                if [[ "$output" =~ "mastersetup" ]]; then
                  echo -e "\n\n\e[96mPLEASE RESTART mastersetup NOW (./mastersetup)\e[0m\n"
                  updatestatfile
                  exit 0
                fi
              fi
            else
              echo -e "\n\t\e[91mgit reported error number: $errnum\n"
            fi
          fi

        else
          echo -e "\n\t\e[91mgit reported error number: $errnum\n"
          echo -e "\t$output\e[0m\n"
      fi
  fi

  return 0
}

#Create QR code image file for device serial in SDK example dir
createqr() {

  local retcode=1
  
  echo -e "\n\t\e[97mCreating QRCODE for your device\e[0m"
        
  cd "$sdkpkgdir/tools/qrgen"
              
  qroutput=$(python3 stdk-qrgen.py --folder "$sdkpkgdir/example/")
  errnum=$?
              
  if [ $errnum == 0 ]; then
    savIFS=$IFS
    IFS=":"
    read -a outarr <<< ${qroutput[0]}
    IFS=$savIFS
              
    if [ "${outarr[0]}" == "File" ]; then
      qrfname="${outarr[1]}"
      qrfname=${qrfname//[[:space:]]/}
                
      if [ -f "$sdkpkgdir/tools/qrgen/$qrfname" ]; then
                
        cp "$sdkpkgdir/tools/qrgen/$qrfname" "$sdkpkgdir/example/$qrfname"
        echo -e "\t\e[92m$qrfname copied to $sdkpkgdir/example/ directory"
        retcode=0
                  
      else
        echo -e "\n\t\e[91m$qrfname not found\e[0m"
      fi            
    else
      echo -e "\n\t\e[91mUnexpected results from stdk_qrgen\e[0m"
    fi
  else
    echo -e "\n\t\e[91mqrcode tool failed with error #$errnum\e[0m"
  fi
  
  cd "$rpipkgdir"
  return $retcode

}

# Check hardware model, Raspbian & Python versions
verifysys() {

  local rpirevision
  local rpimodel
  local pyver
  local pyvernum
  local verarr
  local savIFS

  # Check what hardware we're running on

  rpirevision=$(cat /proc/cpuinfo | grep "Revision" | cut -f2 -d" ")
  if [[ ! "${modellist[@]}" =~ "${rpirevision}" ]]
    then
      echo -e "\n\t\e[91m\n\tThis Raspberry Pi model not tested or supported\e[0m"
      return 1
    else
      rpimodel=$(cat /proc/cpuinfo | grep "Model" | cut -f2 -d":")
      echo -e "\t\e[92mModel:$rpimodel... OK"
  fi

  # Check what OS version we're running on

  osrelease=$(cat /etc/os-release | grep "VERSION_ID" | cut -f2 -d"=")
  osrelease="${osrelease%\"}"
  osrelease="${osrelease#\"}"
  if [ $osrelease -le 8 ]
    then
      echo -e "\n\t\e\91m\nYour OS version is too old; must be Version 8 or later\e[0m"
      return 1
    else
      rpios=$(cat /etc/os-release | grep "PRETTY_NAME" | cut -f2 -d"=")
      echo -e "\t\e[92mO/S: $rpios... OK"
  fi

  # Check what version of Python3 is installed

  pyver=$(python3 --version)
  read -a pyvernum <<< "$pyver"
  savIFS=$IFS
  IFS='.'
  read -a verarr <<< "${pyvernum[1]}"
  IFS=$savIFS

  if [ ${verarr[1]} -ge 5 ]; then
    echo -e "\t\e[92m$pyver... OK\n\e[0m"
  else
    echo -e "\n\t\e\91m\nYour Python version is too old; must be Version 3.5 or later\e[0m"
    return 1
  fi

  return 0
}

########################################################################
#              Functions for each step in the menu
########################################################################
# Install RPI enablement package
step1() {

  echo -e "\n\t\e[97mInstalling Pi enablement package from github\n\e[0m"

  clonepkg 0 "https://github.com/toddaustin07/rpi-st-device.git"

  if [[ "${stepst[0]}" == "$done" && "$startdir" != "$rpipkgdir" ]]; then
      echo -e "\t\e[93m>> From now on, run this setup script from the"
      echo -e "\t   \e[97m$rpipkgdir\e[93m directory\e[0m"
      echo -e "\t\e[0m>> You can continue for now"
      if [ -f "$HOME/mastersetup" ]; then rm "$HOME/mastersetup"; fi
      cd $rpipkgdir
  fi
  
  return 0
}

# Install all software libs required by SDK
step2() {

  echo -e "\n\t\e[97mInstalling software dependencies - watch for errors...\n\e[0m"

  bash $rpipkgdir/installSDKdeps

  echo -ne "\n\n\t\e[95mDid you encounter any errors or additional dependencies? (y/n): "
  getyesno

  if [ $keyresp == "y" ]
    then
      echo -e "\n\t\e[93m>>Manually install your missing dependencies and then try again\e[0m\n"
    else
      stepst[1]=$done
  fi

  return 0
}

# Clone SmartThings core SDK
step3() {

  echo -e "\n\t\e[97mCloning SmartThings Core SDK from github\n\e[0m"

  clonepkg 2 "https://github.com/SmartThingsCommunity/st-device-sdk-c.git"

  return 0
}

# Build the Core SDK
step4() {

  echo -e "\n\t\e[97mBuilding SmartThings Core SDK\n\e[0m"
 
  bash $rpipkgdir/sdkbuildsetup
  
  cd "$sdkpkgdir"
  make
  errnum=$?
  
  if [ $errnum -eq 0 ]; then
    if [[ -f output/libiotcore.a ]]; then
      echo -e "\n\t\e[92mCore SDK built: ~/st-device-sdk-c/output/libiotcore.a\e[0m\n"
      stepst[3]=$done
    else
      echo -e "\n\t\e[91mSomething seems to have gone wrong.  Correct errors and retry.\e[0m\n"
    fi  
  else
    echo -e "\n\t\e[91mMake reported error # $errnum. Correct errors and retry.\e[0m\n"
  fi
  cd "$rpipkgdir"  
  return 0
}

# Perform Developer Workspace tasks and obtain needed json files
step5() {
  
  local cmdoutput=()
  local errnum=0
  local i=0

  # Save existing json files
  
  if [ -f "ORIG_$onbjsonfile" ]; then
    cp "$onbjsonfile" "$onbjsonfile""_SAVED"
  else
    cp "$onbjsonfile" "$onbjsonfile""_ORIG"
  fi

  if [ -f "ORIG_$devjsonfile" ]; then
    cp "$devjsonfile" "$devjsonfile""_SAVED"
  else
    cp "$devjsonfile" "$devjsonfile""_ORIG"
  fi
  

  chromium-browser community.smartthings.com/t/how-to-build-direct-connected-devices/204055 >/dev/null 2>&1 &
  
  echo -e "\n\t\e[97mRegister Project in Samsung SmartThings Develper Workspace\e[0m"
  
  echo -e "\tFollow the instructions outlined in the SmartThings Community post to set up"
  echo -e "\tyour example device in the Developer Workspace. (displayed now in browser window)"
  echo -e "\tBegin with section \e[1m2.1\e[22m 'Create a new project' - continuing to and including"
  echo -e "\tsection \e[1m2.5\e[22m 'Deploy Your Device to Test'"
  
  echo -en "\n\t\e[95mPress any key once you have completed those steps\e[0m "
  read -rsn1 keyin
  echo
  
  echo -e "\n\t\e[0mWe will now create a new device serial number and key for your test device"
  echo -en "\t\e[95mPress '\e[97mc\e[95m' to continue or '\e[97ms\e[95m' to skip\e[0m "
  
  keyin=""
  while [[ "$keyin" != "c" && "$keyin" != "s" ]]; do
    read -rsn1 keyin
  done
  echo
  
  if [ "$keyin" == "c" ]; then
  
    echo -e "\n\t\e[0mUse the serial number and public key generated below to complete the instructions"
    echo -e "\tin section \e[97m2.6\e[0m 'Register Test Devices'"
  
    cd "$sdkpkgdir/tools/keygen"
    output=$(python3 stdk-keygen.py --firmware switch_example_001)
    errnum=$?
  
    echo -e "-------------------------------------------------------"
    echo "$output"
    echo -e "-------------------------------------------------------"
  
    if [ $errnum -eq 0 ]; then
      echo -en "\n\t\e[95mPress any key once you've entered these into Developer Workspace\e[0m "
      read -rsn1 keyin
      echo
    
      while read -r line; do
        cmdoutput[i]="$line"
        i=$((i+1))
      done <<< "$output"

      i=0
      while [ "${cmdoutput[$i]}" != "Serial Number:" ]; do i=$((i+1)); done
      i=$((i+1))
      serialnum="${cmdoutput[i]}"
      sndir="output_$serialnum"
    
      if [ -f "$sdkpkgdir/tools/keygen/$sndir/device_info.json" ]; then
    
        cp "$sdkpkgdir/tools/keygen/$sndir/device_info.json" "$devjsonfile"
        errnum=$?
        if [ $errnum -eq 0 ]; then
        
          echo -e "\n\t\e[92mdevice_info.json copied to \e[97m~/st-device-sdk-c/example\e[92m directory\e[0m"

        else
          echo -e "\n\e[91mError copying device_info.json file to SDK example directory\e[0m"      
        fi
      else
        echo -e "\n\e[91mdevice_info.json file is missing\e[0m"
      fi
    else
      echo -e "\n\t\e[91mKeygen tool failed with error #$errnum\e[0m"
    fi
  fi
  
  echo -e "\n\t\e[0mNow finish device profile & registration in Samsung SmartThings Developer Workspace"
  echo -e "\t\e[0m>> Download \e[97monboarding_config.json\e[0m to \e[97m~/st-device-sdk-c/example\e[0m directory<<"
        
  echo -en "\n\t\e[95mPress any key once you have downloaded \e[97monboarding_config.json \e[0m"
  read -rsn1 keyin
  echo
        
  if [ -f "$onbjsonfile" ]; then
          
    getjsonitem "$onbjsonfile" "deviceOnboardingId"
    errnum=$?
          
    if [[ $errnum -eq 0 && "$jsonvalue" != "NAME" ]]; then

      echo -e "\t\e[0m$onbjsonfile \e[92m...VERIFIED\e[0m"
      stepst[4]=$done
                
    else
      echo -e "\n\t\e[91mSorry, but onboarding_config.json doesn't look updated\e[0m"
    fi
  else
    echo -e "\n\t\e[91monboarding_config.json is missing from $sdkpkgdir/example\e[0m"
  fi
      
}

# Build the SDK example application
step6() {
 
  echo -e "\n\t\e[97mBuilding example application\n\e[0m"
 
  cd "$sdkpkgdir"/example
  rm example
  make
  errnum=$?
  
  if [ $errnum == 0 ]; then
  
    echo -en "\n\t\e[95mDid you have any errors (\e[0my/n\e[95m)? \e[0m"
    getyesno
    
    if [ "$keyresp" == "n" ]; then
    
      echo -e "\n\t\e[92mExample application successfully created\e[0m"
      
      createqr
      
      if [ $? == 0 ]; then
        stepst[5]=$done
      fi
    else
      echo -e "\n\t\e[93mCorrect source of errors and try again\e[0m"
    fi
  else
    echo -e "\n\t\e[91mError #$errnum reported by make\e[0m"
  fi
}

# Configure system for SoftAP - call SoftAPconfig bash script
step7() {
 
  cd "$rpipkgdir"
  
  echo -e "\n\t\e[97mRaspberry Pi SoftAP Configuration\e[0m"
  
  echo -e "\n\t\e[0mLaunching configuration script with \e[93mroot\e[0m privileges...\n"
  
  sudo ./SoftAPconfig
  errnum=$?
  
  case $errnum in
    -1)
       echo -e "\n\t\e[91mSoftAP configuration failed\e[0m"
       ;;
     0)
       echo -e "\n\t\e[92mSoftAP Successfully Configured\e[0m"
       stepst[6]=$done
       ;;
     1)
       echo -e "\n\t\e[93mSoftAP configuration not complete\e[0m"
       ;;
  esac
  
} 

# Onboard the example device
step8() {
  
  echo -e "\n\t\e[97mPrepare to onboard your device!\e[0m"
  echo -e "\n\tOpen the SmartThings mobile app and begin the '\e[97mAdd Device\e[0m' process"
  echo -en "\n\t\e[95mPress any key once you have tapped '\e[97mScan QR code\e[0m' "
  read -rsn1 keyin
  echo 
  
  cd "$sdkpkgdir/example"
  
  getjsonitem "./device_info.json" "serialNumber"
  if [ $? ]; then
    pngfile="./$jsonvalue.png"
    if [ -f "$pngfile" ]; then
      
      gpicview "$pngfile" &
      
      echo -e "\n\t\e[97mStarting example application...\e[0m\n"
      
      ./example &
      
      stepst[7]=$done
      
      menuselect="q"
      
    else
      echo -e "\n\t\e[91mQR code file is missing; cannot display\e[0m"
    fi
  else
      echo -e "\n\t\e[91mUnexpected error getting device serial number\e[0m"
  fi
  
}
  
##########################################################################
#
#								- MAIN -
#
##########################################################################

# Save directory we're running from

startdir=$(pwd)

# Load step status from file if exists, otherwise initialize with defaults
if [ -f $stepsfile ]; then
  read -a stepst <$stepsfile
else
  stepst=("${initstepst[@]}")
fi

# If RPI package is installed, make sure we're running in that directory
if [ "${stepst[0]}" == "$done" ]; then
  if [[ "$startdir" != "$rpipkgdir" ]]; then
    cd "$rpipkgdir"
  fi
fi

echo -e "\n\t\e[97mInstall and configure Raspberry Pi support for"
echo -e "\tSamsung SmartThings direct-connected device applications\e[0m"
echo -e "\tVersion $VERSION"

echo -e "\n\t\e[4mCHECKING YOUR SYSTEM:\e[0m"

# Check hardware, Raspbian, and Python versions
verifysys
if [ $? -ne 0 ]; then
  exit 1;
fi

aptgetflag=0

# Check that git is installed; if not, install it

output=$(apt-cache policy git 2>&1)

if [[ "$output" =~ "Installed: (none)" ]]; then

  echo -e "\n\t\e[97mRunning apt-get update\n\e[0m"
  sudo apt-get update -y
  aptgetflag=1
  
  echo -e "\n\t\e[97mInstalling git\n\e[0m"
  sudo apt-get install git -y

fi

# Check that pip3 is installed; if not, install it

output=$(apt-cache policy python3-pip 2>&1)

if [[ "$output" =~ "Installed: (none)" ]]; then

  if [ $aptgetflag -eq 0 ]; then
    echo -e "\n\t\e[97mRunning apt-get update\n\e[0m"
    sudo apt-get update -y
  fi

  echo -e "\n\t\e[97mInstalling pip3\n\e[0m"
  sudo apt-get install python3-pip -y

fi

output=$(apt-cache policy python3-pip 2>&1)

if [[ "$output" =~ "Installed: (none)" ]]; then

  echo -e "\n\t\e[97mInstalling pip3\n\e[0m"
  sudo apt-get install python3-pip -y

fi

#####################################
#   **** MENU DISPLAY LOOP ****
#####################################

while [ "$menuselect" != "q" ]
  do
    showmenu

    proc="y"

    if [ "$menuselect" != "q" ]; then
      ix=$((menuselect-1))
      if [ ${stepst[ix]} == $done ]
        then
          echo -en "\n\t\e[93mAre you sure you want to repeat this step? (y/n):\e[0m "
          getyesno
          echo
          if [ "$keyresp" == "n" ]
            then
              proc="n"
            else
              stepst[ix]=$todo
          fi
      fi
    fi

    if [[ "$proc" == "y" && "$menuselect" != "q" ]]
      then
        pix=$((ix-1))
        if [[ $ix -gt 0 && "${stepst[pix]}" != "$done" ]]
          then
            echo -e "\n\t\e[93mComplete the previous steps first!\n"

          else
            case $menuselect in
              1)
                step1
                ;;
              2)
                step2
                ;;
              3)
                step3
                ;;
              4)
                step4
                ;;
              5)
                step5
                ;;
              6)
                step6
                ;;
              7)
                step7
                ;;
              8)
                step8
                ;;
              *)
                echo -e "\nShould never get here"
                ;;
            esac
        
            updatestatfile
        
        fi
    fi
  done


# Save step status to a file in ~/rpi-st-devices

updatestatfile

echo -e "\n\e[0mGoodbye\n"

exit 0
