#!/bin/bash

# Asserts that the cwd is an app directory.
# By default it checks that there is a 'current' link.
assert_is_app() {
  local check_link=yes
  local version=

  while getopts "Cv:" opt
  do
    case $opt in
      C)
        check_link=no
        ;;
      v)
        version=$OPTARG
        ;;
    esac
  done

  local app_home=${APP_HOME-.}

  if [ ! -d "$app_home/.app" ]
  then
    fatal "This is not an app, missing directory: .app"
  fi

  if [[ $check_link == yes ]]
  then
    if [ ! -e "$app_home/current" ]
    then
      fatal "Missing 'current' link." >&2
    fi
  fi

  if [[ $version != "" ]]
  then
    if [[ ! -d "$app_home/versions/$version" ]]
    then
      fatal "No such version: $version"
    fi
  fi
}

show_help() {
  message=${1-}

  if [[ $message != "" ]]
  then
    echo $message
  fi

  if [ "`declare -f usage_text >/dev/null; echo $?`" = 0 ]
  then
    usage_text
  else
    echo "The command $usage_app does not have any usage info."
  fi
  exit 1
}

usage() {
  message=${1-}

  if [[ $message != "" ]]
  then
    echo $message >&2
  fi

  if [ "`declare -f usage_text >/dev/null; echo $?`" = 0 ]
  then
    usage_text >&2
  fi
  exit 1
}

debug() {
  [[ $echo_debug == no ]] || echo "D: $usage_app: $@" 2>&1
}

info() {
  echo "I: $usage_app: $@" 2>&1
}

fatal() {
  echo "$usage_app: fatal: $@" 2>&1
  exit 1
}

list_apps() {
  local filter_name=$1; shift
  local filter_instnace=$1; shift
  local vars="$@"

  sort $apps/.app/var/list | while read line
  do
    echo $line | (IFS=:; while read name instance version junk
    do
      if [ -n "$filter_name" -a "$filter_name" != "$name" ]
      then
        continue
      fi

      if [ -n "$filter_instance" -a "$filter_instance" != "$instance" ]
      then
        continue
      fi

      local line=""
      IFS=" "; for var in $vars
      do
        case $var in
          name) x=$name;;
          instance) x=$instance;;
          version) x=$version;;
          current_version) x=`find_current_version $name $instance`;;
          *) x="";;
        esac

        if [ -z "$line" ]
        then
          line="$line$x"
        else
          line="$line:$x"
        fi
      done
      echo $line
    done)
  done
}

find_current_version() {
  local name=$1
  local instance=$2

  if [ ! -L $apps/$name/$instance/current ]
  then
    return 0
  fi

  (
    cd $apps/$name/$instance
    ls -l current | sed -n "s,.* current -> versions/\(.*\)/root,\1,p"
  )
}

find_versions() {
  local name="$1"
  local instance="$2"

  if [ ! -d $apps/$name/$instance/versions ]
  then
    return 0
  fi

  (
    cd $apps/$name/$instance/versions
    ls -1d *
  )
}

validate_location() {
  local name=$1; shift

  case "${!name}" in
    s|system)
      eval ${name}=1
      ;;
    u|user)
      eval ${name}=2
      ;;
    a|app)
      eval ${name}=3
      ;;
    *)
      fatal "Invalid location: ${!name}, must be one of 's', 'system', 'u', 'user', 'a' or 'app'."
    ;;
  esac
}

location_to_file() {
  case "${!1}" in
    s|system|1)
      _get_config_file_system $1
      ;;
    u|user|2)
      _get_config_file_user $1
      ;;
    a|app|3)
      _get_config_file_app $1
      ;;
    *)
      fatal "Invalid location: ${!1}, must be one of 's', 'system', 'u', 'user', 'a' or 'app'."
  esac
}

_get_config_file_system() {
  eval $1="${APPSH_DEFAULT_CONFIG-$APPSH_HOME/lib/default-config}"
}

_get_config_file_user() {
  if [[ -z $HOME ]]
  then
    eval $1=""
  else
    eval $1="$HOME/.appconfig"
  fi
}

_get_config_file_app() {
  eval $1=".app/config"
}

grep_path() {
  local regex="$1"; shift
  local path="$1"; shift

  find `echo $path | tr : " "` -type f -executable 2>/dev/null | (egrep "$regex" || exit 0)
#  IFS=:
#  for x in $path
#  do
#    ls $x/* 2>/dev/null | while read f
#    do
#      if [[ $f =~ $regex ]]
#      then
#        echo $f
#      fi
#    done
#  done
}

# TODO: set ulimit
# TODO: set umask
# TODO: change group newgrp/sg
# usage: run_app [-v version] [bin to execute]
run_app() {
  version=
  while getopts "v:" opt
  do
    case $opt in
      v)
        version=$OPTARG
		shift 2
		OPTIND=1
        ;;
    esac
  done

  local bin=$1; shift
  local e=`app-cat-conf -n "env\..*" | cut -f 2- -d .`

  local app_home=`pwd`

  (
    if [[ $version == "" ]]
    then
      assert_is_app
      cd current
    else
      assert_is_app -v "$version"
      cd "versions/$version"
    fi

    path=/bin:/usr/bin

    # This magically get the expansion of $u correct.
    IFS="
"

    set +e
    env -i \
      PATH="$PATH" \
      $e \
      PWD="$PWD" \
      APPSH_HOME="$APPSH_HOME" \
      APP_HOME="$app_home" \
      $bin "$@"
    local ret=$?
    set +x
    set -e

    exit $ret
  )
}

find_resolver() {
  grep_path "/app-resolver-$resolver_name$" "$PATH" | head -n 1
}

#####################################################################
# Common init

# Add the app-* apps to PATH. They're added last to allow the user to
# overload their implementations.
PATH=$PATH:$APPSH_HOME/bin:$APPSH_HOME/libexec

# Make sure that $HOME is present to prevent unbound errors
HOME=${HOME:-}

# Save for later
usage_app=${0##*/}
echo_debug=${echo_debug-no}