#!/bin/bash
#
# This script is to generate a complete configuration file needed for the bondbridge plugin
# This script can handle up to 3 independent BondBridge (BB) systems
#
# This script can be invoked in two ways:  
# 1. from homebridge customUI
#
# 2. from a terminal
#
UIversion="customUI"

BBIP1="${1}"
BBtoken1="${2}"
CFsetupOption1="${3}"
CFtimerSetup1="${4}"
BBdebug1="${5}"
BBIP2="${6}"
BBtoken2="${7}"
CFsetupOption2="${8}"
CFtimerSetup2="${9}"
BBdebug2="${10}"
BBIP3="${11}"
BBtoken3="${12}"
CFsetupOption3="${13}"
CFtimerSetup3="${14}"
BBdebug3="${15}"
BONDBRIDGE_SH_PATH="${16}"

# Initialize some JSON varialbles
myPlaceConstantsBB="{}"
myPlaceQueueTypesBB="{}"
myPlaceAccessoriesBB="{}"

# fun color stuff
BOLD=$(tput bold)
TRED=$(tput setaf 1)
TGRN=$(tput setaf 2)
TYEL=$(tput setaf 3)
TPUR=$(tput setaf 5)
TLBL=$(tput setaf 6)
TNRM=$(tput sgr0)

function myPlaceBasicKeys()
{
   myPlaceBasicKeys="{}"
   myPlaceBasicKeys=$( echo "${myPlaceBasicKeys}" | jq ".title |= \"MyPlace configuration generated by Configuration Creator\"" \
                                                  | jq ".debug |= ${debugMyPlace}" \
                                                  | jq ".outputConstants |= false" \
                                                  | jq ".statusMsg |= true" \
                                                  | jq ".timeout |= 60000" \
                                                  | jq ".stateChangeResponseTime |= 0" )
}

function myPlaceConstants()
{
   local debugA=""

   if [ "${debug}" = "true" ]; then
      debugA="-debug"
   fi

   myPlaceConstants="{}"
   myPlaceConstants=$( echo "${myPlaceConstants}" | jq ".key |= \"${ip}\"" \
                                                  | jq ".value |= \"${IPA}${debugA}\"" )

   myPlaceConstantsBB=$( echo "${myPlaceConstantsBB}" | jq ".constants += [${myPlaceConstants}]" )
}

function myPlaceQueueTypes()
{
   myPlaceQueueTypes="{}"
   myPlaceQueueTypes=$( echo "${myPlaceQueueTypes}" | jq ".queue |= \"${queue}\"" \
                                                    | jq ".queueType |= \"WoRm2\"" )

   myPlaceQueueTypesBB=$( echo "${myPlaceQueueTypesBB}" | jq ".queueTypes += [${myPlaceQueueTypes}]" )
}

function myPlaceModelQueue()
{
   myPlaceModelQueue="{}"
   myPlaceModelQueue=$( echo "${myPlaceModelQueue}" | jq ".manufacturer |= \"OLIBRA\"" \
                                                    | jq ".model |= \"${model}\"" \
                                                    | jq ".serialNumber |= \"${bondid}\"" \
                                                    | jq ".queue |= \"${queue}\"" )
}

function myPlaceFan()
{
   local name="$1"
   local minStep="${2}"
                  
   myPlaceFan="{}"
   myPlaceFan=$( echo "${myPlaceFan}" | jq ".type |= \"Fan\"" \
                                      | jq ".displayName |= \"${name}\"" \
                                      | jq ".on |= false" \
                                      | jq ".rotationSpeed |= 25" \
                                      | jq ".name |= \"${name}\"" \
                                      | jq ". += ${myPlaceModelQueue}" \
                                      | jq ".polling[0].characteristic |= \"on\"" \
                                      | jq ".polling[1].characteristic |= \"rotationSpeed\"" \
                                      | jq ".props.rotationSpeed.minStep |= ${minStep}" \
                                      | jq ".state_cmd |= \"'${BONDBRIDGE_SH_PATH}'\"" \
                                      | jq ".state_cmd_suffix |= \"fan 'token:${bondToken}' 'device:${device}' ${ip}\"" )

   myPlaceAccessoriesBB=$( echo "${myPlaceAccessoriesBB}" | jq ".accessories += [${myPlaceFan}]" )
}

function myPlaceLightbulbNoDimmer()
{
   local name="$1"
   local accType="${2}"
                 
   myPlaceLightbulbNoDimmer="{}"
   myPlaceLightbulbNoDimmer=$( echo "${myPlaceLightbulbNoDimmer}" | jq ".type |= \"Lightbulb\"" \
                                                                  | jq ".displayName |= \"${name}\"" \
                                                                  | jq ".on |= false" \
                                                                  | jq ".name |= \"${name}\"" \
                                                                  | jq ". += ${myPlaceModelQueue}" \
                                                                  | jq ".polling[0].characteristic |= \"on\"" \
                                                                  | jq ".state_cmd |= \"'${BONDBRIDGE_SH_PATH}'\"" \
                                                                  | jq ".state_cmd_suffix |= \"${accType} 'token:${bondToken}' 'device:${device}' ${ip}\"" )

   myPlaceAccessoriesBB=$( echo "${myPlaceAccessoriesBB}" | jq ".accessories += [${myPlaceLightbulbNoDimmer}]" )
}

function myPlaceLightbulbWithDimmer()
{
   local name="$1"
   local accType="${2}"
   local minStep="${3}"
                   
   myPlaceLightbulbWithDimmer="{}"
   myPlaceLightbulbWithDimmer=$( echo "${myPlaceLightbulbWithDimmer}" | jq ".type |= \"Lightbulb\"" \
                                                                      | jq ".displayName |= \"${name}\"" \
                                                                      | jq ".on |= false" \
                                                                      | jq ".brightness |= 80" \
                                                                      | jq ".name |= \"${name}\"" \
                                                                      | jq ". += ${myPlaceModelQueue}" \
                                                                      | jq ".polling[0].characteristic |= \"on\"" \
                                                                      | jq ".polling[1].characteristic |= \"brightness\"" \
                                                                      | jq ".props.brightness.minStep |= ${minStep}" \
                                                                      | jq ".state_cmd |= \"'${BONDBRIDGE_SH_PATH}'\"" \
                                                                      | jq ".state_cmd_suffix |= \"${accType} 'token:${bondToken}' 'device:${device}' ${ip}\"" )

   myPlaceAccessoriesBB=$( echo "${myPlaceAccessoriesBB}" | jq ".accessories += [${myPlaceLightbulbWithDimmer}]" )
}

function myPlaceTimerLightbulb()
{
   local name="$1"
   local accType="$2"
   local deviceType="$3"

   myPlaceTimerLightbulb="{}"
   myPlaceTimerLightbulb=$( echo "${myPlaceTimerLightbulb}" | jq ".type |= \"Lightbulb\"" \
                                                            | jq ".displayName |= \"${name}\"" \
                                                            | jq ".on |= false" \
                                                            | jq ".brightness |= 0" \
                                                            | jq ".name |= \"${name}\"" \
                                                            | jq ". += ${myPlaceModelQueue}" \
                                                            | jq ".polling[0].characteristic |= \"on\"" \
                                                            | jq ".polling[1].characteristic |= \"brightness\"" \
                                                            | jq ".props.brightness.minStep |= 1" \
                                                            | jq ".state_cmd |= \"'${BONDBRIDGE_SH_PATH}'\"" \
                                                            | jq ".state_cmd_suffix |= \"${accType} 'token:${bondToken}' 'device:${timerDevice}' '${deviceType}:${device}' ${ip}\"" )

   myPlaceAccessoriesBB=$( echo "${myPlaceAccessoriesBB}" | jq ".accessories += [${myPlaceTimerLightbulb}]" )
}

function readHomebridgeConfigJson()
{
   case  $UIversion in
      customUI )
         DIR=$(pwd) 
         homebridgeConfigJson="${DIR}/config.json"
         if [ -f "${homebridgeConfigJson}" ]; then
            # expand the json just in case it is in compact form
            config=$( jq '.' "${homebridgeConfigJson}" )
            validFile=$( echo "${config}" | grep "\"MyPlace\"" )
            if [ -z "${validFile}" ]; then
               echo "ERROR: no MyPlace Config found in \"${homebridgeConfigJson}\"! Please ensure that homebridge-myplace plugin is installed"
               exit 1
            fi
         else
            echo "ERROR: no Homebridge config.json found in \"${DIR}\"! Please copy \"${myPlaceConfigBB}\" to MyPlace JASON Config manually."
            exit 1
         fi
      ;;
      nonUI )
         INPUT=""
         homebridgeConfigJson=""
         getHomebridgeConfigJsonPath
         if [ "${fullPath}" != "" ]; then homebridgeConfigJson="${fullPath}"; fi 
 
         # if no config.json file found, ask user to input the full path
         if [ -z "${homebridgeConfigJson}" ]; then
            homebridgeConfigJson=""
            echo ""
            echo "${TPUR}WARNING: No Homebridge config.json file located by the script!${TNRM}"
            echo ""
            until [ -n "${INPUT}" ]; do
               echo "${TYEL}Please enter the full path of your Homebridge config.json file,"
               echo "otherwise just hit enter to abort copying \"${myPlaceConfigBB}\" to Homebridge config.json."
               echo "The config.json path should be in the form of /*/*/*/config.json ${TNRM}"
               read -r -p "${BOLD}> ${TNRM}" INPUT
               if [ -z "${INPUT}" ]; then
                  echo "${TPUR}WARNING: No Homebridge config.json file specified"
                  echo "         Copying of ${myPlaceConfigBB} to Homebridge config.json was aborted"
                  echo ""
                  echo "${TLBL}${BOLD}INFO: Please copy/paste the ${myPlaceConfigBB} into MyPlace JASON Config Editor manually${TNRM}"
                  exit 1
               elif expr "${INPUT}" : '[./a-zA-Z0-9]*/config.json$' >/dev/null; then
                  if [ -f "${INPUT}" ]; then
                     homebridgeConfigJson="${INPUT}"
                     break
                  else
                     echo ""
                     echo "${TPUR}WARNING: No such file exits!${TNRM}"
                     echo ""
                     INPUT=""
                  fi
               else
                  echo ""
                  echo "${TPUR}WARNING: Wrong format for file path for Homebridge config.json!${TNRM}"
                  echo ""
                  INPUT=""
               fi
           done
         fi
         if [ -f "${homebridgeConfigJson}" ]; then
            if [ -z "${INPUT}" ]; then
               echo ""
               echo "${TLBL}INFO: The Homebridge config.json found: ${homebridgeConfigJson}${TNRM}"
               echo ""
            else
               echo ""
               echo "${TLBL}INFO: The Homebridge config.json specified: ${homebridgeConfigJson}${TNRM}"
               echo ""
            fi
            # expand the json just in case it is in compact form
            config=$( jq '.' "${homebridgeConfigJson}" )
            validFile=$( echo "${config}" | grep "\"MyPlace\"" )
            if [ -z "${validFile}" ]; then
               echo ""
               echo "${TRED}ERROR: no MyPlace Config found in \"${homebridgeConfigJson}\"! Please ensure that homebridge-myplace plugin is installed${TNRM}"
               echo "${TLBL}INFO: ${myPlaceConfigBB} was created but not copied to homebridge-myplace JASON Config Editor!"
               echo "      Please copy/paste the ${myPlaceConfigBB} into MyPlace JASON Config Editor manually${TNRM}"
               exit 1
            fi
         fi
      ;;
   esac
}

function extractBBmyPlaceConfigFromConfigJson()
{
   # Extract MyPlace platform and create a config without MyPlace platforms
   noOfPlatforms=$(( $( echo "${config}" | jq ".platforms|keys" | wc -w) - 2 ))
   for ((i=0; i<noOfPlatforms; i++)); do
      plaftorm=$( echo "${config}" | jq ".platforms[${i}].platform" )
      if [ "${plaftorm}" = "\"MyPlace\"" ]; then
         configMyPlace=$( echo "${config}" | jq ".platforms[${i}]" )
         configMyPlaceLess=$( echo "${config}" | jq "del(.platforms[${i}])" )
         break
      fi
   done

   # Now extract BB platform and create a config without BB and MyPlace platforms
   noOfPlatforms=$(( $( echo "${configMyPlaceLess}" | jq ".platforms|keys" | wc -w) - 2 ))
   for ((i=0; i<noOfPlatforms; i++)); do
      plaftorm=$( echo "${configMyPlaceLess}" | jq ".platforms[${i}].platform" )
      if [ "${plaftorm}" = "\"BondBridge\"" ]; then
         configBB=$( echo "${configMyPlaceLess}" | jq ".platforms[${i}]" )
         configBBmyPlaceLess=$( echo "${configMyPlaceLess}" | jq "del(.platforms[${i}])"  )
         break
      fi
   done
}

function extractMyPlaceConfigNonBBandAccessoriesNonBB()
{
   myPlaceConfigNonBB="${configMyPlace}"
   presenceOfAccessories=$( echo "${configMyPlace}" | jq ".accessories" )
   if [ "${presenceOfAccessories}" != "null" ]; then
      noOfAccessories=$(( $( echo "${configMyPlace}" | jq ".accessories|keys" | wc -w) - 2 ))
      for (( i=0; i<noOfAccessories; i++ )); do
         myPlaceStateCmd=$( echo "${configMyPlace}" | jq ".accessories[${i}].state_cmd" | grep -n "homebridge-bondbridge" )
         # create the non-BB myPlaceConfigNonBB
         if [ "${myPlaceStateCmd}" != "" ]; then
            myPlaceConfigNonBB=$( echo "${myPlaceConfigNonBB}" | jq "del(.accessories[${i}])" )
         else   # create the non-BB accessories
            accessoriesNonBB=$( echo "${configMyPlace}" | jq ".accessories[${i}]" )
            myPlaceAccessoriesBBwithNonBB=$( echo "${myPlaceAccessoriesBBwithNonBB}" | jq ".accessories += [${accessoriesNonBB}]" )
         fi
      done
   fi
}

function extractNonBBconstants()
{
   noOfConstants=$(( $( echo "${myPlaceConfigNonBB}" | jq ".constants|keys" | wc -w) - 2 ))
   for ((i=0; i<noOfConstants; i++)); do
      key=$( echo "${myPlaceConfigNonBB}" | jq ".constants[${i}].key" )
      key=${key//\"/}
      keyUsed=$( echo "${accessoriesNonBB}" | grep -n "${key}" | grep -v 'key' | head -n 1 | cut -d":" -f1 )
      if [ -n "${keyUsed}" ]; then
         constantsNonBB=$( echo "${myPlaceConfigNonBB}" | jq ".constants[${i}]" )
         myPlaceConstantsBBwithNonBB=$( echo "${myPlaceConstantsBBwithNonBB}" | jq ".constants += [${constantsNonBB}]" )
      fi
   done
}

function extractNonBBqueueTypes()
{
   noOfQueues=$(( $( echo "${myPlaceConfigNonBB}" | jq ".queueTypes|keys" | wc -w) - 2 ))
   for ((i=0; i<noOfQueues; i++)); do
      queue=$( echo "${myPlaceConfigNonBB}" | jq ".queueTypes[${i}].queue" )
      queueUsed=$( echo "${accessoriesNonBB}" | grep -n "${queue}" | head -n 1 )
      if [ -n "${queueUsed}" ]; then
         queueTypesNonBB=$( echo "${myPlaceConfigNonBB}" | jq ".queueTypes[${i}]" )
         myPlaceQueueTypesBBwithNonBB=$( echo "${myPlaceQueueTypesBBwithNonBB}" | jq ".queueTypes += [${queueTypesNonBB}]" )
      fi
   done
}

function extractMyPlaceMiscKeys()
{
   # Extract any misc MyPlace Keys used by non-BB accessories
   myPlaceMiscKeys="${myPlaceConfigNonBB}"
   keys=$( echo "${myPlaceConfigNonBB}" | jq ".|keys" )
   noOfKeys=$(( $(echo "${keys}" | wc -w) - 2 ))
   for ((i=0; i<noOfKeys; i++)); do
      key=$( echo "${keys}" | jq ".[${i}]" )
      key=${key//\"/}
      if [[ "${key}" = "title" || "${key}" = "name" || "${key}" = "devices" || "${key}" = "platform" || "${key}" = "debug" || "${key}" = "outputConstants" || "${key}" = "statusMsg" || "${key}" = "timeout" || "${key}" = "stateChangeResponseTime" || "${key}" = "constants" || "${key}" = "queueTypes" || "${key}" = "accessories" ]]; then
         myPlaceMiscKeys=$( echo "${myPlaceMiscKeys}" | jq "del(.${key})" )
      fi
   done
}

function extractNonBBaccessoriesConstantsQueueTypesMisc()
{
   # this function should only be called after the BB constants, queueTypes and accessories are created
   # extract non-BB config from ${configMyPlace} and concatenate non-BB accessories to BB accessories
   myPlaceAccessoriesBBwithNonBB="${myPlaceAccessoriesBB}"
   extractMyPlaceConfigNonBBandAccessoriesNonBB

   # extract and concatenate the non-BB constants, non-BB queueTypes and non-BB related misc. keys if there are non-BB accessories
   myPlaceConstantsBBwithNonBB="${myPlaceConstantsBB}"
   myPlaceQueueTypesBBwithNonBB="${myPlaceQueueTypesBB}"
   myPlaceMiscKeys="{}"
   if [ -n "${accessoriesNonBB}" ]; then
      extractNonBBconstants
      extractNonBBqueueTypes
      extractMyPlaceMiscKeys
   fi

}

function extractMyPlaceDevices()
{
   # Extract MyPlace devices (name and devices) information
   myPlaceDevices="{}"
   devices=$( echo "${myPlaceConfigNonBB}" | jq '.devices' )
   if [ "${devices}" != "null" ]; then
      myPlaceDevices=$( echo "${myPlaceDevices}" | jq ".devices += $devices" )
   fi
}

function updateConfigBB()
{
   # To update the parmaters of BB devices and is only call for nonUI case
   # The parameters of BB devices are updated by config.schema for customUI case
   # update device1
   if [ "${CFtimerSetup1}" = "includeTimers" ]; then timerSetup=true; else timerSetup=false; fi
   configBB=$( echo "${configBB}" | jq ".devices[0].ipAddress |= \"${BBIP1}\"" \
                                  | jq ".devices[0].token |= \"${BBtoken1}\"" \
                                  | jq ".devices[0].debug |= ${BBdebug1}" \
                                  | jq ".devices[0].CFsettings.setupOption |= \"${CFsetupOption1}\"" \
                                  | jq ".devices[0].CFsettings.timerSetup |= ${timerSetup}" )

   # update/insert/remove device2
   if [ "${CFtimerSetup2}" = "includeTimers" ]; then timerSetup=true; else timerSetup=false; fi
   if [ -n "${BBIP2}" ]; then
      configBB=$( echo "${configBB}" | jq ".devices[1].ipAddress |= \"${BBIP2}\"" \
                                     | jq ".devices[1].token |= \"${BBtoken2}\"" \
                                     | jq ".devices[1].debug |= ${BBdebug2}" \
                                     | jq ".devices[1].CFsettings.setupOption |= \"${CFsetupOption2}\"" \
                                     | jq ".devices[1].CFsettings.timerSetup |= ${timerSetup}" )
   else # remove device2
      configBB=$( echo "${configBB}" | jq "del(.devices[1])" )
   fi

   # update/insert device3
   if [ "${CFtimerSetup3}" = "includeTimers" ]; then timerSetup=true; else timerSetup=false; fi
   if [ -n "${BBIP3}" ]; then
      configBB=$( echo "${configBB}" | jq ".devices[2].ipAddress |= \"${BBIP3}\"" \
                                     | jq ".devices[2].token |= \"${BBtoken3}\"" \
                                     | jq ".devices[2].debug |= ${BBdebug3}" \
                                     | jq ".devices[2].CFsettings.setupOption |= \"${CFsetupOption3}\"" \
                                     | jq ".devices[2].CFsettings.timerSetup |= ${timerSetup}" )
   else # remove device2
      configBB=$( echo "${configBB}" | jq "del(.devices[2])" )
   fi
}

function getGlobalNodeModulesPathForFile()
{
   file="$1"
   fullPath=""    

   for ((tryIndex = 1; tryIndex <= 8; tryIndex ++)); do
      case $tryIndex in  
         1)
            foundPath=$(find /var/lib/hoobs 2>&1|grep -v find|grep -v System|grep -v cache|grep node_modules|grep bondbridge|grep "/${file}$") 
            fullPath=$(echo "${foundPath}"|head -n 1)
            if [ -f "${fullPath}" ]; then
               return
            else
               fullPath=""
            fi
         ;;
         2)
            foundPath=$(npm root -g)
            fullPath="${foundPath}/homebridge-bondbridge/${file}"
            if [ -f "${fullPath}" ]; then
               return    
            else
               fullPath=""
            fi
         ;;
         3)
            fullPath="/var/lib/homebridge/node_modules/homebridge-bondbridge/${file}"
            if [ -f "${fullPath}" ]; then
               return   
            else
               fullPath=""
            fi
         ;;
         4)
            fullPath="/var/lib/node_modules/homebridge-bondbridge/${file}"
            if [ -f "${fullPath}" ]; then
               return   
            else
               fullPath=""
            fi
         ;;
         5)
            fullPath="/usr/local/lib/node_modules/homebridge-bondbridge/${file}"
            if [ -f "${fullPath}" ]; then
               return
            else
               fullPath=""
            fi
         ;;
         6)
            fullPath="/usr/lib/node_modules/homebridge-bondbridge/${file}"
            if [ -f "${fullPath}" ]; then
               return
            else
               fullPath=""
            fi
         ;;
         7)
            fullPath="/opt/homebrew/lib/node_modules/homebridge-bondbridge/${file}"
            if [ -f "${fullPath}" ]; then
               return
            else
               fullPath=""
            fi
         ;;
         8)
            fullPath="/opt/homebridge/lib/node_modules/homebridge-bondbridge/${file}"
            if [ -f "${fullPath}" ]; then
               return
            else
               fullPath=""
            fi
         ;;
      esac
   done
}

function getHomebridgeConfigJsonPath()
{
   fullPath=""
   # Typicall HOOBS installation has its config.json root path same as the root path of "BondBridge.sh"
   # The typical full path to the "BondBridge.sh" script is .../hoobs/<bridge>/node_modules/homebridge-bondbridge/BondBridge.sh
   # First, determine whether this is a HOOBS installation
   Hoobs=$( echo "$BONDBRIDGE_SH_PATH" | grep "/hoobs/" )
   if [ -n "${Hoobs}" ]; then
      fullPath="${BONDBRIDGE_SH_PATH%/*/*/*}/config.json"
      if [ -f "${fullPath}" ]; then
         myPlacePlatformFound=$( grep "\"MyPlace\"" "${fullPath}" )
         if [ -z "${myPlacePlatformFound}" ]; then
            fullPath=""
         fi
         return
      fi
   fi

   for ((tryIndex = 1; tryIndex <= 6; tryIndex ++)); do
      case $tryIndex in
         1)
            # Typical RPi, Synology NAS installations have this path to config.json
            fullPath="/var/lib/homebridge/config.json"
            if [ -f "${fullPath}" ]; then
               myPlacePlatformFound=$( grep "\"MyPlace\"" "${fullPath}" )
               if [ -n "${myPlacePlatformFound}" ]; then 
                  return
               else
                  fullPath=""
               fi
            fi
         ;;
         2)
            # Typical Mac installation has this path to config.json
            fullPath="$HOME/.homebridge/config.json"
            if [ -f "${fullPath}" ]; then
               myPlacePlatformFound=$( grep "\"MyPlace\"" "${fullPath}" )
               if [ -n "${myPlacePlatformFound}" ]; then 
                  return
               else
                  fullPath=""
               fi
            fi
         ;;
         3)
            foundPath=$(find /usr/local/lib 2>&1|grep -v find|grep -v System|grep -v cache|grep -v hassio|grep -v node_modules|grep "/config.json$")
            noOfInstances=$(echo "${foundPath}"|wc -l)
            for ((i = 1; i <= noOfInstances; i ++)); do
               fullPath=$(echo "${foundPath}"|sed -n "${i}"p)
               if [ -f "${fullPath}" ]; then
                  myPlacePlatformFound=$( grep "\"MyPlace\"" "${fullPath}" )
                  if [ -n "${myPlacePlatformFound}" ]; then 
                     return
                  else
                     fullPath=""
                  fi
               fi
            done
         ;;
         4)
            foundPath=$(find /usr/lib 2>&1|grep -v find|grep -v System|grep -v cache|grep -v hassio|grep -v node_modules|grep "/config.json$")
            noOfInstances=$(echo "${foundPath}"|wc -l)
            for ((i = 1; i <= noOfInstances; i ++)); do
               fullPath=$(echo "${foundPath}"|sed -n "${i}"p)
               if [ -f "${fullPath}" ]; then
                  myPlacePlatformFound=$( grep "\"MyPlace\"" "${fullPath}" )
                  if [ -n "${myPlacePlatformFound}" ]; then 
                     return
                  else
                     fullPath=""
                  fi
               fi
            done
         ;;
         5)
            foundPath=$(find /var/lib 2>&1|grep -v find|grep -v hoobs|grep -v System|grep -v cache|grep -v hassio|grep -v node_modules|grep "/config.json$")
            noOfInstances=$(echo "${foundPath}"|wc -l)
            for ((i = 1; i <= noOfInstances; i ++)); do
               fullPath=$(echo "${foundPath}"|sed -n "${i}"p)
               if [ -f "${fullPath}" ]; then
                  myPlacePlatformFound=$( grep "\"MyPlace\"" "${fullPath}" )
                  if [ -n "${myPlacePlatformFound}" ]; then 
                     return
                  else
                     fullPath=""
                  fi
               fi
            done
         ;;
         6)
            foundPath=$(find /opt 2>&1|grep -v find|grep -v hoobs|grep -v System|grep -v cache|grep -v hassio|grep -v node_modules|grep "/config.json$")
            noOfInstances=$(echo "${foundPath}"|wc -l)
            for ((i = 1; i <= noOfInstances; i ++)); do
               fullPath=$(echo "${foundPath}"|sed -n "${i}"p)
               if [ -f "${fullPath}" ]; then
                  myPlacePlatformFound=$( grep "\"MyPlace\"" "${fullPath}" )
                  if [ -n "${myPlacePlatformFound}" ]; then 
                     return
                  else
                     fullPath=""
                  fi
               fi
            done
         ;;
      esac
   done
}

function assembleMyPlaceConfigBB()
{
   myPlaceConfigBB="{}"
   myPlaceConfigBB=$( echo "${myPlaceConfigBB}" | jq ".name += \"MyPlace\"" \
                                                | jq ". += ${myPlaceDevices}" \
                                                | jq ". += ${myPlaceBasicKeys}" \
                                                | jq ". += ${myPlaceConstantsBB}" \
                                                | jq ". += ${myPlaceQueueTypesBB}" \
                                                | jq ". += ${myPlaceAccessoriesBB}" \
                                                | jq ".platform += \"MyPlace\"" )
}

function assembleMyPlaceConfigBBwithNonBB()
{
   myPlaceConfigBBwithNonBB="{}"
   myPlaceConfigBBwithNonBB=$( echo "${myPlaceConfigBBwithNonBB}" | jq ".name += \"MyPlace\"" \
                                                                  | jq ". += ${myPlaceDevices}" \
                                                                  | jq ". += ${myPlaceBasicKeys}" \
                                                                  | jq ". += ${myPlaceConstantsBBwithNonBB}" \
                                                                  | jq ". += ${myPlaceQueueTypesBBwithNonBB}" \
                                                                  | jq ". += ${myPlaceAccessoriesBBwithNonBB}" \
                                                                  | jq ". += ${myPlaceMiscKeys}" \
                                                                  | jq ".platform += \"MyPlace\"" )
}

function writeToHomebridgeConfigJson()
{
   # Writing the "${configBB}" and created "${myPlaceConfigBBwithNonBB}" to "${configBBmyPlaceLess}" to create "${configNew}"
   # before copying to Homebridge config.json
   
   configNew=$( echo "${configBBmyPlaceLess}" | jq ".platforms += [$configBB]" \
                                              | jq ".platforms += [$myPlaceConfigBBwithNonBB]" )
   rc=$?
   if [ "${rc}" != "0" ]; then
      echo "${TRED}${BOLD}ERROR: Writing of created MyPlace config to config.json.new failed!${TNRM}"
      echo "${TLBL}${BOLD}INFO: Instead you can copy/paste the content of \"${myPlaceConfigBB}\" into MyPlace JASON Config editor.${TNRM}"
      exit 1
   fi

   # Copy the "${configNew}" to Homebridge config.json
   fname=$( find "${homebridgeConfigJson}" -user "$USER" );
   if [ "${fname}" = "${homebridgeConfigJson}" ]; then
      echo "${configNew}" | tee "${homebridgeConfigJson}" > /dev/null
      rc=$?
   else
      echo "${configNew}" | sudo tee "${homebridgeConfigJson}" > /dev/null
      rc=$?
   fi
}

# main starts here

if [ -z "${BONDBRIDGE_SH_PATH}" ]; then UIversion="nonUI"; fi

case $UIversion in
   customUI )
      if expr "${BBIP1}" : '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*$' >/dev/null; then
         echo ""
      else
         echo "WARNING: the specified IP address ${BBIP1} is in wrong format"
         exit 1
      fi

      if [[ -n "${BBIP2}" && "${BBIP2}" != "undefined" ]]; then 
         if expr "${BBIP2}" : '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*$' >/dev/null; then
           echo "" 
         else
            echo "WARNING: the specified IP address ${BBIP2} is in wrong format"
            exit 1
         fi
      else
         BBIP2=""
         BBtoken2=""
      fi

      if [[ -n "${BBIP3}" && "${BBIP3}" != "undefined" ]]; then 
         if expr "$5" : '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*$' >/dev/null; then
            echo ""
         else
            echo "WARNING: the specified IP address ${BBIP3} is in wrong format"
            exit 1
         fi
      else
         BBIP3=""
         BBtoken3=""
      fi
   ;;
   nonUI )
      BBIP1=""
      BBIP2=""
      BBIP3=""

      until [ -n "${BBIP1}" ]; do
         echo "${TYEL}Please enter the IP address and the token of your BondBridge device:"
         read -r -p "${TYEL}IP address (xxx.xxx.xxx.xxx): ${TNRM}" INPUT
         if expr "${INPUT}" : '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*$' >/dev/null; then
            BBIP1="${INPUT}"
            read -r -p "${TYEL}Token of this device (this can be found in Bond Settings of Bond app): ${TNRM}" INPUT
            BBtoken1="${INPUT}"
            BBdebug1="false"
            echo "${TYEL}"
            echo "${BOLD}Zone Control Setup Options:${TNRM}"
            echo "${TYEL}1. Configure only a Ceiling Fan with SpeedControl"
            echo "2. Configure a Ceiling fan with SpeedControl and a Light Switch"
            echo "3. Configure a Ceiling Fan with SpeedControl and a Light with Dimmer"
            echo "4. Configure only a Light Dimmer"
            echo "5. Do not configure this Ceiling Fan"
            echo ""
            CFsetupOption1=""
            until [ -n "${CFsetupOption1}" ]; do
               read -r -p "${TYEL}Select Ceiling Fan setup options (1, 2, 3, 4 or 5, default=5):${TNRM} " INPUT
               if [ "${INPUT}" = "1" ]; then CFsetupOption1="fan"
               elif [ "${INPUT}" = "2" ]; then CFsetupOption1="fanLight"
               elif [ "${INPUT}" = "3" ]; then CFsetupOption1="fanLightDimmer"
               elif [ "${INPUT}" = "4" ]; then CFsetupOption1="lightDimmer"
               elif [[ "${INPUT}" = "5" || "${INPUT}" = "" ]]; then CFsetupOption1="doNotConfigure"
               else
                  echo ""
                  echo "${TPUR}WARNING: Invalid option selected. Try again!${TNRM}"
                  echo ""
               fi
            done
            CFtimerSetup1="noTimers"
            read -r -p "${TYEL}Include a Light and a Fan timer? (y/n, default=n): ${TNRM}" INPUT
            if [[ "${INPUT}" = "y" || "${INPUT}" = "Y" || "${INPUT}" = "true" ]]; then CFtimerSetup1="includeTimers"; fi
            read -r -p "${TYEL}Enable debug? (y/n, default=n): ${TNRM}" INPUT
            if [[ "${INPUT}" = "y" || "${INPUT}" = "Y" || "${INPUT}" = "true" ]]; then BBdebug1="true"; fi
         else
            echo ""
            echo "${TPUR}WARNING: Wrong format for an IP address! Please enter again!${TNRM}"
            echo ""
         fi
      done
      until [ -n "${BBIP2}" ]; do
         echo ""
         echo "${TYEL}Please enter the IP address and the token of your 2nd BondBridge device if any. Just hit 'enter' if none:"
         read -r -p "${TYEL}IP address (xxx.xxx.xxx.xxx): ${TNRM}" INPUT
         if [ -z "${INPUT}" ]; then
            break
         fi
         if expr "${INPUT}" : '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*$' >/dev/null; then
            BBIP2="${INPUT}"
            read -r -p "${TYEL}Token of this device (this can be found in Bond Settings of Bond app): ${TNRM}" INPUT
            BBtoken2="${INPUT}"
            BBdebug2="false"
            CFsetupOption2=""
            until [ -n "${CFsetupOption2}" ]; do
               read -r -p "${TYEL}Select Ceiling Fan setup options (1, 2, 3, 4 or 5, default=5):${TNRM} " INPUT
               if [ "${INPUT}" = "1" ]; then CFsetupOption2="fan"
               elif [ "${INPUT}" = "2" ]; then CFsetupOption2="fanLight"
               elif [ "${INPUT}" = "3" ]; then CFsetupOption2="fanLightDimmer"
               elif [ "${INPUT}" = "4" ]; then CFsetupOption2="lightDimmer"
               elif [[ "${INPUT}" = "5" || "${INPUT}" = "" ]]; then CFsetupOption2="doNotConfigure"
               else
                  echo ""
                  echo "${TPUR}WARNING: Invalid option selected. Try again!${TNRM}"
                  echo ""
               fi
            done
            CFtimerSetup2="noTimers"
            read -r -p "${TYEL}Include a Light and a Fan timer? (y/n, default=n): ${TNRM}" INPUT
            if [[ "${INPUT}" = "y" || "${INPUT}" = "Y" || "${INPUT}" = "true" ]]; then CFtimerSetup2="includeTimers"; fi
            read -r -p "${TYEL}Enable debug? (y/n, default=n): ${TNRM}" INPUT
            if [[ "${INPUT}" = "y" || "${INPUT}" = "Y" || "${INPUT}" = "true" ]]; then BBdebug2="true"; fi
         else
            echo ""
            echo "${TPUR}WARNING: Wrong format for an IP address! Please enter again!${TNRM}"
            echo ""
         fi
      done
      if [ -n "${BBIP2}" ]; then
         until [ -n "${BBIP3}" ]; do
            echo ""
            echo "${TYEL}Please enter the IP address and the token of your 2nd BondBridge device if any. Just hit 'enter' if none:"
            read -r -p "${TYEL}IP address (xxx.xxx.xxx.xxx): ${TNRM}" INPUT
            if [ -z "${INPUT}" ]; then
               break
            fi
            if expr "${INPUT}" : '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*$' >/dev/null; then
               BBIP3="${INPUT}"
               read -r -p "${TYEL}Token of this device (this can be found in Bond Settings of Bond app): ${TNRM}" INPUT
               BBtoken3="${INPUT}"
               BBdebug3="false"
               CFsetupOption3=""
               until [ -n "${CFsetupOption3}" ]; do
                  read -r -p "${TYEL}Select Ceiling Fan setup options (1, 2, 3, 4 or 5, default=5):${TNRM} " INPUT
                  if [ "${INPUT}" = "1" ]; then CFsetupOption3="fan"
                  elif [ "${INPUT}" = "2" ]; then CFsetupOption3="fanLight"
                  elif [ "${INPUT}" = "3" ]; then CFsetupOption3="fanLightDimmer"
                  elif [ "${INPUT}" = "4" ]; then CFsetupOption3="lightDimmer"
                  elif [[ "${INPUT}" = "5" || "${INPUT}" = "" ]]; then CFsetupOption3="doNotConfigure"
                  else
                     echo ""
                     echo "${TPUR}WARNING: Invalid option selected. Try again!${TNRM}"
                     echo ""
                  fi
               done
               CFtimerSetup3="noTimers"
               read -r -p "${TYEL}Include a Light and a Fan timer? (y/n, default=n): ${TNRM}" INPUT
               if [[ "${INPUT}" = "y" || "${INPUT}" = "Y" || "${INPUT}" = "true" ]]; then CFtimerSetup3="includeTimers"; fi
               read -r -p "${TYEL}Enable debug? (y/n, default=n): ${TNRM}" INPUT
               if [[ "${INPUT}" = "y" || "${INPUT}" = "Y" || "${INPUT}" = "true" ]]; then BBdebug3="true"; fi
            else
               echo ""
               echo "${TNRM}${TPUR}WARNING: Wrong format for an IP address! Please enter again!${TNRM}"
               echo ""
            fi
         done
      fi

      echo ""
      echo "${TLBL}INFO: (1) ip1:${BBIP1}, token1:${BBtoken1}, ${CFsetupOption1}, ${CFtimerSetup1}${TNRM}"
      if [ -n "${BBIP2}" ]; then echo "${TLBL}INFO: (2) ip2:${BBIP2}, token2:${BBtoken2}, ${CFsetupOption2}, ${CFtimerSetup2}${TNRM}"; fi
      if [ -n "${BBIP3}" ]; then echo "${TLBL}INFO: (3) ip3:${BBIP3}, token3:${BBtoken3}, ${CFsetupOption3}, ${CFtimerSetup3}${TNRM}"; fi
      echo ""

      # get the full path to BondBridge.sh
      BONDBRIDGE_SH_PATH=""
      getGlobalNodeModulesPathForFile "BondBridge.sh"
      if [ -n "${fullPath}" ]; then
         BONDBRIDGE_SH_PATH=${fullPath}
         echo "${TLBL}INFO: BondBridge.sh found: ${BONDBRIDGE_SH_PATH}${TNRM}"
      fi

      if [ -z "${BONDBRIDGE_SH_PATH}" ]; then
         BONDBRIDGE_SH_PATH=""
         until [ -n "${BONDBRIDGE_SH_PATH}" ]; do
            echo ""
            echo "${TYEL}Please enter the full path of where the BondBridge.sh is installed in your system"
            echo "The file path format should be : /*/*/*/node_modules/homebridge-bondbridge/BondBridge.sh${TNRM}"
            read -r -p "${BOLD}> ${TNRM}" INPUT
            if expr "${INPUT}" : '/[a-zA-Z0-9/_]*/node_modules/homebridge-bondbridge/BondBridge.sh$' >/dev/null; then
               if [ -f "${INPUT}" ]; then
                  BONDBRIDGE_SH_PATH=${INPUT}
                  echo ""
                  echo "${TLBL}INFO: BondBridge.sh specified: ${BONDBRIDGE_SH_PATH}${TNRM}"
                  break
               else
                  echo ""
                  echo "${TPUR}WARNING: file ${INPUT} not found${TNRM}"
               fi
            else
               echo ""
               echo "${TPUR}WARNING: file ${INPUT} is in wrong format${TNRM}"
            fi
         done
      fi
   ;;
esac

noOfBondBridges=1
if [ -n "${BBIP2}" ]; then noOfBondBridges=2; fi
if [ -n "${BBIP3}" ]; then noOfBondBridges=3; fi

for ((n=1; n<=noOfBondBridges; n++)); do

   if [ "${n}" = "1" ]; then 
      ip="\${BBIP1}"
      IPA="${BBIP1}"
      bondToken="${BBtoken1}"
      CFsetupOption="${CFsetupOption1}"
      CFtimerSetup="${CFtimerSetup1}"
      debug="${BBdebug1}"
      queue="BBA"
   fi
   if [ "${n}" = "2" ]; then 
      ip="\${BBIP2}"
      IPA="${BBIP2}"
      bondToken="${BBtoken2}"
      CFsetupOption="${CFsetupOption2}"
      CFtimerSetup="${CFtimerSetup2}"
      debug="${BBdebug2}"
      queue="BBB"
   fi
   if [ "${n}" = "3" ]; then 
      ip="\${BBIP3}"
      IPA="${BBIP3}"
      bondToken="${BBtoken3}"
      CFsetupOption="${CFsetupOption3}"
      CFtimerSetup="${CFtimerSetup3}"
      debug="${BBdebug3}"
      queue="BBC"
   fi
  
   if [[ "${n}" = "1" && "${UIversion}" = "nonUI" ]]; then
      echo ""
      if [ "${noOfBondBridges}" = "1" ]; then echo "${TLBL}${BOLD}INFO: This will take up to 1 minute to process!${TNRM}"; fi
      if [ "${noOfBondBridges}" = "2" ]; then echo "${TLBL}${BOLD}INFO: This will take up to 2 minutes to process!${TNRM}"; fi
      if [ "${noOfBondBridges}" = "3" ]; then echo "${TLBL}${BOLD}INFO: This will take up to 3 minutes to process!${TNRM}"; fi
   fi

   if [ "${UIversion}" = "nonUI" ]; then
      echo "${TLBL}INFO: Fetching and processing data from your BondBridge device (${bondToken} ${IPA}).... ${TNRM}"
   fi

   # retrieve the Bond Bridge system info and get the bondid
   version=$(curl -s -g -H -i http://"${IPA}"/v2/sys/version)
   if [ -z "${version}" ]; then
      echo "${TRED}ERROR: BondBridge device is inaccessible or your IP address ${IPA} is invalid!${TNRM}"
      exit 1
   fi

   bondid=$(echo "${version}" | jq ".bondid")
   bondid=${bondid//\"/}
   if [ -z "${bondid}" ]; then
      echo "${TRED}ERROR: jq failed! Please make sure that jq is installed!${TNRM}"
      exit 1
   fi

   model=$(echo "${version}" | jq ".model")
   model=${model//\"/}

   # Read the existing Homebridge config.json file
   readHomebridgeConfigJson

   # Extract BB plaform and MyPlace platform
   extractBBmyPlaceConfigFromConfigJson

   # Create the ${myPlaceBasicKeys}
   # First check whether the original MyPlace platform has its "debug=true", if so leave that as "true"
   debugPresence=$( echo "${configMyPlace}" | jq ".constants" | grep ":2025-debug" )
   debugMyPlace=false
   if [ -n "${debugPresence}" ]; then 
      debugMyPlace=true
   else
      if [[ "${BBdebug1}" = "true" || "${BBdebug2}" = "true" ||"${BBdebug3}" = "true" ]]; then
         debugMyPlace=true
      fi
   fi
   myPlaceBasicKeys

   # Create the ${myPlaceConstantsBB} and ${myPlaceQueueTypesBB}
   if [ "${CFsetupOption}" != "doNotConfigure" ]; then
      myPlaceConstants
      myPlaceQueueTypes
   fi

   # Create the myPlaceModelQueue for this BB system
   myPlaceModelQueue

   # Create the $myPlaceConfigAccessories
   # first retireve the info of all the defined devices 
   Devices=$(curl -s -g -H "BOND-Token: ${bondToken}" http://"${IPA}"/v2/devices)
   devices=$(echo "$Devices" | jq '. | keys')
   noOfDevices=$(($(echo "${devices}" | wc -w) - 2))

   # Now create the config for the devices
   for (( i=0;i<noOfDevices;i++ )); do
      device=$(echo "${devices}"|jq ".[$i]")
      if expr "${device}" : '^\"[a-f0-9]*\"$' >/dev/null; then
         device=${device//\"/}
         timerDevice=$(echo "${device}" | rev)
         max_speed=$(curl -s -g -H "BOND-Token: ${bondToken}" http://"${IPA}"/v2/devices/"${device}"/properties |  jq ".max_speed")
         speed_interval=$((100 / max_speed))
         name=$(curl -s -g -H "BOND-Token: ${bondToken}" http://"${IPA}"/v2/devices/"${device}" |  jq ".name")
         name=${name//\"/}
         if [ "${CFsetupOption}" != "doNotConfigure" ]; then
            if expr "${name}" : '[a-zA-Z0-9 ]*Fan$' >/dev/null; then
               if [ "${CFsetupOption}" != "lightDimmer" ]; then
                  myPlaceFan "${name}" "${speed_interval}"
               fi
               if [ "${CFtimerSetup}" = "includeTimers" ]; then
                  myPlaceTimerLightbulb "${name} Timer" "fanTimer" "fanDevice"
               fi
            fi
            #
            if expr "${name}" : '[a-zA-Z0-9 ]*Light$' >/dev/null; then
               if [ "${CFsetupOption}" = "fanLight" ]; then
                  myPlaceLightbulbNoDimmer "${name}" "light"
               elif [ "${CFsetupOption}" = "fanLightDimmer"  ]; then
                  myPlaceLightbulbWithDimmer "${name}" "light" "${speed_interval}"
               elif [ "${CFsetupOption}" = "lightDimmer" ]; then
                  myPlaceLightbulbWithDimmer "${name} Dimmer" "dimmer" "${speed_interval}"
               fi
               if [[ "${CFtimerSetup}" = "includeTimers" && "${CFsetupOption}" != "fan" ]]; then
                  myPlaceTimerLightbulb "${name} Timer" "lightTimer" "lightDevice"
               fi
            fi
         fi
      fi
   done      
done


# Extract non-BB accessories, nonBB constants and nonBB queueTypes
extractNonBBaccessoriesConstantsQueueTypesMisc

# Extract non-BB related devices from MyPlace platform
extractMyPlaceDevices

# Update the BB devices of BB platform
if [ "${UIversion}" = "nonUI" ]; then
   updateConfigBB
fi

# Assemble a complete MyPlace configuration file for the specified BB device(s)
assembleMyPlaceConfigBB

# Assemble a complete MyPlace configuration file for the specified BB devices(s) with the extracted nonBB devices
assembleMyPlaceConfigBBwithNonBB

# Write the assembled BB + non-BB configuration into the Homebridge config.json
writeToHomebridgeConfigJson

if [ "${rc}" = "0" ]; then
   echo "${TGRN}${BOLD}DONE! Run CheckConfig then restart Homebridge or HOOBS.${TNRM}" 
   if [ "${UIversion}" = "nonUI" ]; then
      check1="${BONDBRIDGE_SH_PATH%/*}/CheckConfig.sh"
      echo ""
      echo "${TYEL}To run CheckConfig, please copy/paste and run the following command to check whether the configuration meets all the requirements${TNRM}"
      echo "${check1}"
   fi
else
   # Copying of the new config.json to homebridge config.json failed so restore the homebridge config.json from backup
   fname=$( find "${homebridgeConfigJson}" -user "$USER" );
   if [ "${fname}" = "${homebridgeConfigJson}" ]; then
      echo "${config}" | tee "${homebridgeConfigJson}" > /dev/null
   else
      echo "${config}" | sudo tee "${homebridgeConfigJson}" > /dev/null
   fi
   echo "${TRED}${BOLD}ERROR: Copying of \"${myPlaceConfigBB}\" to Homebridge config.json failed! Original config.json restored.${TNRM}"
   echo "${TLBL}${BOLD}INFO: Instead you can copy/paste the content of \"${myPlaceConfigBB}\" into MyPlace JASON Config editor.${TNRM}"
fi

exit 0
