# internal shortcut alias
alias() {
  rlx.commands.alias "$@";
}

# main
rlx.commands.alias() {
  local overwrite=false;
  local aliases="${directories[aliases]}";
  local keys=(server database username);
  local alias_prefix="@";
  local varprefix="rlx_alias_";
  if [ $# -eq 0 ]; then
    alias.commands.ls;
  else
    local alias_namespace="alias.commands";
    local cmd="${1:-}"; shift;
    if ! method.exists? "${alias_namespace}.${cmd}"; then
      alias.commands.set "${cmd}" "$@";
    else
      delegate "${alias_namespace}" "${cmd}" "$@";
    fi
  fi
}

alias.commands.set() {
  local name="${1:-}";
  local server="${2:-}";
  local database="${3:-}";
  local username="${4:-}";
  alias.strip;
  if [ -z "${name}" ]; then
    console error -- "no alias name specified";
  elif [ $# -eq 1 ]; then
      alias.commands.get "${name}";
  else
    if [ -z "${server}" ]; then
      console error -- "no alias server specified";
    elif [[ ! "${name}" =~ ${regexp[name]} ]]; then
      console error -- "invalid alias name %s" "${name}";
    elif [[ ! "${server}" =~ ${regexp[scheme]} ]]; then
      console error -- "invalid server, must be %s or %s" "http" "https";
    else
      alias.save;
    fi
  fi
}

alias.commands.get() {
  local name="${1:-}";
  local file;
  alias.strip;
  if alias find; then
    alias.load "${file}";
    local k v;
    for k in "${keys[@]}"
      do
        variable.get "${varprefix}${k}" "v";
        if [ -n "${v}" ]; then
          console print -- "${k}=%s" "${v}";
        fi
    done
  fi
}

alias.commands.rm() {
  local name="${1:-}";
  local force="${2:-false}";
  if [ -z "${name}" ]; then
    console error -- "no alias name specified";
  else
    local file;
    alias.strip;
    if alias find; then
      accepted() {
        rm "${file}" \
          || {
            console error -- "could not delete alias %s" "${file}";
            return 1;
          }
        console info -- "deleted alias %s" "${name}";
        rlx.prompt;
      }
      if [ "${force}" == true ]; then
        accepted;
      else
        console prompt --program \
          "delete alias %s? (y/n)" "${alias_prefix}${name}";
        prompt confirm \
          --accepted=accepted \
          --rejected=rlx.rejected \
          --id=delete;
      fi
    fi
  fi
}

alias.commands.server() {
  local name="${1:-}";
  local server="${2:-}";
  local overwrite=true;
  if [ -z "${name}" ]; then
    console error -- "no alias name specified";
  elif [ -z "${server}" ]; then
    console error -- "no server specified";
  elif [[ ! "${server}" =~ ${regexp[scheme]} ]]; then
    console error -- "invalid server, must be %s or %s" "http" "https";
  else
    local file;
    alias.strip;
    if alias find; then
      alias.load "${file}";
      local database username;
      variable.get "${varprefix}database" "database";
      variable.get "${varprefix}username" "username";
      alias.save >/dev/null;
      alias.commands.get "${name}";
    fi
  fi
}

alias.commands.db() {
  local name="${1:-}";
  local database="${2:-}";
  local overwrite=true;
  if [ -z "${name}" ]; then
    console error -- "no alias name specified";
  elif [ -z "${database}" ]; then
    console error -- "no database specified";
  else
    local file;
    alias.strip;
    if alias find; then
      alias.load "${file}";
      local server username;
      variable.get "${varprefix}server" "server";
      variable.get "${varprefix}username" "username";
      alias.save >/dev/null;
      alias.commands.get "${name}";
    fi
  fi
}

alias.commands.user() {
  local name="${1:-}";
  local username="${2:-}";
  local overwrite=true;
  if [ -z "${name}" ]; then
    console error -- "no alias name specified";
  elif [ -z "${username}" ]; then
    console error -- "no username specified";
  else
    local file;
    alias.strip;
    if alias find; then
      alias.load "${file}";
      local server database;
      variable.get "${varprefix}server" "server";
      variable.get "${varprefix}database" "database";
      alias.save >/dev/null;
      alias.commands.get "${name}";
    fi
  fi
}

alias.commands.ls() {
  local IFS=$'\n';
  local files=( $( find "${aliases}" -type f ) );
  local file name;
  for file in ${files[@]:-}
    do
      fs.basename "${file}" "name";
      file="${file//%/%%}";
      console print -- "%s ${file}" "${alias_prefix}${name}";
  done
  unset IFS;
}

# print url for an alias
alias.commands.url() {
  local name="${1:-}";
  local includedb="${2:-true}";
  local print="${3:-true}";
  local file;
  alias.strip;
  if alias find; then
    alias.load "${file}";
    local server database;
    variable.get "${varprefix}server" "server";
    variable.get "${varprefix}database" "database";
    local url="${server:-}";
    if [ -n "${database}" ] && [ "${includedb}" == true ]; then
      url+="/${database}";
    fi
    if [ -n "${url}" ]; then
      if $print; then
        echo "${url}";
      else
        alias_url="${url}";
      fi
      return 0;
    fi
  fi
  return 1;
}

alias.commands.find() {
  local name="${1:-$name}";
  alias.strip;
  local IFS=$'\n';
  local files=( $( find "${aliases}" -type f -name "${name}" ) );
  unset IFS;
  if [ "${#files[@]}" -eq 0 ]; then
    console error -- "unknown alias %s" "${name}";
    return 1;
  fi
  file="${files[0]}";
}

## PRIVATE

alias.load() {
  local file="${1:-}";
  if [ -n "${file}" ]; then
    . "${file}" \
      || {
        console error -- "failed to load alias file %s" "${file}";
        return 1;
      }
  fi
  #env | grep rlx_alias;
  return 0;
}

alias.save() {
  local overwrite="${1:-$overwrite}";
  local prefix="[save]";
  if [ ! -d "${aliases}" ]; then
    fs.mkdirs "${aliases}";
  fi
  local file="${aliases}/${name}";
  accepted() {
    printf "" >| "${file}";
    local k v;
    for k in "${keys[@]}"
      do
        variable.get "${k}" "v";
        if [ "${k}" == server ]; then
          # strip trailing slash
          v="${v%/}";
        fi
        echo "export ${varprefix}${k}=${v}" >> "${file}";
    done
    console info -- "alias %s saved" "${name}";
    rlx.prompt;
  }
  if [ -f "${file}" ] && ! $overwrite; then
    # prompt to confirm overwrite
    console prompt --prefix="${prefix}" \
      "overwrite %s? (y/n)" "${file}";
    prompt confirm \
      --accepted=accepted \
      --rejected=rlx.rejected \
      --id=overwrite;
  else
    accepted;
  fi
}

# strip leading @ and set name
alias.strip() {
  local aliasref="${1:-${name}}";
  if [[ "${aliasref}" =~ ${regexp[alias]} ]]; then
    name="${BASH_REMATCH[2]}";
  fi
}

# expand an explicit alias reference to
# a server URL optionally including the database
alias.expand() {
  local reference="${1:-${server:-}}";
  local varname="${2:-server}";
  local includedb="${3:-false}";
  # shortcut out on scheme match
  if [[ "${reference:-}" =~ ${regexp[scheme]} ]]; then
    return 0;
  fi
  if [[ "${reference:-}" =~ ${regexp[alias]} ]]; then
    local name="${BASH_REMATCH[2]}";
    local file;
    local alias_url;
    if alias url "${name}" "${includedb}" false; then
      variable.set "${varname}" "${alias_url}";
      return 0;
    fi
    return 1;
  fi
}
