#!/bin/bash

# (C) 2017 Intel Corporation. All rights reserved.
# Your use of Intel Corporation's design tools, logic functions and other
# software and tools, and its AMPP partner logic functions, and any output
# files any of the foregoing (including device programming or simulation
# files), and any associated documentation or information are expressly subject
# to the terms and conditions of the Intel Program License Subscription
# Agreement, Intel MegaCore Function License Agreement, or other applicable
# license agreement, including, without limitation, that your use is for the
# sole purpose of programming logic devices manufactured by Intel and sold by
# Intel or its authorized distributors.  Please refer to the applicable
# agreement for further details.

###############################################################################
# Script install the software packages needed for using PAC card
# and also calls setup_permission.sh to configure permission for 
# device.  It is called by 'aocl install'
###############################################################################

if [ -n "$PAC_BSP_ENV_DEBUG_INSTALL_SCRIPT" ]; then
  set -x
fi

###############################################################################
# Global variables in script:
#   BSP_ROOT: root directory of BSP
#   HOST_OS: OS running on host system
#   PAC_CARD: type of PAC card that is installed in system
#   PKG_DIR: subdirectory with software package to install on system
###############################################################################
BSP_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd ../.. && pwd )"
HOST_OS=""
PAC_CARD=""
PKG_DIR=""

###############################################################################
# Check return code and exit with error message if not 0
# Arguments:
#   Return code to check
#   Error message printed on failure
###############################################################################
check_res() {
  local ret_code="$1"
  local msg="$2"
  if [ "$ret_code" -ne 0 ]; then
    echo "Error: $msg" >&2
    exit "$ret_code"
  fi
}

###############################################################################
# Print error message and exit
# Arguments
#   Error message to print
###############################################################################
error() {
  echo "Error: $1" >&2
  exit 1
}

###############################################################################
# Check number of PAC cards detected with matching device ID
# Arguments
#   Device ID to detect
###############################################################################
get_num_boards() {
  if [ -z "$1" ]; then
    error "Device ID not specified"
  fi

  local board_did=$1
  local num_boards
  num_boards=$(lspci -d 8086:"$board_did" | wc | awk '{print $1}')
  echo "$num_boards"
}

###############################################################################
# Check PCI devices to determine if any PAC cards are installed on the host
# and set PAC_CARD to matching type if only single type of card is found
# Globals:
#   PAC_CARD
###############################################################################
check_for_card() {
  local darby_creek_did="0b2b"
  local rush_creek_did="09c4"

  local num_pac_a10
  num_pac_a10=$(get_num_boards $rush_creek_did)
  
  local num_pac_s10
  num_pac_s10=$(get_num_boards $darby_creek_did)

  if [[ $num_pac_a10 -eq 0 && $num_pac_s10 -eq 0 ]]; then
    PAC_CARD=""
  elif [[ $num_pac_a10 -gt 0 && $num_pac_s10 -gt 0 ]]; then
    PAC_CARD=""
  elif [[ $num_pac_a10 -gt 0 ]]; then
    PAC_CARD="pac_a10"
  elif [[ $num_pac_s10 -gt 0 ]]; then
    PAC_CARD="pac_s10"
  fi
}

###############################################################################
# Check for packages for PAC card. If only 1 type detected then use that
# if sets of packages found then use set that matches card deteced on host
# Globals
#   PKG_DIR
###############################################################################
check_for_bringup()
{
  local bringup_root="$BSP_ROOT/bringup/opae"
  if [ ! -d "$bringup_root" ]; then
    error "bringup directory '$bringup_root' not found"
  fi

  local bringup_dirs
  bringup_dirs=$(ls -1 "$bringup_root")
  local bringup_dirs_cnt
  bringup_dirs_cnt=$(echo "$bringup_dirs" | wc | awk '{print $1}')
  if [ "$bringup_dirs_cnt" -eq 0 ]; then
    error "no board variants found in '$bringup_dirs'"
  elif [ "$bringup_dirs_cnt" -eq 1 ]; then
    PKG_DIR="$bringup_dirs"
  else
    PKG_DIR="$PAC_CARD"
  fi

}

###############################################################################
# Determine host OS and exit if OS not supported
# Globals:
#   HOST_OS  
###############################################################################
check_os() {
  local kernel
  kernel=$(uname -r)
  local kernel_status=$?

  # lsb_release not installed by default on CentOS 7
  if command -v lsb_release > /dev/null; then
    local distro
    distro=$(lsb_release -is)
    local distro_status=$?
    local release
    release=$(lsb_release -rs)
    local release_status=$?

    if [ $distro_status == 0 ] && [ $release_status == 0 ] && [ $kernel_status == 0 ]; then
      if [ "$distro" == "RedHatEnterpriseServer" ] || [ "$distro" == "CentOS" ] && [[ $release =~ ^7.[0-9]+ ]]; then
        HOST_OS="rhel7"
      elif [ "$distro" == "Ubuntu" ] && [ "$release" == "18.04" ] &&  [[ $kernel == 4.15.* ]]; then
        HOST_OS="ubuntu1804"
      else
        error "unsupported OS: $distro $release kernel $kernel"
      fi
    else
      error "could not determine OS"
    fi
  elif [ -f /etc/redhat-release ] && [[ $kernel == 3.10.* ]]; then
    HOST_OS="rhel7"
  else
    error "could not determine OS"
  fi
}

###############################################################################
# Install packages for RHEL 7
###############################################################################
install_rhel_pkg() {
  local pkg_root="$1"
  local pkg_list_file="$pkg_root/rhel7.pkgs"
  if [ ! -f "$pkg_list_file" ]; then
    error "cannot find OPAE file list: $pkg_list_file"
  fi

  local pkg_list
  pkg_list=$(cat "$pkg_list_file")
  declare -a pkg_arr
  for pkg in $pkg_list; do
    pkg_arr+=("$(find "$pkg_root" -name "$pkg" -exec readlink -e {} \;)")
  done

  IFS=""
  sudo yum localinstall -y "${pkg_arr[@]}"
  check_res $? "OPAE package install failed"
  unset IFS
}

###############################################################################
# Install packages for Ubuntu 18.04
###############################################################################
install_ubuntu_pkg() {
  local pkg_root="$1"

  local pkg_list_file="$pkg_root/ubuntu1804.pkgs"
  if [ ! -f "$pkg_list_file" ]; then
    error "cannot find OPAE file list: $pkg_list_file"
  fi

  local pkg_list
  pkg_list=$(cat "$pkg_list_file")
  local pkg_arr=()
  for pkg in $pkg_list; do
    pkg_arr+=("$(find "$pkg_root" -name "$pkg" -exec readlink -e {} \;)")
  done
  
  IFS=""
  sudo apt install -y "${pkg_arr[@]}"
  check_res $? "OPAE package install failed"
  unset IFS
}

###############################################################################
# Determine cards and OS and call appropriate install function
# Globals:
#   PAC_CARD
#   PKG_DIR
###############################################################################
install_packages() {
  if [ -z "$PAC_CARD" ]; then
    PAC_CARD="$PKG_DIR"
  elif [ "$PAC_CARD" != "$PKG_DIR" ]; then
    echo "Detected card ($PAC_CARD) does not match bringup dir ($PKG_DIR)"
    echo "Enter name of card to install (pac_a10 or pac_s10): "
    read -r pac_card_name
    PAC_CARD="$pac_card_name"
  fi

  if [ "$PAC_CARD" != "pac_s10" ] && [ "$PAC_CARD" != "pac_a10" ]; then
    error "Invalid card type: '$PAC_CARD'"
  fi

  local bringup_dir="$BSP_ROOT/bringup/opae/$PKG_DIR"
  if [ ! -d "$bringup_dir" ]; then
    error "Cannot find packages directory: $bringup_dir" 
  fi

  echo "Installing $HOST_OS packages for $PAC_CARD card"
  if [ "$HOST_OS" == ubuntu1804 ]; then
    install_ubuntu_pkg "$bringup_dir"
  elif [ "$HOST_OS" == rhel7 ]; then
    install_rhel_pkg "$bringup_dir"
  else
    error "invalid OS: $HOST_OS"
  fi
}

###############################################################################
# Call script to configure permissions needed for using PAC card
###############################################################################
configure_permission() {
  /usr/bin/env bash "$BSP_ROOT/linux64/libexec/setup_permissions.sh"
  check_res $? "Error: 'setup_permissions.sh' script failed"
}


###############################################################################
# Initialize all PAC cards with default aocx
# Globals:
#   BSP_ROOT
#   PAC_CARD
###############################################################################
init_pac_bsp() {
  local lib_path="$BSP_ROOT/linux64/lib"
  local exec_path="$BSP_ROOT/linux64/libexec"
  local default_aocx="$BSP_ROOT/bringup/aocxs/$PAC_CARD.aocx"

  if [ ! -f "$lib_path/libintel_opae_mmd.so" ]; then
    error "cannot locate libintel_opae_mmd.so library"
  fi

  if [ ! -f "$exec_path/diagnose" ]; then
    error "cannot locate diagnose utility"
  fi

  if [ ! -f "$exec_path/program" ]; then
    error "cannot locate program utility"
  fi

  # Exit with install as success even if default aocx can't be found
  if [ ! -f "$default_aocx" ]; then
    echo "Warning: cannot locate $default_aocx. Must initialize card manually"
    exit 0
  fi

  export LD_LIBRARY_PATH="$LD_LIBRARY_PATH":"$lib_path"
  local devices
  devices=$("$exec_path/diagnose" -probe)
  for dev in $devices; do
    "$exec_path/program" "$dev" "unused" "$default_aocx"
  done
}


###############################################################################
# Main script logic
###############################################################################
check_for_card
check_os
check_for_bringup

if [ -z "$PKG_DIR" ] && [ ! -z "$PAC_BSP_ENV_NO_PKG_INSTALL" ]; then
  echo "Skipping packages install. OPAE must be installed manually"
else
  install_packages
fi

if [ -z "$PAC_BSP_ENV_NO_PERMISSIONS_INSTALL" ]; then
  configure_permission
fi

init_pac_bsp

echo "PAC OpenCL BSP install complete"
