#!/usr/bin/env zsh

set -eu

# The default ZSH to use; it can just be the first few characters.
# This should be the oldest version we support.
default_version='4.'

setopt extended_glob glob_subst numeric_glob_sort
setopt warn_create_global warn_nested_var 2> /dev/null
cd "${${(%):-%x}:A:h}"

# TODO: Crazy Logic to munge TERM to something supported in Ubuntu 14.04
term=screen-256color

# Note: If versions and frameworks looks complicated, it isn't that bad...
# ...see Modifiers in zshexpn(1) for details.

# List of ZSH versions
typeset -aU versions
versions=( docker/base-*/Dockerfile(N.on:h:t:s/base-//) )
typeset -r versions

# List of frameworks
typeset -aU frameworks
frameworks=( docker/*/Dockerfile(N.on:h:t) )
for i in {$#frameworks..1}; do
  # Remove all base entries
  [[ "${frameworks[$i]}" == base-* ]] && frameworks[$i]=()
done
typeset -r frameworks

# Known Issues
typeset -A known_issues
known_issues["4.3.11-antigen"]="Antigen commands that need git won't work; it needs a newer version of git."
known_issues["4.3.11-zim"]="BROKEN: Zim wants ZSH 5.2 or newer."
known_issues["5.0.3-zim"]="DEPRECATED: Zim wants ZSH 5.2 or newer."
known_issues["5.1.1-zim"]="DEPRECATED: Zim wants ZSH 5.2 or newer."
known_issues["4.3.11-zulu"]="Zulu doesn't work; it needs a newer version of git."
typeset -r known_issues

err()
{
  print -P "%F{red}Error:%f $*"
  exit 2
}

resolve_framework() {
  local f=$1 found
  found=${frameworks[(In:-1:)$f*]}
  if (( found <= $#frameworks )); then
    echo "${frameworks[$found]}"
  fi
}

resolve_version() {
  local v=$1 found
  found=${versions[(In:-1:)$v*]}
  if (( found <= $#versions )); then
    echo "${versions[$found]}"
  fi
}

check_for_known_issues() {
  local version="$1"
  local framework="$2"
  local name="${version}-${framework}"

  if (( ${+known_issues["$name"]} )); then
    echo
    print -P "%F{red}Known Issue: %F{yellow}${known_issues["$name"]}%f"
    echo
  fi
}

cmd() {
  if (( dry_run )); then
    echo "${(@q)*}" 1>&2
  else
    "${(@)*}"
  fi
}

build_and_run() {
  local version="$1"
  local framework="$2"
  local name="${version}-${framework}"

  check_for_known_issues "$version" "$framework"

  print -P "%F{green}Preparing containers...%f"

  echo -n "p9k:base-${version}: "
  cmd docker build \
    --quiet \
    --tag "p9k:base-${version}" \
    --file "docker/base-${version}/Dockerfile" \
    .

  echo -n "p9k:${version}-${framework}: "
  cmd docker build \
    --quiet \
    --build-arg="base=base-${version}" \
    --tag "p9k:${version}-${framework}" \
    --file "docker/${framework}/Dockerfile" \
    .

  print -P "%F{green}Starting ${name} container...%f"
  cmd docker run \
    --rm \
    --interactive \
    --tty \
    --hostname="${name//./_}" \
    --env="TERM=${term}" \
    "p9k:${version}-${framework}"
}

show_help() {
  local f v
  echo "Usage: ${(%):-%x} <framework>|--list"
  echo
  echo "Loads up a docker image with powershell9k configured in <framework>"
  echo
  echo "  -f --frameworks  Lists all available frameworks, newline separated."
  echo "  -v --versions    Lists all available ZSH versions, newline separated."
  echo "  -z --zsh VER     Uses ZSH with version VER."
  echo "  -n --dry-run     Just prints the docker commands that would be run."
  echo "  --help        You're soaking in it."
  echo
  echo "ZSH versions:"
  for v in "${(@)versions}"; do
    echo "  $v"
  done
  echo
  echo "Framework containers:"
  for f in "${(@)frameworks}"; do
    echo "  $f"
  done
}

# No arguments
if (( $# == 0 )); then
  show_help
  exit
fi

# Parse flags and such.
asked_for_version=$default_version
asked_for_framework=
dry_run=0
while (( $# > 0 )); do
  case "$1" in
    -f | --frameworks )
      print -l "${(@)frameworks}"
      exit
      ;;
    -v | --versions )
      print -l "${(@)versions}"
      exit
      ;;
    -z | --zsh )
      shift
      asked_for_version=$1
      ;;
    -n | --dry-run ) dry_run=1 ;;
    -h | --help )
      show_help
      exit
      ;;;
    -* )
      err "Unknown option ${1}"
      show_help
      exit 1
      ;;
    * )
      if [[ -z "$asked_for_framework" ]]; then
        asked_for_framework=$1
      else
        err "You can only specify one framework at a time; you already specified '${asked_for_framework}'"
      fi
      ;;
  esac
  shift
done

typeset -r asked_for_version asked_for_framework

typeset -r use_version="$(resolve_version "${asked_for_version}")"
if [[ -z "$use_version" ]]; then
  err "No such ZSH version '${asked_for_version}'"
fi

typeset -r use_framework="$(resolve_framework "${asked_for_framework}")"
if [[ -z "$use_framework" ]]; then
  err "No such framework '${asked_for_framework}'"
fi

build_and_run "$use_version" "$use_framework"

# EOF