#!/bin/bash

# boot method：flock -xno /run/boot.lock -c '/data/homeassistant/gree_hc_ota boot'

# ota method：flock -xno /run/ota.lock -c '/data/homeassistant/gree_hc_ota ota'

# version number
version="v1.0.5"
# program name
name="ota"
# root path
root_path="/data/homeassistant/"
# initial program path
init_path="${root_path}init/"
# compressed file path
compress_path="${root_path}compress"
# backup program path
backup_path="${root_path}backup/"
# temporary program path
temp_path="${root_path}temp/"
# logger path
logs_path="${root_path}logs/"
# ota_file_path path
ota_file_path="${root_path}ota.conf"
# program prefix
file_prefix="gree_hc_"
# can program
can="iot_host_can"
# wifi program
wifi="alpha"
# iot program
iot="cmd-linux-arm"
# test program
test="test"
# third-party program
third="third_party"
# daemon process
#daemon="daemon.sh"
# Compression package name
fileName="362001069922+ZTS31B"
# ota number
num=0
# start number
start_num=0
# # env
# mode=$(flag)
# datetime format
DATE=$(TZ=UTC-8 date '+%Y-%m-%d %T %Z%z')
# flag
flag=0
# conf file for random number
#config_file="${root_path}/random.conf"

# ${FUNCNAME[1] represents the function that called the function
# $LINENO represent the current line number
function fmt() {
  local log_level=$1
  local log_info=$2
  local line=$3
  local script_name
  script_name=$(basename $0)

  case ${log_level} in
  "INFO")
    echo -e "\033[32m[${DATE}] [${script_name}] [INFO] [${FUNCNAME[1]}:$line] \"${log_info}\"\033[0m"
    ;;
  "WARN")
    echo -e "\033[33m[${DATE}] [${script_name}] [WARN]: [${FUNCNAME[1]}:$line] \"${log_info}\"\033[0m"
    ;;
  "ERROR")
    echo -e "\033[31m[${DATE}] [${script_name}] [ERROR] [${FUNCNAME[1]}:$line] \"${log_info}\"\033[0m"
    ;;
  *)
    echo -e "${@}"
    ;;
  esac
}

# service recover
function recover() {
  fmt WARN "recover..." $LINENO
  find $root_path -maxdepth 1 -name "${file_prefix}*" -type f -exec mv -f {} $temp_path \;
  find $backup_path -maxdepth 1 -name "${file_prefix}*" -type f -exec mv -f {} $root_path \;
  # find $temp_path -maxdepth 1 -name "${file_prefix}*" -type f -exec mv -f {} $backup_path \;
  return 0
}

# service backup
function backup() {
  fmt INFO "backup..." $LINENO
  if [ "$(ls -A ${backup_path})" != "" ]; then
    mv $backup_path* $temp_path
  fi
  find $root_path -maxdepth 1 -name "${file_prefix}*" -not -name "${fileName}*.tar.gz" -type f -exec mv -f {} $backup_path \;
  return 0
}

# service initial
function init() {
  fmt WARN "init..."
  find $init_path -maxdepth 1 -name "${file_prefix}*" -type f -exec cp -f {} $root_path \;
  return 0
}

#start daemon service
#function daemon() {
#  killall ${file_prefix}${daemon}
#  fmt INFO "${root_path}${file_prefix}${daemon} stop" $LINENO
#  chmod +x ${root_path}${file_prefix}${daemon}
#  fmt INFO "${root_path}${file_prefix}${daemon} start" $LINENO
#  nohup ${root_path}${file_prefix}${daemon} >>${logs_path}${file_prefix}daemon.log &
#  sleep 2
#}

#start all main service
function start() {
  fmt INFO "start..." $LINENO
  fmt INFO "set PWD env" $LINENO
  export PWD=$root_path
  cd $root_path
  rm ${root_path}start_env.log
  env >>${root_path}start_env.log

  # killall service
  fmt INFO "killall service"
#  systemctl stop ${file_prefix}${daemon}
  systemctl stop $file_prefix$can
  systemctl stop $file_prefix$wifi
  systemctl stop $file_prefix$iot
  systemctl stop $file_prefix$test
  systemctl stop $file_prefix$third
  systemctl stop udhcpc

  sleep 2

  #eth0 get ip auto
  fmt INFO "eth0 get ip auto" $LINENO
  #udhcpc -ieth0 2>&1 &
  udhcpc -i eth0 -x hostname:GREE_ALPHA_Engine 2>&1 &
  udhcpc -ieth1 2>&1 &
  sleep 1

  #start all service
  fmt INFO "${root_path}${file_prefix}${iot} start" $LINENO
  chmod +x ${root_path}${file_prefix}${iot}
  # nohup ${root_path}${file_prefix}${iot} >>${logs_path}${file_prefix}${iot}.log &
  systemctl start $file_prefix$iot
  #sleep 2

  fmt INFO "${root_path}${file_prefix}${wifi} start" $LINENO
  chmod +x ${root_path}${file_prefix}${wifi}
  # nohup ${root_path}${file_prefix}${wifi} >>${logs_path}${file_prefix}${wifi}.log &
  systemctl start ${file_prefix}${wifi}
  #sleep 4

  fmt INFO "${root_path}${file_prefix}${can} start" $LINENO
  chmod +x ${root_path}${file_prefix}${can}
  # nohup ${root_path}${file_prefix}${can} >>${logs_path}${file_prefix}${can}.log &
  systemctl start ${file_prefix}${can}

  fmt INFO "${root_path}${file_prefix}${test} start" $LINENO
  chmod +x ${root_path}${file_prefix}${test}
  # nohup ${root_path}${file_prefix}${test} >>${logs_path}${file_prefix}${test}.log &
  systemctl start ${file_prefix}${test}

   fmt INFO "${root_path}${file_prefix}${third} start" $LINENO
   chmod +x ${root_path}${file_prefix}${third}
  #  nohup ${root_path}${file_prefix}${third} >>${logs_path}${file_prefix}${third}.log &
   systemctl start ${file_prefix}${third}
   sleep 4

  # check if 5 process is alive
  status=$(ps  | grep -E "$file_prefix$iot*|$file_prefix$wifi*|$file_prefix$can*|${file_prefix}${test}*|${file_prefix}${third}*")
  status_count=$(fmt "$status" | wc -l)
  fmt INFO $status $LINENO

  if ((${status_count} >= 6)); then
    fmt INFO "service number "$status_count $LINENO
    return 0
  fi

  return 1
}

function init_check() {
  fmt INFO "init_check..."
  if (($(ps  | grep -E "$file_prefix$iot*" | wc -l) >= 2)); then
    fmt INFO "init_check iot success" $LINENO
  else
    fmt ERROR "init_check iot failed" $LINENO
    return 1
  fi
  if (($(ps  | grep -E "$file_prefix$wifi*" | wc -l) >= 2)); then
    fmt INFO "init_check wifi success" $LINENO
  else
    fmt ERROR "init_check wifi failed" $LINENO
    return 2
  fi
  if (($(ps  | grep -E "$file_prefix$can*" | wc -l) >= 2)); then
    fmt INFO "init_check can success" $LINENO
  else
    fmt ERROR "init_check can failed" $LINENO
    return 3
  fi
  if (($(ps  | grep -E "$file_prefix$test*" | wc -l) >= 2)); then
    fmt INFO "init_check test success" $LINENO
    return 0
  else
    fmt ERROR "init_check test failed" $LINENO
    return 4
  fi
  if (($(ps  | grep -E "$file_prefix$third*" | wc -l) >= 2)); then
     fmt INFO "init_check third_party success" $LINENO
     return 0
   else
    fmt ERROR "init_check third_party failed" $LINENO
     return 6
   fi
}

function check() {
  fmt INFO "check..." $LINENO
  if [ "$(ls -A ${temp_path})" != "" ]; then
    rm -f $temp_path*
  fi
  result=$(find ${compress_path} -maxdepth 1 -type f -name "${fileName}*.tar.gz")
  fmt INFO "ota package: $result" $LINENO
  if [ -f "${result}" ] && [ -f "${compress_path}/${fileName}.tar.gz.md5" ]; then
    if md5sum -c "${compress_path}/${fileName}.tar.gz.md5"; then
      backup
      tar -xzvf $result -C $root_path && rm -rf $result

      fmt INFO "check and start..." $LINENO
      # reboot plan
      sync
      fmt INFO "reboot" $LINENO
      get_ota_conf
      shutdown -r now

      # not reboot plan
      # start
      return $?
    fi
  fi
  # find $root_path -maxdepth 1 -not -name "${file_prefix}*_${version}" ! -name "*.sh" -type f -exec mv -f {} $backup_path \;

  # check if 4 process is alive
  if (($(ps  | grep -E "$file_prefix$iot*" | wc -l) >= 2)); then
    fmt INFO "check iot success" $LINENO
  else
    fmt ERROR "check iot failed" $LINENO
    return 1
  fi
  if (($(ps  | grep -E "$file_prefix$wifi*" | wc -l) >= 2)); then
    fmt INFO "check wifi success" $LINENO
  else
    fmt ERROR "check wifi failed" $LINENO
    return 1
  fi
  if (($(ps  | grep -E "$file_prefix$can*" | wc -l) >= 2)); then
    fmt INFO "check can success" $LINENO
  else
    fmt ERROR "check can failed" $LINENO
    return 1
  fi
  if (($(ps  | grep -E "$file_prefix$test*" | wc -l) >= 2)); then
    fmt INFO "check test success" $LINENO
    return 0
  else
    fmt ERROR "check test failed" $LINENO
    return 1
  fi
  if (($(ps  | grep -E "$file_prefix$third*" | wc -l) >= 2)); then
     fmt INFO "init_check third_party success" $LINENO
     return 0
   else
    fmt ERROR "init_check third_party failed" $LINENO
     return 1
   fi
}

function boot() {
#  rand=$(cat /dev/urandom |tr -dc '0-9a-zA-Z!@_#?.,' |head -c 16)
#  sed -r -i "s/(rand=).*/\1$rand/" $config_file

  if [ ! -f "${ota_file_path}" ]; then
    flag=0
  else
    flag=$(sed '/^complete=/!d;s/.*=//' ${ota_file_path})
  fi

  fmt INFO "boot..." $LINENO
#  fmt INFO "random num $rand"
  fmt INFO "get ota flag num $flag" $LINENO
#  start
  check
  fmt INFO "cycle start"
  until [ $? -eq 0 ]; do
    fmt INFO "check status $?"
    if (($start_num > 5)); then
      fmt ERROR "error: start failed" $LINENO
      break
    fi
    start_num=$(($start_num + 1))
    fmt INFO "start number: ${start_num}" $LINENO
    start
  done

  fmt INFO "cycle init_check" $LINENO
  for ((i=0;i<3;i++));do
    init_check
    case $? in
    1)
      start
      ;;
    2)
        fmt warn "cycle check: ${root_path}${file_prefix}${wifi} start" $LINENO
        chmod +x ${root_path}${file_prefix}${wifi}
        # nohup ${root_path}${file_prefix}${wifi} >>${logs_path}${file_prefix}${wifi}.log &
        systemctl stop ${file_prefix}${wifi}
        systemctl start ${file_prefix}${wifi}
      ;;
    3)
        fmt warn "cycle check: ${root_path}${file_prefix}${can} start" $LINENO
        chmod +x ${root_path}${file_prefix}${can}
        # nohup ${root_path}${file_prefix}${can} >>${logs_path}${can}.log &
        systemctl stop ${file_prefix}${can}
        systemctl start ${file_prefix}${can}
      ;;
    4)
        fmt warn "cycle check: ${root_path}${file_prefix}${test} start" $LINENO
        chmod +x ${root_path}${file_prefix}${test}
        # nohup ${root_path}${file_prefix}${test} >>${logs_path}${file_prefix}${test}.log &
        systemctl stop ${file_prefix}${test}
        systemctl start ${file_prefix}${test}
      ;;
    6)
        fmt warn "cycle check: ${root_path}${file_prefix}${third} start" $LINENO
        chmod +x ${root_path}${file_prefix}${third}
        # nohup ${root_path}${file_prefix}${third} >>${logs_path}${file_prefix}${third}.log &
        systemctl stop ${file_prefix}${third}
        systemctl start ${file_prefix}${third}
      ;;
    *)
      return 0
      ;;
    esac
    fmt INFO "cycle number $i"
    sleep 1
  done

  if [ $flag -eq 0 ];then
    fmt INFO "not need recover or init..." $LINENO
    return 1
  fi

  fmt WARN "need recover or init..." $LINENO
  if init_check; then
    return 0
  fi
  fmt WARN "need recover..." $LINENO
  recover
  start
  if init_check; then
    return 0
  fi
  fmt WARN "need init..." $LINENO
  init
  start
  if init_check; then
    return 0
  fi
}

function ota() {
  fmt INFO "OTA..." $LINENO
  systemctl daemon-reload
  # check if 3 process is alive
  # ps |grep -E "gree_hc_cmd-linux-arm*|gree_hc_demo_gree*|gree_hc_iot_host_can*"|wc -l

  if [ "$(ls -A ${backup_path})" != "" ]; then
    recover
    start
    return $?
  else
    init
    start
    return $?
  fi
}


function complete() {
      if grep -q "^complete=" ${ota_file_path}; then
        # 如果存在，则只替换值
      sed -ri "s/^(complete=).*/\1$1/"  ${ota_file_path}
      fmt INFO "update complete $1" $LINENO
    else
      # 如果不存在，则添加一行
      echo "complete=$1" >>  ${ota_file_path}
      fmt INFO "add complete $1" $LINENO
    fi
}

function rand() {
    rand=$(cat /dev/urandom |tr -dc '0-9a-zA-Z!@_#?.,' |head -c 16)

    if grep -q "^complete=" ${config_file}; then
      # 如果存在，则只替换值
      sed -r -i "s/(rand=).*/\1$rand/" ${config_file}
    else
      # 如果不存在，则添加一行
      echo "complete=$1" >>  ${config_file}
    fi
}

function get_ota_conf() {
      if [ ! -f "${ota_file_path}" ]; then
        fmt INFO "${ota_file_path} not exist" $LINENO
      else
        flag=$(sed '/^complete=/!d;s/.*=//' ${ota_file_path})
        fmt INFO "${ota_file_path} exist" $LINENO
      fi
}

case $1 in
check)
  check
  ;;
backup)
  backup
  ;;
recover)
  recover
  ;;
init)
  init
  start
  ;;
ota)
  complete 1
  check
  get_ota_conf
#  until [ $? -eq 0 ]; do
#    fmt INFO "check status $?" $LINENO
#    if (($num > 3)); then
#      fmt ERROR "ota error: init failed" $LINENO
#      #            sed -r -i "s/(flag=).*/\1check/" /etc/ota.conf
#      break
#      exit 2
#    fi
#    num=$(($num + 1))
#    fmt INFO "OTA number: ${num}"
#    ota
#  done
#  fmt INFO "go to daemon" $LINENO
#  daemon
#  complete 0
  ;;
start)
  start
#  daemon
  ;;
boot)
  boot
#  daemon
  complete 0
  ;;
version)
  fmt INFO "${file_prefix}${name}_${version}"
  ;;
*)
  boot
#  daemon
  complete 0
  ;;
esac

exit 0
