#!/bin/sh
#

#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the Common Development
# and Distribution License Version 1.0 (the "License").
#
# You can obtain a copy of the license at
# http://www.opensource.org/licenses/CDDL-1.0.  See the License for the
# specific language governing permissions and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each file and
# include the License file in a prominent location with the name LICENSE.CDDL.
# If applicable, add the following below this CDDL HEADER, with the fields
# enclosed by brackets "[]" replaced with your own identifying information:
#
# Portions Copyright (c) [yyyy] [name of copyright owner]. All rights reserved.
#
# CDDL HEADER END
#

#
# Copyright (c) 2017--2018, Regents of the University of Minnesota.
# All rights reserved.
#
# Contributors:
#    Ryan S. Elliott
#    John S. Spear
#

#
# Release: This file is part of the kim-api.git repository.
#

collections_info=/usr/lib/libexec/kim-api-v2/kim-api-v2-collections-info
major_version=

make_command="make"
cmake_command="cmake"


# define usage function
usage () {
  local command="`printf $0 | sed 's|.*/\([^/][^/]*\)/*|\1|'`"

  # Follows docopt.org format
  printf "Usage:\n"
  printf "  ${command} list [--with-version] [--log]\n"
  printf "  ${command} set-user-models-dir <directory>\n"
  printf "  ${command} set-user-drivers-dir <directory>\n"
  printf "  ${command} install [--force]\n"
  printf "          (CWD | environment | user | system [--sudo])\n"
  printf "          (<openkim-item-id>... | <local-item-path>... | OpenKIM |\n"
  printf "           OpenKIM_with_history)\n"
  printf "  ${command} reinstall [--interacitive] [--sudo]\n"
  printf "          (<openkim-item-id> | <local-item-path>)...\n"
  printf "  ${command} remove [--interactive] [--sudo] <item-id>...\n"
  printf "  ${command} remove-all [--interactive] [--sudo]\n"
  printf "\n\n"

  printf "list:\n"
  printf "  List installed kim-api models and model drivers\n"
  printf "    * '--with-version' print the kim-api version used to compiled the item.\n"
  printf "    * '--log' generate a kim.log file.  This will show any errors that\n"
  printf "      occur as the utility searches for installed items.\n"
  printf "\n"
  printf "set-user-models-dir:\n"
  printf "  Rewrite configuration file with provided directory\n"
  printf "\n"
  printf "set-user-drivers-dir:\n"
  printf "  Rewrite configuration file with provided directory\n"
  printf "\n"
  printf "install:\n"
  printf "  Install model and/or model driver from openkim.org or from a local path\n"
  printf "    * Installing to the environment collection places items in the first\n"
  printf "      directory of the list.)\n"
  printf "    * 'install --force' is essentially equivalent to 'reinstall', but works\n"
  printf "      even when the item is not currently installed.\n"
  printf "    * 'OpenKIM' installs all 'current' items found at openkim.org,\n"
  printf "      whereas 'OpenKIM_with_history' installs all 'current'\n"
  printf "      and all 'old' items.\n"
  printf "\n"
  printf "reinstall:\n"
  printf "  Remove and reinstall items.\n"
  printf "  WARNING: This will remove and reinstall the entire directory of files\n"
  printf "           associated with the item.\n"
  printf "\n"
  printf "remove:\n"
  printf "  Remove model or model driver.\n"
  printf "  WARNING: This will remove the entire directory of files associated\n"
  printf "           with the item.\n"
  printf "\n"
  printf "remove-all:\n"
  printf "  Remove all items from all collections.\n"
  printf "  WARNING: This will remove the entire directory of files associated\n"
  printf "           with all items.\n"
}

check_version_compatibility () {
  local version="$1"
  local major="`printf -- "${version}" | sed -e 's/\([^.}]*\).*/\1/'`"
  local minor="`printf -- "${version}" | sed -e 's/[^.]*\.\([^.:]*\).*/\1/'`"
  if test \( ${major} -eq ${major_version} \) ; then
    return 0
  else
    return 1
  fi
}

check_item_compatibility () {
  local item_name="$1"
  local query="query={\"kimcode\":\"${item_name}\"}"
  query="${query}"'&fields={"kim-api-version":1}'
  query="${query}"'&database=obj&history=on'
  local version
  version="`wget -q -O - --post-data="${query}" https://query.openkim.org/api`"
  if test $? -ne 0; then
    printf "*** ERROR *** Unable to successfully contact openkim.org to check ${item_name} compatibility.\n"
    return 1
  fi
  version="`printf -- "${version}" | \
                 sed -e 's/\[//g' -e 's/\]//g' \
                 -e 's/{"kim-api-version": "\([0-9.]*\)"}/\1/g'`"
  if test x"" = x"${version}"; then
    printf "*** ERROR *** ${item_name} not found at openkim.org.\n"
    return 1
  else
    if check_version_compatibility "${version}"; then
      return 0
    else
      printf "*** ERROR *** ${item_name} found at openkim.org is not compatible with this version of the KIM API.\n"
      return 1
    fi
  fi
}

check_for_local_build () {
  local name="$1"
  local_build_path=""
  local base_name="`printf -- "${name}" | sed 's|.*/\([^/][^/]*\)/*$|\1|'`"
  if test x"${base_name}" != x"${name}"; then
    local_build_path="`printf -- "${name}" | sed 's|/*$||'`"
    if test x"/" != x"`expr ${local_build_path} : '\(.\)'`"; then
      local_build_path="${PWD}/${local_build_path}"
    fi
    return 0
  else
    return 1
  fi
  # output is: local_build_path
}

get_local_build_item_name () {
  local build_path="$1"
  if test \! -d "${build_path}"; then
    printf "Item path '${build_path}' does not exist.\n"
    return 1
  fi

  # create private temporary directory
  if test x"" = x"${TMPDIR}"; then TMPDIR="/tmp"; fi
  local build_dir="`mktemp -d "${TMPDIR}/kim-api-v2-build-XXXXXXXXXX"`"
  if test $? -ne 0; then
    printf "Unable to create temporary directory.\n"
    return 1;
  fi

  (  # subshell
    cd "${build_dir}" || return 1
    cp -r "${build_path}" "./item-source"
    cd item-source && mkdir build && cd build
    ${cmake_command} ../ > ./cmake-log.txt 2>&1

    local item_type="`grep -- "model-type:" model-info.txt | sed -e 's/^model-type://'`"
    case "${item_type}" in
      stand-alone-model|parameterized-model|simulator-model)
        item_name="`grep -- "model-name:" model-info.txt | sed -e 's/^model-name://'`"
        ;;
      model-driver)
        item_name="`grep -- "driver-name:" model-info.txt | sed -e 's/^driver-name://'`"
        ;;
      *)
        item_name=""
        printf "Item type '${item_type}' unknown.\n"
        error="true"
        ;;
    esac

    if test x"true" = x"${error}"; then
      return 1
    else
      return 0
    fi
  ) || return 1  # exit subshell

  rm -rf "${build_dir}" || return 1

  return 0
  # output is: item_name
}

check_config_file () {
  local config_file_name drivers_dir models_dir
  config_file_name="`${collections_info} config_file name`"; if test $? -ne 0; then return 1; fi
  drivers_dir="`${collections_info} config_file model_drivers`"; if test $? -ne 0; then return 1; fi
  models_dir="`${collections_info} config_file models`"; if test $? -ne 0; then return 1; fi

  if test \! -f "${config_file_name}" -o x"" = x"${drivers_dir}" -o x"" = x"${models_dir}"; then
    printf "Invalid kim-api configuration file.\n"
    return 1
  fi
}

rewrite_config_file_models_dir () {
  if test -d "$1"; then
    local config_file_name drivers_dir models_dir
    config_file_name="`${collections_info} config_file name`"; if test $? -ne 0; then return 1; fi
    drivers_dir="`${collections_info} config_file model_drivers`"; if test $? -ne 0; then return 1; fi
    models_dir="`cd "$1" && pwd`"; if test $? -ne 0; then return 1; fi

    printf "model_drivers_dir = %s\n" "${drivers_dir}" >  "${config_file_name}" || return 1
    printf "models_dir = %s\n" "${models_dir}"         >> "${config_file_name}"
  else
    printf "Directory '%s' does not exist.\n" "$1"
    return 1
  fi
}

rewrite_config_file_drivers_dir () {
  if test -d "$1"; then
    local config_file_name drivers_dir models_dir
    config_file_name="`${collections_info} config_file name`"; if test $? -ne 0; then return 1; fi
    drivers_dir="`cd "$1" && pwd`"; if test $? -ne 0; then return 1; fi
    models_dir="`${collections_info} config_file models`"; if test $? -ne 0; then return 1; fi

    printf "model_drivers_dir = %s\n" "${drivers_dir}" >  "${config_file_name}" || return 1
    printf "models_dir = %s\n" "${models_dir}"         >> "${config_file_name}"
  else
    printf "Directory '%s' does not exist." "$1"
    return 1
  fi
}

get_build_install_item () {
  local install_collection="$1"
  local item_name="$2"
  local force="$3"
  local use_sudo="$4"
  local PASSWORD="$5"
  local found_item=""
  local item_type=""
  local local_build_path=""

  # check for non-empty item_name
  if test x"" = x"${item_name}"; then
    printf "Empty item id.\n"
    return 1
  fi

  # make changes for installing to CWD collection, if necessary
  if test x"${install_collection}" = x"CWD"; then
    export KIM_API_MODEL_DRIVERS_DIR=${PWD}
    export KIM_API_MODELS_DIR=${PWD}
    install_collection="environment"
  fi

  # check for local build and get item name
  if check_for_local_build "${item_name}"; then  # sets local_build_path
    if ! get_local_build_item_name "${local_build_path}"; then  # sets item_name
      # error message already printed
      return 1
    fi
  fi

  # check for existing item
  if test x"OpenKIM" = x"${item_name}"; then
    found_item=""
    item_type="OpenKIM"
  elif test x"OpenKIM_with_history" = x"${item_name}"; then
    found_item=""
    item_type="OpenKIM_with_history"
  else
    found_item="`${collections_info} model_drivers find "${item_name}"`"; if test $? -ne 0; then return 1; fi
    found_item="${found_item}""`${collections_info} models find "${item_name}"`"; if test $? -ne 0; then return 1; fi
  fi
  if test x"" != x"${found_item}"; then
    local item_collection="`printf -- "${found_item}" | sed -e 's/ .*//'`"
    printf "Item '${item_name}' already installed in collection '${item_collection}'.\n"
    if test x"${force}" = x"yes"; then
      if ! remove_item "${item_name}" "${use_sudo}" "${PASSWORD}" "interactive-no"; then
        return 1
      fi
    else
      if test x"${item_collection}" = x"${install_collection}"; then
        return 0
      else
        return 1
      fi
    fi
  fi

  # create private temporary directory
  if test x"" = x"${TMPDIR}"; then TMPDIR="/tmp"; fi
  local build_dir="`mktemp -d "${TMPDIR}/kim-api-v2-build-XXXXXXXXXX"`"
  if test $? -ne 0; then
    printf "Unable to create temporary directory.\n"
    return 1;
  fi

  (  # subshell
    cd "${build_dir}" || return 1

    # download item (and possibly its driver)
    if test x"OpenKIM" = x"${item_type}" -o x"OpenKIM_with_history" = x"${item_type}"; then
      local query='query={"type":"mo","kim-api-version":{"$regex":"^'"${major_version}"'\\."}}'
      query="${query}"'&fields={"kimcode":1, "kim-api-version":1}'
      query="${query}"'&database=obj'
      if test x"OpenKIM_with_history" = x"${item_type}"; then
        query="${query}"'&history=on'
      fi
      local list
      list="`wget -q -O - --post-data="${query}" https://query.openkim.org/api`"
      if test $? -ne 0; then  # wget failed
        printf "*** ERROR *** Unable to successfully contact openkim.org to download models.\n"
        return 1
      fi
      list="`printf -- "${list}" | \
                     sed -e 's/\[//g' -e 's/\]//g' \
                     -e 's/{"kim-api-version": "\([0-9.]*\)", "kimcode": "\([^"]*\)"},*/\1:\2/g'`"
      for version in ${list}; do \
        if check_version_compatibility "${version}"; then
          local modname="`printf -- ${version} | sed -e s/[^:]*://`"
          get_build_install_item "$install_collection" "${modname}" "${force}" "${use_sudo}" "${PASSWORD}" || return 1
        fi
      done
    else
      if test x"" = x"${local_build_path}"; then
        if check_item_compatibility "${item_name}"; then
          printf "Downloading..............@%s\n" "${item_name}" | sed -e 's/ /./g' -e 's/@/ /g'
          if wget -q --content-disposition "https://openkim.org/download/${item_name}.txz"; then
            tar Jxf "${item_name}.txz" 2>&1 | sed -e 's/^/                /' &&
              rm -f "${item_name}.txz"
          else
            printf "                Unable to download ${item_name} from https://openkim.org.  Check the KIM Item ID for errors.\n"
            return 1
          fi
        else
          return 1
        fi
      else
        cp -r "${local_build_path}" "./${item_name}"
      fi
      cd "./${item_name}" && mkdir build && cd build
      if ! ${cmake_command} ../ -DKIM_API_INSTALL_COLLECTION="`printf ${install_collection} | tr "[:lower:]" "[:upper:]"`" > ./cmake-log.txt 2>&1; then
        cat ./cmake-log.txt
        return 1
      fi
      item_type="`grep "model-type:" model-info.txt | sed -e 's/model-type://'`"
      if test x"parameterized-model" = x"${item_type}"; then
        dvr="`grep "driver-name:" model-info.txt | sed -e 's/driver-name://'`"
        if test x"" != x"`${collections_info} model_drivers find "${dvr}"`"; then
          printf "Usingdriver...@%s\n" "${dvr}" | sed -e 's/ /./g' -e 's/@/ /g' || return 1
        else
          printf "This model needs its driver '${dvr}', trying to find it at openkim.org.\n"
          # try openkim.org first
          if ! get_build_install_item "${install_collection}" "${dvr}" "${force}" "${use_sudo}" "${PASSWORD}"; then
            if test x"" != x"${local_build}"; then
              # now try local
              printf "Now trying to find '${dvr}' locally.\n"
              dvr="`printf "${local_build}" | sed "s|^\(.*/\)${item_name}\$|\1${dvr}|"`"
              get_build_install_item "${install_collection}" "${dvr}" "${force}" "${use_sudo}" "${PASSWORD}" || return 1
            fi
          fi
        fi
        if ! ((${make_command} clean && ${make_command}) > ./make-log.txt 2>&1 && \
                if test x"sudo-yes" = x"${use_sudo}"; then
                  printf -- "${PASSWORD}\n" | sudo -k -S ${make_command} install 2> /dev/null
                else
                  ${make_command} install
                fi); then
          cat ./make-log.txt
          return 1
        fi
      elif test x"stand-alone-model" = x"${item_type}" -o \
                x"model-driver"      = x"${item_type}" -o \
                x"simulator-model"   = x"${item_type}"; then
        if ! ((${make_command} clean && ${make_command}) > ./make-log.txt 2>&1 && \
                if test x"sudo-yes" = x"${use_sudo}"; then
                  printf -- "${PASSWORD}\n" | sudo -k -S ${make_command} install 2> /dev/null
                else
                  ${make_command} install
                fi); then
          cat ./make-log.txt
          return 1
        fi
      else
        printf "Item '${item_name}' of unknown type '${item_type}'.\n"
        return 1
      fi
    fi
  ) || return 1  # exit subshell

  rm -rf "${build_dir}" || return 1
}

remove_item () {
  local item_name="$1"
  local use_sudo="$2"
  local PASSWORD="$3"
  local interactive="$4"
  local found_item=""
  local item_type=""
  local confirmed=1

  # check for existing item
  found_item="`${collections_info} model_drivers find "${item_name}"`"
  if test x"" = x"${found_item}"; then
    found_item="`${collections_info} models find "${item_name}"`"
    if test x"" = x"${found_item}"; then
      printf "Item '${item_name}' not installed.\n"
      return 1
    else
      item_type="models"
    fi
  else
    item_type="model_drivers"
  fi

  local item_dir
  item_dir="`${collections_info} "${item_type}" find "${item_name}" | sed -e 's/^[^ ]* [^ ]* \([^ ]*\).*/\1/'`""/${item_name}"; if test $? -ne 0; then return 1; fi

  printf "Removing '%s'. " "${item_dir}"
  if test x"${interactive}" = x"interactive"; then
    printf "Continue? "
    if get_confirmation; then
      confirmed=0
    fi
  else
    confirmed=0
  fi
  if test 0 -eq ${confirmed}; then
    if test x"sudo-yes" = x"${use_sudo}"; then
      printf -- "${PASSWORD}\n" | sudo -k -S rm -rf "${item_dir}" 2> /dev/null || return 1
    else
      rm -rf "${item_dir}" || return 1
    fi
    printf "[done]\n"
  else
    printf "[skipped]\n"
  fi
}

split_drivers_list_into_collections () {
  local with_version=$2

  drivers_cwd_collection=""; number_drivers_cwd=0
  drivers_env_collection=""; number_drivers_env=0
  drivers_usr_collection=""; number_drivers_usr=0
  drivers_sys_collection=""; number_drivers_sys=0
  while read line; do
    local collection="`printf -- "$line" | sed -e 's/\([^ ]*\) .*/\1/'`"
    local name="`printf -- "$line" | sed -e 's/[^ ]* \([^ ]*\) .*/\1/'`"
    local directory="`printf -- "$line" | sed -e 's/[^ ]* [^ ]* \([^ ]*\) .*/\1/'`"
    local version="`printf -- "$line" | sed -e 's/[^ ]* [^ ]* [^ ]* \([^ ]*\).*/\1/'`"
    case $collection in
      "")
      # empty do nothing
      ;;
      CWD)
        number_drivers_cwd="`expr $number_drivers_cwd \+ 1`"
        drivers_cwd_collection="${drivers_cwd_collection}\t${name}"
        if test x"${with_version}" = x"yes"; then
          drivers_cwd_collection="${drivers_cwd_collection}\n\t\t${version}"
        fi
        drivers_cwd_collection="${drivers_cwd_collection}\n"
        ;;
      environment)
        number_drivers_env="`expr $number_drivers_env \+ 1`"
        drivers_env_collection="${drivers_env_collection}\t${name}"
        if test x"${with_version}" = x"yes"; then
          drivers_env_collection="${drivers_env_collection}\n\t\t${version}"
        fi
        drivers_env_collection="${drivers_env_collection}\n"
        ;;
      user)
        number_drivers_usr="`expr $number_drivers_usr \+ 1`"
        drivers_usr_collection="${drivers_usr_collection}\t${name}"
        if test x"${with_version}" = x"yes"; then
          drivers_usr_collection="${drivers_usr_collection}\n\t\t${version}"
        fi
        drivers_usr_collection="${drivers_usr_collection}\n"
        ;;
      system)
        number_drivers_sys="`expr $number_drivers_sys \+ 1`"
        drivers_sys_collection="${drivers_sys_collection}\t${name}"
        if test x"${with_version}" = x"yes"; then
          drivers_sys_collection="${drivers_sys_collection}\n\t\t${version}"
        fi
        drivers_sys_collection="${drivers_sys_collection}\n"
        ;;
      *)
        printf "Error unknown collection!\n"
        exit 1
        ;;
    esac
  done <<EOF
$1
EOF
}

split_models_list_into_collections () {
  local with_version=$2

  models_cwd_collection=""; number_models_cwd=0
  models_env_collection=""; number_models_env=0
  models_usr_collection=""; number_models_usr=0
  models_sys_collection=""; number_models_sys=0
  while read line; do
    local collection="`printf -- "$line" | sed -e 's/\([^ ]*\) .*/\1/'`"
    local name="`printf -- "$line" | sed -e 's/[^ ]* \([^ ]*\) .*/\1/'`"
    local directory="`printf -- "$line" | sed -e 's/[^ ]* [^ ]* \([^ ]*\) .*/\1/'`"
    local version="`printf -- "$line" | sed -e 's/[^ ]* [^ ]* [^ ]* \([^ ]*\).*/\1/'`"
    case $collection in
      "")
      # empty do nothing
      ;;
      CWD)
        number_models_cwd="`expr $number_models_cwd \+ 1`"
        models_cwd_collection="${models_cwd_collection}\t${name}"
        if test x"${with_version}" = x"yes"; then
          models_cwd_collection="${models_cwd_collection}\n\t\t${version}"
        fi
        models_cwd_collection="${models_cwd_collection}\n"
        ;;
      environment)
        number_models_env="`expr $number_models_env \+ 1`"
        models_env_collection="${models_env_collection}\t${name}"
        if test x"${with_version}" = x"yes"; then
          models_env_collection="${models_env_collection}\n\t\t${version}"
        fi
        models_env_collection="${models_env_collection}\n"
        ;;
      user)
        number_models_usr="`expr $number_models_usr \+ 1`"
        models_usr_collection="${models_usr_collection}\t${name}"
        if test x"${with_version}" = x"yes"; then
          models_usr_collection="${models_usr_collection}\n\t\t${version}"
        fi
        models_usr_collection="${models_usr_collection}\n"
        ;;
      system)
        number_models_sys="`expr $number_models_sys \+ 1`"
        models_sys_collection="${models_sys_collection}\t${name}"
        if test x"${with_version}" = x"yes"; then
          models_sys_collection="${models_sys_collection}\n\t\t${version}"
        fi
        models_sys_collection="${models_sys_collection}\n"
        ;;
      *)
        printf "Error unknown collection!\n"
        exit 1
        ;;
    esac
  done <<EOF
$1
EOF
}

print_separator_line () {
  printf "%79s\n" " " | sed -e "s/ /$1/g"
}

print_list_of_drivers_and_models () {
  local with_version=$1
  local with_log
  if test x"$2" = x"yes"; then
    with_log="--log"
  else
    with_log=""
  fi

  config_env_name="`${collections_info} config_file env | sed -e 's/ .*//'`"; if test $? -ne 0; then return 1; fi
  config_env="`${collections_info} config_file env | sed -e 's/^[^ ]* //'`"; if test $? -ne 0; then return 1; fi
  if test x"" = x"${config_env}"; then config_env="--empty--"; fi
  drivers_env_name="`${collections_info} env env | sed -e 's/^[^ ]* //'`"; if test $? -ne 0; then return 1; fi
  drivers_env="`${collections_info} env model_drivers`"; if test $? -ne 0; then return 1; fi
  if test x"" = x"${drivers_env}"; then drivers_env="--empty--"; fi
  models_env_name="`${collections_info} env env | sed -e 's/ .*//'`"; if test $? -ne 0; then return 1; fi
  models_env="`${collections_info} env models`"; if test $? -ne 0; then return 1; fi
  if test x"" = x"${models_env}"; then models_env="--empty--"; fi

  printf "\n\n"
  printf "Knowledgebase of Interatomic Models (KIM)"
  printf -- "  ---  Model Collections Listing\n"
  print_separator_line "="
  printf "\n"
  printf "kim-api library: \n\t%s\n" "`${collections_info} system library`"
  printf "\n"
  printf "kim-api configuration file:\n\t%s\n" \
         "`${collections_info} config_file name`"
  printf "\n\n"
  printf "Environment Variables:\n"
  print_separator_line "-"
  printf -- "${config_env_name}:\n"
  printf -- "\t${config_env}\n"
  printf "\n"
  printf -- "${drivers_env_name}:\n"
  printf -- "%s\n" "`printf -- "${drivers_env}" | sed -e 's/^/	/g'`"
  printf "\n"
  printf -- "${models_env_name}:\n"
  printf -- "%s\n" "`printf -- "${models_env}" | sed -e 's/^/	/g'`"
  printf "\n"
  print_separator_line "="


  model_drivers_list="`${collections_info} model_drivers ${with_log}`"; if test $? -ne 0; then return 1; fi
  split_drivers_list_into_collections "${model_drivers_list}" "${with_version}"
  models_list="`${collections_info} models ${with_log}`"; if test $? -ne 0; then return 1; fi
  split_models_list_into_collections "${models_list}" "${with_version}"

  printf "\n\n\n"
  printf "Current Working Directory Collection\n"
  print_separator_line "-"
  printf "Drivers: %s\n" "${PWD}"
  if test $number_drivers_cwd -gt 0; then
    printf "${drivers_cwd_collection}"
  else
    printf "\t--empty--\n"
  fi
  printf "\n"

  printf "Models: %s\n" "${PWD}"
  if test $number_models_cwd -gt 0; then
    printf -- "${models_cwd_collection}"
  else
    printf "\t--empty--\n"
  fi
  printf "\n\n"

  printf "Environment Variable Collection\n"
  print_separator_line "-"
  printf "Drivers: "
  if test x"--empty--" = x"${drivers_env}"; then
    printf "%s" ${drivers_env}
  else
    printf "'%s' " ${drivers_env}
  fi
  printf "\n"
  if test $number_drivers_env -gt 0; then
    printf -- "${drivers_env_collection}"
  else
    printf "\t--empty--\n"
  fi
  printf "\n"
  printf "Models: "
  if test x"--empty--" = x"${models_env}"; then
    printf "%s" ${models_env}
  else
    printf "'%s' " ${models_env}
  fi
  printf "\n"
  if test $number_models_env -gt 0; then
    printf -- "${models_env_collection}"
  else
    printf "\t--empty--\n"
  fi
  printf "\n\n"

  drivers_usr="`${collections_info} config_file model_drivers`"; if test $? -ne 0; then return 1; fi
  if test x"" = x"${drivers_usr}"; then drivers_usr="--empty--"; fi
  models_usr="`${collections_info} config_file models`"; if test $? -ne 0; then return 1; fi
  if test x"" = x"${models_usr}"; then models_usr="--empty--"; fi
  printf "User Collection\n"
  print_separator_line "-"
  printf "Drivers: %s\n" "${drivers_usr}"
  if test $number_drivers_usr -gt 0; then
    printf -- "${drivers_usr_collection}"
  else
    printf "\t--empty--\n"
  fi
  printf "\n"
  printf "Models: %s\n" "${models_usr}"
  if test $number_models_usr -gt 0; then
    printf -- "${models_usr_collection}"
  else
    printf "\t--empty--\n"
  fi
  printf "\n\n"

  printf "System Collection\n"
  print_separator_line "-"
  printf "Drivers: %s\n" "`${collections_info} system model_drivers`"
  if test $number_drivers_sys -gt 0; then
    printf -- "${drivers_sys_collection}"
  else
    printf "\t--empty--\n"
  fi
  printf "\n\n"
  printf "Models: %s\n" "`${collections_info} system models`"
  if test $number_models_sys -gt 0; then
    printf -- "${models_sys_collection}"
  else
    printf "\t--empty--\n"
  fi
  printf "\n"
}


get_password () {
  printf "Enter Password : "
  stty -echo
  trap 'stty echo' EXIT
  read PASSWORD
  stty echo
  trap - EXIT
  printf "\n"
  if ! (printf -- "${PASSWORD}\n" | \
          sudo -k -S printf "" > /dev/null 2>&1); then
    printf "Bad password.\n"
    return 1
  fi
}

get_confirmation () {
  local ANSWER
  printf "[y/n] : "
  read ANSWER
  if test x"${ANSWER}" = x"y"; then
    return 0;
  else
    return 1;
  fi
}

######## main script ########

# check that command is given
if test $# -lt 1; then
  usage
  exit 1
else
  command=$1
  case $command in
    list|set-user-drivers-dir|set-user-models-dir|install|reinstall|remove|remove-all)
    ;;
    *)
      printf "unknown command: %s\n\n" $command
      usage
      exit 1
  esac
fi

if ! check_config_file; then
  printf "Aborting!\n"
  exit 1
fi

case $command in
  list)
    if test $# -gt 3; then
      usage
      exit 1
    fi
    shift
    list_with_version="no"
    list_with_log="no"
    for arg in "$@"; do
      case "$arg" in
        --with-version)
          list_with_version="yes"
          ;;
        --log)
          list_with_log="yes"
          ;;
        *)
          printf "unknown option %s\n\n" "$arg"
          usage
          exit 1
          ;;
      esac
    done
    print_list_of_drivers_and_models "${list_with_version}" "${list_with_log}"
    ;;
  set-user-models-dir)
    if test $# -lt 2; then
      usage
      exit 1
    else
      subcommand=$2
      if ! rewrite_config_file_models_dir "$subcommand"; then
        printf "\nAborting!\n"
        exit 1
      else
        printf "\nSuccess!\n."
      fi
    fi
    ;;
  set-user-drivers-dir)
    if test $# -lt 2; then
      usage
      exit 1
    else
      subcommand=$2
      if ! rewrite_config_file_drivers_dir "$subcommand"; then
        printf "\nAborting!\n"
        exit 1
      else
        printf "\nSuccess!\n"
      fi
    fi
    ;;
  install)
    if test $# -lt 3; then
      usage
      exit 1
    else
      force="no"
      if test x"$2" = x"--force"; then
        force="yes"
        shift
      fi
      subcommand=$2
      shift
      shift
      case $subcommand in
        CWD|environment|user)
          for item_id in $@; do
            if ! get_build_install_item "${subcommand}" "${item_id}" "${force}" "sudo-no" ""; then
              printf "\nAborting!\n"
              exit 1
            else
              printf "\nSuccess!\n"
            fi
          done
          ;;
        system)
          PASSWORD=""
          if test x"--sudo" = x"$1"; then
            shift
            use_sudo="sudo-yes"
            if ! get_password; then
              printf "\nAborting!\n"
              exit 1
            fi
          else
            use_sudo="sudo-no"
          fi
          for item_id in $@; do
            if ! get_build_install_item "system" "${item_id}" "${force}" "${use_sudo}" "${PASSWORD}"; then
              printf "\nAborting!\n"
              exit 1
            else
              printf "\nSuccess!\n"
            fi
          done
          ;;
        *)
          printf "unknown subcommand: %s\n\n" $subcommand
          usage
          exit 1
          ;;
      esac
    fi
    ;;
  reinstall)
    if test $# -lt 2; then
      usage
      exit 1
    else
      shift
      use_sudo="sudo-no"
      use_interactive="interactive-no"
      while test x"--" = x"`printf -- "$1" | sed -e 's/^\(..\).*/\1/'`"; do
        case $1 in
          --interactive)
            use_interactive="interactive"
            ;;
          --sudo)
            use_sudo="sudo-yes"
            if ! get_password; then
              printf "\nAborting!\n"
              exit 1
            fi
            ;;
          *)
            printf "unknown option: %s\n\n" $1
            usage
            exit 1
            ;;
        esac
        shift
      done
    fi
    printf "This will remove and reinstall all files associated with these items.\n"
    printf "  Use the '--interactive' option to request confirmation\n"
    printf "  before attempting to remove each item.\n"
    printf "\n"
    printf "Are you sure you want to proceed? "
    if get_confirmation; then
      for item_id in $@; do
        if check_for_local_build "${item_id}"; then  # sets local_build_path
          if ! get_local_build_item_name "${local_build_path}"; then  # sets item_name
            printf "\nAborting!\n"
            exit 1
          fi
        else
          if ! check_item_compatibility "${item_id}"; then
            printf "\nAborting!\n"
            exit 1
          else
            item_name="${item_id}"
          fi
        fi
        found_item="`${collections_info} model_drivers find "${item_name}"` `${collections_info} models find "${item_name}"`"
        if test \! x"" = x"${found_item}"; then
          item_collection="`printf "${found_item}" | sed -e 's/^[[:space:]]*\([^[:space:]]*\) .*/\1/'`"
          if ! (remove_item "${item_name}" "${use_sudo}" "${PASSWORD}" "${use_interactive}" && \
                  get_build_install_item "${item_collection}" "${item_id}" "${use_sudo}" "${PASSWORD}" "no"); then
            printf "\nAborting!\n"
            exit 1
          fi
        else
          printf "\nAborting!\n"
          exit 1
        fi
      done
      printf "\nSuccess!\n"
    fi
    ;;
  remove)
    if test $# -lt 2; then
      usage
      exit 1
    else
      shift
      use_sudo="sudo-no"
      use_interactive="interactive-no"
      while test x"--" = x"`printf -- "$1" | sed -e 's/^\(..\).*/\1/'`"; do
        case $1 in
          --interactive)
            use_interactive="interactive"
            ;;
          --sudo)
            use_sudo="sudo-yes"
            if ! get_password; then
              printf "\nAborting!\n"
              exit 1
            fi
            ;;
          *)
            printf "unknown option: %s\n\n" $1
            usage
            exit 1
            ;;
        esac
        shift
      done
    fi
    printf "This will remove all files associated with these items.\n"
    printf "  Use the '--interactive' option to request confirmation\n"
    printf "  before attempting to remove each item.\n"
    printf "\n"
    printf "Are you sure you want to proceed? "
    if get_confirmation; then
      for item_id in $@; do
        if ! remove_item "${item_id}" "${use_sudo}" "${PASSWORD}" "${use_interactive}"; then
          printf "\nAborting!\n"
          exit 1
        fi
      done
      printf "\nSuccess!\n"
    else
      printf "\nAborting!\n"
    fi
    ;;
  remove-all)
    shift
    use_sudo="sudo-no"
    use_interactive="interactive-no"
    while test x"--" = x"`printf -- "$1" | sed -e 's/^\(..\).*/\1/'`"; do
      case $1 in
        --interactive)
          use_interactive="interactive"
          ;;
        --sudo)
          use_sudo="sudo-yes"
          if ! get_password; then
            printf "\nAborting!\n"
            exit 1
          fi
          ;;
        *)
          printf "unknown option: %s\n\n" $1
          usage
          exit 1
          ;;
      esac
      shift
    done
    printf "This will remove all files associated with all items in the 'environment',\n"
    printf "'user', and 'system' collections.\n"
    printf "  Use the '--interactive' option to request confirmation\n"
    printf "  before attempting to remove each item.\n"
    printf "\n"
    printf "Are you sure you want to proceed? "
    if get_confirmation; then
      # get full list and loop over it to remove
      for item_id in `${collections_info} model_drivers | sed -e 's/^[^[:space:]]* \([^[:space:]]*\).*/\1/'`; do
        if ! remove_item "${item_id}" "${use_sudo}" "${PASSWORD}" "${use_interactive}"; then
          printf "\n Aborting!\n"
          exit 1
        fi
      done
      for item_id in `${collections_info} models | sed -e 's/^[^[:space:]]* \([^[:space:]]*\).*/\1/'`; do
        if ! remove_item "${item_id}" "${use_sudo}" "${PASSWORD}" "${use_interactive}"; then
          printf "\n Aborting!\n"
          exit 1
        fi
      done
      printf "\nSuccess!\n"
    else
      printf "\nAborting!\n"
      exit 1
    fi
    ;;
esac
