#!/bin/sh

################## https://github.com/mkropat/sh-realpath #####################
#
# The MIT License (MIT)
#
# Copyright (c) 2014 Michael Kropat
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

realpath() {
    canonicalize_path "$(resolve_symlinks "$1")"
}

resolve_symlinks() {
    _resolve_symlinks "$1"
}

_resolve_symlinks() (
    _assert_no_path_cycles "$@" || return

    if path=$(readlink -- "$1"); then
        dir_context=$(dirname -- "$1")
        _resolve_symlinks "$(_prepend_dir_context_if_necessary "$dir_context" "$path")" "$@"
    else
        printf '%s\n' "$1"
    fi
)

_prepend_dir_context_if_necessary() {
    if [ "$1" = . ]; then
        printf '%s\n' "$2"
    else
        _prepend_path_if_relative "$1" "$2"
    fi
}

_prepend_path_if_relative() {
    case "$2" in
        /* ) printf '%s\n' "$2" ;;
         * ) printf '%s\n' "$1/$2" ;;
    esac
}

_assert_no_path_cycles() (
    target=$1
    shift

    for path in "$@"; do
        if [ "$path" = "$target" ]; then
            return 1
        fi
    done
)

canonicalize_path() {
    if [ -d "$1" ]; then
        _canonicalize_dir_path "$1"
    else
        _canonicalize_file_path "$1"
    fi
}

_canonicalize_dir_path() {
    { cd "$1" 2>/dev/null && pwd -P; }
}

_canonicalize_file_path() (
    dir=$(dirname -- "$1")
    file=$(basename -- "$1")
    { cd "$dir" 2>/dev/null >/dev/null && printf '%s/%s\n' "$(pwd -P)" "$file"; }
)

##############################################################################

# Based on http://stackoverflow.com/q/370047/641451
remove_path_item() (
  path="$1"

  printf "%s" "$path" | awk -v item="$2" -v RS=: -v ORS=: '$0 != item' | sed 's/:$//'
)

##############################################################################

__has_colors() (
  num_colors=$(tput colors 2>/dev/null)

  if [ -n "$num_colors" ] && [ "$num_colors" -gt 2 ]; then
    return 0
  else
    return 1
  fi
)
__error_msg() {
  if __has_colors; then
    # bold red coloring
    printf '%b\n' "\033[31;1m$*\033[0m" 1>&2
  else
    printf '%b\n' "$@" 1>&2
  fi
}
__warning_msg() {
  if __has_colors; then
    # brown coloring
    printf '%b\n' "\033[33m$*\033[0m" 1>&2
  else
    printf '%b\n' "$@" 1>&2
  fi
}


SCRIPT_PATH="$(realpath "$0")"
SCRIPT_ROOT="$(dirname "$SCRIPT_PATH")"
CRYSTAL_ROOT="$(dirname "$SCRIPT_ROOT")"
CRYSTAL_DIR="$CRYSTAL_ROOT/.build"

export CRYSTAL_PATH="${CRYSTAL_PATH:-./lib:$CRYSTAL_ROOT/src}"
if [ -n "${CRYSTAL_PATH##*"$CRYSTAL_ROOT"/src*}" ]; then
  __warning_msg "CRYSTAL_PATH env variable does not contain $CRYSTAL_ROOT/src"
fi

export CRYSTAL_HAS_WRAPPER=true
: "${CRYSTAL=crystal}"

PARENT_CRYSTAL="$CRYSTAL"

# check if the parent crystal command is a path that refers to this script
if [ -z "${PARENT_CRYSTAL##*/*}" ] && [ "$(realpath "$PARENT_CRYSTAL")" = "$SCRIPT_PATH" ]; then
  # ignore it and use `crystal` as parent compiler command
  PARENT_CRYSTAL="crystal"
fi

# check if the parent crystal command refers to this script
if [ "$(realpath "$(command -v "$PARENT_CRYSTAL" 2> /dev/null)" 2> /dev/null)" = "$SCRIPT_PATH" ]; then
  # remove the path to this script from PATH
  NEW_PATH="$(remove_path_item "$(remove_path_item "$PATH" "$SCRIPT_ROOT")" "bin")"
  # if the PATH did not change it will lead to an infinite recursion => display error
  if [ "$NEW_PATH" = "$PATH" ]; then
    __error_msg 'Could not remove the script bin/crystal from the PATH. Remove it by hand or set the CRYSTAL env variable'
    exit 1
  fi
  PARENT_CRYSTAL=$(PATH=$NEW_PATH command -v "$PARENT_CRYSTAL" 2> /dev/null)
  if [ "$(realpath "$PARENT_CRYSTAL" 2> /dev/null)" = "$SCRIPT_PATH" ]; then
    __error_msg 'Could not remove the script bin/crystal from the PATH. Remove it by hand or set the CRYSTAL env variable'
    exit 1
  fi
fi

command -v "$PARENT_CRYSTAL" > /dev/null 2> /dev/null
PARENT_CRYSTAL_EXISTS=$(test !$?)
if ($PARENT_CRYSTAL_EXISTS); then
  if [ -z "$CRYSTAL_CONFIG_LIBRARY_PATH" ] || [ -z "$CRYSTAL_LIBRARY_PATH" ]; then
    CRYSTAL_INSTALLED_LIBRARY_PATH="$($PARENT_CRYSTAL env CRYSTAL_LIBRARY_PATH 2> /dev/null || echo "")"
    export CRYSTAL_LIBRARY_PATH="${CRYSTAL_LIBRARY_PATH:-$CRYSTAL_INSTALLED_LIBRARY_PATH}"
    export CRYSTAL_CONFIG_LIBRARY_PATH="${CRYSTAL_CONFIG_LIBRARY_PATH:-$CRYSTAL_INSTALLED_LIBRARY_PATH}"
  fi
fi

# CRYSTAL_PATH has all symlinks resolved. In order to avoid issues with duplicate file
# paths when the working directory is a symlink, we cd into the current directory
# with symlinks resolved as well (see https://github.com/crystal-lang/crystal/issues/12969).
cd "$(realpath "$(pwd)")" || exit

case "$(uname -s)" in
  CYGWIN*|MSYS_NT*|MINGW32_NT*|MINGW64_NT*)
    CRYSTAL_BIN="crystal.exe"
    ;;
  *)
    CRYSTAL_BIN="crystal"
    ;;
esac

# CRYSTAL_EXEC_PATH determines the location of the `crystal` program for external
# compiler commands.
CRYSTAL_EXEC_PATH="$SCRIPT_ROOT"
export CRYSTAL_EXEC_PATH

if [ -x "$CRYSTAL_DIR/${CRYSTAL_BIN}" ]; then
  __warning_msg "Using compiled compiler at ${CRYSTAL_DIR#"$PWD/"}/${CRYSTAL_BIN}"
  exec "$CRYSTAL_DIR/${CRYSTAL_BIN}" "$@"
elif (! $PARENT_CRYSTAL_EXISTS); then
  __error_msg 'You need to have a crystal executable in your path! or set CRYSTAL env variable'
  exit 1
else
  exec "$PARENT_CRYSTAL" "$@"
fi
