#!/bin/bash

##############################################################################
# DO NOT MODIFY THIS FILE. Instead, modify 'helpers/custom'.
##############################################################################

COOKBOOK_NAME="$(basename $0)"
if [ -z "$SHOESTRAP_BASE" ]; then
    DIR="$( cd "$( dirname "$0" )" && pwd )"
else
    DIR="$SHOESTRAP_BASE"
fi

#
# Run a given recipe.
#
# Arguments can be passed to the 'recipe' function. They will be accessible by
# the recipe as $2, $3, $4, etc.
#
recipe () {
  CURRENT_RECIPE_NAME=$1
  DEFAULT_ASSETS_PATH="$DIR/assets/default/$CURRENT_RECIPE_NAME"
  COOKBOOK_ASSETS_PATH="$DIR/assets/$COOKBOOK_NAME/$CURRENT_RECIPE_NAME"
  local default_recipe="$DIR/recipes/default/$CURRENT_RECIPE_NAME"
  local cookbook_recipe="$DIR/recipes/$COOKBOOK_NAME/$CURRENT_RECIPE_NAME"

  if [ -f $cookbook_recipe ]; then
    log "Running recipe '$cookbook_recipe'..." 1
    separator
    . $cookbook_recipe
  elif [ -f $default_recipe ]; then
    log "Running recipe '$default_recipe'..." 1
    separator
    . $default_recipe
  else
    error "Could not find recipe for '$CURRENT_RECIPE_NAME'. Fail!"
  fi

  cd $DIR
}

#
# Prints the 'finished' banner.
#
finished () {
  spacer 1
  separator "="
  echo " FINISHED: '$COOKBOOK_NAME'"
  separator "="
  spacer 1
}

#
# Writes a log line to the screen
#
# If specified, the first parameter is the number of empty lines to print
# before the log message.
#
# If specified, the second parameter is the number of empty lines to print
# before the log message.
#
log () {
  if [[ $2 -gt 0 ]]; then
    spacer $2
  fi

  echo " * $1"

  if [[ $3 -gt 0 ]]; then
    spacer $3
  fi
}

#
# Writes an error log line to the screen and exit with an error code.
#
error () {
  spacer 2
  echo " -> $1"
  spacer 2
  exit 1
}

#
# Write one or many empty lines to the screen.
#
spacer () {
  if [ $1 ]; then
    local spaces=$1
  else
    local spaces=1
  fi

  for (( i=0; i<$spaces; i++ )) do
    echo ""
  done
}

#
# noop
#
noop () {
  return 0
}

#
# Write a separator to the screen.
#
# You can optionally specify the separator character. Default is '-'.
#
separator () {
  if [ $1 ]; then
    local char=$1
  else
    local char='-'
  fi

  local width=$(tput cols)

  for (( i=0; i < $width-2; i++ )) do
    local output="$output$char"
  done
  echo $output
}

#
# Update packages in package manager.
#
package_update () {
  log "Updating package manager..." 0 1
  detect_package_manager

  if [ "$PACKAGE_MANAGER" == 'apt-get' ]; then
    apt-get update -y
  elif [ "$PACKAGE_MANAGER" == 'yum' ]; then
    yum check-update -y
  elif [ "$PACKAGE_MANAGER" == 'port' ]; then
    port selfupdate
  elif [ "$PACKAGE_MANAGER" == 'brew' ]; then
    brew update
  else
    error "Unknown package manager: $PACKAGE_MANAGER"
  fi

  if [ $? -ne 0 ]; then
    error "An error occured while updating packages. Fail!"
  else
    spacer 2
  fi
}


sudo_package_update () {
  log "Updating package manager..." 0 1
  detect_package_manager

  if [ "$PACKAGE_MANAGER" == 'apt-get' ]; then
    sudo apt-get update -y
  elif [ "$PACKAGE_MANAGER" == 'yum' ]; then
    sudo yum check-update -y
  elif [ "$PACKAGE_MANAGER" == 'port' ]; then
    sudo port selfupdate
  elif [ "$PACKAGE_MANAGER" == 'brew' ]; then
    brew update
  else
    error "Unknown package manager: $PACKAGE_MANAGER"
  fi

  if [ $? -ne 0 ]; then
    error "An error occured while updating packages. Fail!"
  else
    spacer 2
  fi
}

#
# Install a package through package manager
#
package () {
  log "Installing package '$1'..."
  detect_package_manager

  test_package_installed $1 > /dev/null 2>&1

  if [ $? -eq 0 ]; then
    log "Package '$1' is already installed. Skipping."
    return 0
  fi

  if [ "$PACKAGE_MANAGER" == 'apt-get' ]; then
    DEBIAN_FRONTEND=noninteractive apt-get install -y --force-yes $1
  elif [ "$PACKAGE_MANAGER" == 'yum' ]; then
    yum install -y $1
  elif [ "$PACKAGE_MANAGER" == 'port' ]; then
    port install $1
  elif [ "$PACKAGE_MANAGER" == 'brew' ]; then
    brew install $1
  else
    error "Unknown package manager: $PACKAGE_MANAGER"
  fi

  if [ $? -ne 0 ]; then
    error "An error occured while installing package '$1'. Fail!"
  else
    spacer 2
  fi
}


sudo_package () {
  log "Installing package '$1'..."
  detect_package_manager

  test_package_installed $1 > /dev/null 2>&1

  if [ $? -eq 0 ]; then
    log "Package '$1' is already installed. Skipping."
    return 0
  fi

  if [ "$PACKAGE_MANAGER" == 'apt-get' ]; then
    DEBIAN_FRONTEND=noninteractive sudo apt-get install -y --force-yes $1
  elif [ "$PACKAGE_MANAGER" == 'yum' ]; then
    sudo yum install -y $1
  elif [ "$PACKAGE_MANAGER" == 'port' ]; then
    sudo port install $1
  elif [ "$PACKAGE_MANAGER" == 'brew' ]; then
    brew install $1
  else
    error "Unknown package manager: $PACKAGE_MANAGER"
  fi

  if [ $? -ne 0 ]; then
    error "An error occured while installing package '$1'. Fail!"
  else
    spacer 2
  fi
}

#
# Determine if a package is installed or not.
#
# If package is installed, function will return 0. If not, it will return 1.
#
test_package_installed () {
  detect_package_manager

  # When many packages are specified, skip test.
  if [ $# -gt 1 ]; then
    return 1
  fi

  if [ "$PACKAGE_MANAGER" == 'apt-get' ]; then
    dpkg-query -l "$1" | grep -q ^.i
    return $?
  fi

  # Don't know how to detect if a package is installed with other package managers.
  return 1
}

#
# Determine which package manager is in use on the system.
#
detect_package_manager () {
  if [ "$PACKAGE_MANAGER" != "" ]; then
    return 0
  fi

  if command_exist apt-get; then
    PACKAGE_MANAGER='apt-get'
  elif command_exist yum; then
    PACKAGE_MANAGER='yum'
  elif command_exist port; then
    PACKAGE_MANAGER='port'
  elif command_exist brew; then
    PACKAGE_MANAGER='brew'
  else
    error "Could not find a package manager. Fail!"
  fi

  log "Detected package manager: $PACKAGE_MANAGER"
  return 0
}

#
# Determines if a command exist on the system.
#
command_exist () {
  command -v "$1" > /dev/null 2>&1;
}

#
# Copy a file from the assets folder to the specified location.
#
copy () {
  local cookbook_assets_source="$COOKBOOK_ASSETS_PATH/$1"
  local default_assets_source="$DEFAULT_ASSETS_PATH/$1"
  local target="$2"

  if [ -f "$cookbook_assets_source" ]; then
    log "Copying $cookbook_assets_source to $target..."
    cp "$cookbook_assets_source" "$target"
  elif [ -f "$default_assets_source" ]; then
    log "Copying $default_assets_source to $target..."
    cp "$default_assets_source" "$target"
  else
    error "Could not find '$1' to copy. Fail!"
  fi
}

#
# Link a file from the assets folder to the specified location.
#
link () {
  local src="$1"
  local cookbook_assets_source="$COOKBOOK_ASSETS_PATH/$1"
  local default_assets_source="$DEFAULT_ASSETS_PATH/$1"
  local target="$2"

  if [ -f "$src" ]; then
    src="$src"
  elif [ -d "$src" ]; then
    src="$src"
  elif [ -f "$cookbook_assets_source" ]; then
    src="$cookbook_assets_source"
  elif [ -f $default_assets_source ]; then
    src="$default_assets_source"
  elif [ -d "$cookbook_assets_source" ]; then
    src="$cookbook_assets_source"
  elif [ -d $default_assets_source ]; then
    src="$default_assets_source"
  else
    error "Could not find '$1' to link Fail!"
  fi

  ln -s "$src" "$target"
}

#
# Attempt to link a file if it doesn't already exist
#
try_link () {
  local src="$1"
  local cookbook_assets_source="$COOKBOOK_ASSETS_PATH/$1"
  local default_assets_source="$DEFAULT_ASSETS_PATH/$1"
  local target="$2"

  if [ -f "$src" ]; then
    src="$src"
  elif [ -d "$src" ]; then
    src="$src"
  elif [ -f "$cookbook_assets_source" ]; then
    src="$cookbook_assets_source"
  elif [ -f $default_assets_source ]; then
    src="$default_assets_source"
  elif [ -d "$cookbook_assets_source" ]; then
    src="$cookbook_assets_source"
  elif [ -d $default_assets_source ]; then
    src="$default_assets_source"
  else
    error "Could not find '$1' to link Fail!"
  fi

  if [ -L "$2" ] && [ "$(readlink $2)" == "$src" ] ; then
    log "Link already exists: $2"
  else
    log "Creating link: $2 -> $src"
    link "$1" "$2"
  fi
}

#
# Add a user to the system.
#
add_user () {
  local user=$1
  local pass=$2
  local args=$3

  id $user  > /dev/null 2>&1

  if [ $? -eq 0 ]; then
    log "User $user already exists. Skipped creation."
  else
    log "Adding user $user..."
    [ "$pass" == "" ] && pass=generate_password

    if [[ "$args" != *nohome* ]]; then
      /usr/sbin/useradd --password `openssl passwd -crypt $pass` --create-home $user --shell /bin/bash
    else
      /usr/sbin/useradd --password `openssl passwd -crypt $pass` $user --shell /bin/bash
    fi
  fi
}

#
# Generate a random password.
#
generate_password() {
  local l=$1
  [ "$l" == "" ] && l=8
  tr -dc A-Za-z0-9_ < /dev/urandom | head -c ${l} | xargs
}

#
# Run a command as another user
#
run_as () {
  local user=$1
  local cmd=$2
  log "Running command as '$user'..."
  log "$cmd"
  # sudo -u $user -H -s /bin/bash -c "$cmd"
  # sudo -u $user -s /bin/bash -i "$cmd"
  su -c "$cmd" -s /bin/bash $user
}

#
# Add line to a file if line is not already present
#
add_line () {
  local line="$1"
  local file="$2"
  grep "$line" "$file" > /dev/null 2>&1

  if [ $? -ne 0 ]; then
    log "Adding '$line' to '$file'..."
    echo "$line" >> "$file"
  else
    log "'$line' already in '$file'. Skipping."
  fi
}

#
# Write a warning if user is not root.
#
warn_if_not_root () {
  uid=`id -u` && [ "$uid" = "0" ] ||
  { echo "WARNING: You are NOT running this script as 'root'. You might want to consider that..."; }
}

#
# Stops the execution of the script if user is not root.
#
fail_if_not_root () {
  uid=`id -u` && [ "$uid" = "0" ] ||
  { echo "You must run this as 'root'. Exiting."; exit 1; }
}

#
# Checks if a certain element has already been installed.
#
is_installed () {
  local args=$*
  local name=${args//[ \/:@]/-}

  if [[ -f ~/.shoestrap/installed/$name ]]; then
    log "'$name' is already installed."
    return 0
  else
    log "'$name' is not installed."
    return 1
  fi
}

#
# Sets an element as installed.
#
set_installed () {
  local args=$*
  local name=${args//[ \/:@]/-}

  mkdir -p ~/.shoestrap/installed
  touch ~/.shoestrap/installed/$name
}

#
# Promts a user for a Yn confirmation
#

prompt_yn () {
    read -p "$1 [y/n] " -n 1 -r
    echo    # move to a new line
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        return 0
    fi

    return 1
}