#!/usr/bin/env bash
#
#
# Linux equivalent of remove_overlay.ps1, plus a Web Adaptor cleanup
# step. Removes the 'arcgis#platform' overlay and cycles ArcGIS Server:
#
#   1. Stop the ArcGIS Server service.
#   2. Delete arcgis#platform.xml from
#      <InstallDir>/framework/runtime/tomcat/conf/Catalina/localhost (if present).
#   3. Delete the 'arcgis#platform' web app from
#      <InstallDir>/framework/webapps (if present).
#   4. Remove the <url-pattern>/platform/*</url-pattern> entry from the
#      agswebadaptor <servlet-mapping> in the Web Adaptor's
#      webapps/server/WEB-INF/web.xml - ONLY for ArcGIS Server 11.1, 11.3, 11.5
#      and 12.0. This step is skipped for 12.1.
#   5. Start the ArcGIS Server service.
#
# Install dir and version are read from the ESRI properties file. Missing files
# are skipped (not an error), and the service is always started again at the end.
#
# Accepts only -u (the ArcGIS Server account). Uses sudo for privileged reads,
# deletes, and the service control scripts.

# --------------------------- helper functions ------------------------------

# Exit with a message if the previous command's exit code ($1) is non-zero.
function signal_if_failed() {
  if [ "$1" -ne 0 ]; then
    echo "$2"
    exit "$1"
  fi
}

# Print a message and exit with a failure code.
function throw_error() {
  echo "$1"
  exit 1
}

# Stop or start ArcGIS Server. $1 is 'stop' or 'start'. Best-effort: returns
# non-zero (with a warning) rather than exiting, so cleanup/restart can proceed.
function arcgis_server_action() {
  local action="$1"
  local script="$agsserverinstalldir/${action}server.sh"
  if sudo test -f "$script"; then
    echo "Running ${action}server.sh ..."
    sudo -u "$username" "$script"
    return $?
  elif systemctl list-unit-files 2>/dev/null | grep -q '^arcgisserver'; then
    echo "Using systemd to $action arcgisserver ..."
    sudo systemctl "$action" arcgisserver
    return $?
  fi
  echo "WARNING: no ${action}server.sh or systemd unit found; cannot $action ArcGIS Server."
  return 1
}

# Locate the web.xml of the ArcGIS Web Adaptor's 'server' web app. This lives in
# a SEPARATE Tomcat (the one the Web Adaptor is deployed to, typically owned by a
# 'tomcat' account) - NOT the Tomcat bundled with ArcGIS Server. Its location is
# site-specific, so we discover it from running Tomcat processes, then the
# 'tomcat' account's home, then a bounded filesystem search - accepting a
# candidate only when webapps/server/WEB-INF/web.xml both exists AND contains the
# 'agswebadaptor' servlet (which uniquely identifies the Web Adaptor app).
function find_webadaptor_webxml() {
  local rel="webapps/server/WEB-INF/web.xml"
  local bundled="$agsserverinstalldir/framework/runtime/tomcat"
  local -a candidates=()
  local d

  # Catalina base/home dirs from any running Tomcat (Catalina) java processes.
  while IFS= read -r d; do
    [ -n "$d" ] && candidates+=("$d")
  done < <(ps -ww -eo args 2>/dev/null \
            | tr ' ' '\n' \
            | grep -E '^-Dcatalina\.(base|home)=' \
            | sed -E 's/^-Dcatalina\.(base|home)=//' \
            | sort -u)

  # Home directory of a dedicated 'tomcat' service account, if one exists.
  local tchome
  tchome=$(getent passwd tomcat 2>/dev/null | cut -d: -f6)
  [ -n "$tchome" ] && candidates+=("$tchome")

  # Return the first candidate (other than the bundled Tomcat) that holds a
  # 'server' web app whose web.xml references the agswebadaptor servlet.
  for d in "${candidates[@]}"; do
    case "$d" in "$bundled"|"$bundled"/*) continue ;; esac
    if sudo test -f "$d/$rel" && sudo grep -q 'agswebadaptor' "$d/$rel" 2>/dev/null; then
      echo "$d/$rel"
      return 0
    fi
  done

  # Last resort: a bounded filesystem search for the marker file.
  local hit
  while IFS= read -r hit; do
    [ -z "$hit" ] && continue
    case "$hit" in "$bundled"/*) continue ;; esac
    if sudo grep -q 'agswebadaptor' "$hit" 2>/dev/null; then
      echo "$hit"
      return 0
    fi
  done < <(sudo find /opt /data /usr/share /usr/local /var/lib -maxdepth 7 \
             -path "*/webapps/server/WEB-INF/web.xml" 2>/dev/null)

  return 1
}

# Best-effort removal of the /platform/* mapping from the agswebadaptor block.
# Logs and returns on any problem; never aborts the script.
function remove_platform_mapping() {
  local webxml orig_owner orig_group orig_mode backup tmpxml

  webxml="$(find_webadaptor_webxml)"
  if [ -z "$webxml" ] || ! sudo test -f "$webxml"; then
    echo "WARNING: Web Adaptor web.xml (webapps/server/WEB-INF/web.xml) not found or Tomcat not configured; skipping /platform/* removal."
    return 0
  fi
  echo "Using Web Adaptor web.xml at $webxml"

  # Is /platform/* present inside the agswebadaptor block?
  if ! sudo awk '
    /<servlet-mapping>/ { inblock=1; hasadaptor=0 }
    inblock && /<servlet-name>[[:space:]]*agswebadaptor[[:space:]]*<\/servlet-name>/ { hasadaptor=1 }
    inblock && hasadaptor && /<url-pattern>\/platform\/\*<\/url-pattern>/ { found=1 }
    /<\/servlet-mapping>/ { inblock=0 }
    END { exit (found ? 0 : 1) }
  ' "$webxml"; then
    echo "web.xml has no /platform/* mapping in the agswebadaptor block; nothing to remove."
    return 0
  fi

  echo "Removing /platform/* mapping from the agswebadaptor servlet-mapping in web.xml..."

  # Record original ownership/mode so they can be restored after the sudo edit.
  orig_owner=$(sudo stat -c '%U' "$webxml")
  orig_group=$(sudo stat -c '%G' "$webxml")
  orig_mode=$(sudo stat -c '%a' "$webxml")

  # Timestamped backup beside the original for rollback.
  backup="$webxml.bak.$(date +%Y%m%d%H%M%S)"
  if ! sudo cp -p "$webxml" "$backup"; then
    echo "WARNING: failed to back up web.xml to $backup; skipping /platform/* removal."
    return 0
  fi

  # Drop the /platform/* url-pattern line, but only inside the agswebadaptor block.
  tmpxml="$(mktemp)"
  if ! sudo awk '
    /<servlet-mapping>/ { inblock=1; hasadaptor=0 }
    inblock && /<servlet-name>[[:space:]]*agswebadaptor[[:space:]]*<\/servlet-name>/ { hasadaptor=1 }
    {
      if (inblock && hasadaptor && $0 ~ /<url-pattern>\/platform\/\*<\/url-pattern>/) {
        # skip this line (remove it)
      } else {
        print
      }
    }
    /<\/servlet-mapping>/ { inblock=0 }
  ' "$webxml" > "$tmpxml"; then
    echo "WARNING: failed to generate updated web.xml; leaving original unchanged."
    rm -f "$tmpxml"
    return 0
  fi

  # Confirm the mapping is gone from the agswebadaptor block before overwriting.
  if awk '
    /<servlet-mapping>/ { inblock=1; hasadaptor=0 }
    inblock && /<servlet-name>[[:space:]]*agswebadaptor[[:space:]]*<\/servlet-name>/ { hasadaptor=1 }
    inblock && hasadaptor && /<url-pattern>\/platform\/\*<\/url-pattern>/ { found=1 }
    /<\/servlet-mapping>/ { inblock=0 }
    END { exit (found ? 0 : 1) }
  ' "$tmpxml"; then
    echo "WARNING: /platform/* still present after edit; leaving original unchanged."
    rm -f "$tmpxml"
    return 0
  fi

  # Overwrite in place, then restore the original ownership and permissions.
  if ! sudo cp "$tmpxml" "$webxml"; then
    echo "WARNING: failed to write updated web.xml; original left in place (backup at $backup)."
    rm -f "$tmpxml"
    return 0
  fi
  sudo chown "$orig_owner":"$orig_group" "$webxml"
  sudo chmod "$orig_mode" "$webxml"
  rm -f "$tmpxml"

  echo "Updated $webxml (backup at $backup)."
  return 0
}

# ------------------------------ parameters ---------------------------------

username='arcgis'        # ArcGIS Server account that owns the install.

usage() {
  cat <<USAGE
Usage: $0 [-u <username>]
  -u  ArcGIS Server account name (default: arcgis)
USAGE
}

while getopts ":u:h" opt; do
  case "$opt" in
    u) username="$OPTARG" ;;
    h) usage; exit 0 ;;
    *) usage; exit 1 ;;
  esac
done

# ------------- read ArcGIS Server details from ESRI properties -------------

# Resolve the account's home directory from /etc/passwd.
homedir=$(awk -F: -v v="$username" '{if ($1==v) print $6}' /etc/passwd)
if [ -z "$homedir" ]; then
  throw_error "Unable to fetch home directory location for user $username."
fi

# The ESRI properties file is named .ESRI.properties.<hostname>.*; take the most
# recently modified one.
propertiesfilepath=$(sudo ls -tr "$homedir"/.ESRI.properties."$(hostname)".* 2>/dev/null | tail -n 1)
sudo test -f "$propertiesfilepath"
signal_if_failed $? "ESRI properties file does not exist at path $propertiesfilepath"

# Installed ArcGIS Server directory (required - we can't undeploy without it).
line=$(sudo grep -m1 '^Z_ArcGISServer_INSTALL_DIR=' "$propertiesfilepath")
agsserverinstalldir=${line#Z_ArcGISServer_INSTALL_DIR=}
if [ -z "$agsserverinstalldir" ]; then
  throw_error "Unable to retrieve ArcGIS Server installation directory from ESRI properties file."
fi
sudo test -d "$agsserverinstalldir"
signal_if_failed $? "Unable to locate ArcGIS Server installation directory. Expected path is $agsserverinstalldir."

# Installed ArcGIS Server version (best-effort - only used to gate step 4).
line=$(sudo grep -m1 '^Z_REAL_VERSION=' "$propertiesfilepath" 2>/dev/null)
curragsserverversion=${line#Z_REAL_VERSION=}
detectedversion=''
[ -n "$curragsserverversion" ] && detectedversion=$(awk -F. '{print $1"."$2}' <<< "$curragsserverversion")

echo "ArcGIS Server ${detectedversion:-unknown} installed at $agsserverinstalldir"

# Paths to remove.
contextxml="$agsserverinstalldir/framework/runtime/tomcat/conf/Catalina/localhost/arcgis#platform.xml"
webappfolder="$agsserverinstalldir/framework/webapps/arcgis#platform"

# ------------------------------- 1) stop -----------------------------------

echo "Stopping ArcGIS Server..."
arcgis_server_action stop || echo "WARNING: stop reported a problem; continuing with cleanup."

# --------------------------- 2) delete context xml -------------------------

if sudo test -e "$contextxml"; then
  if sudo rm -f "$contextxml"; then
    echo "Deleted $contextxml"
  else
    echo "WARNING: failed to delete $contextxml"
  fi
else
  echo "Not found (skipped): $contextxml"
fi

# ----------------------------- 3) delete webapp ----------------------------

if sudo test -e "$webappfolder"; then
  if sudo rm -rf "$webappfolder"; then
    echo "Deleted $webappfolder"
  else
    echo "WARNING: failed to delete $webappfolder"
  fi
else
  echo "Not found (skipped): $webappfolder"
fi

# ------------------- 4) remove web.xml mapping (conditional) ----------------

# Only for 11.1, 11.3, 11.5 and 12.0. Skipped for 12.1 (and any other version).
case "$detectedversion" in
  11.1|11.3|11.5|12.0)
    remove_platform_mapping
    ;;
  12.1)
    echo "ArcGIS Server 12.1: skipping web.xml /platform/* removal (not applicable for this version)."
    ;;
  '')
    echo "WARNING: ArcGIS Server version could not be determined; skipping web.xml /platform/* removal."
    ;;
  *)
    echo "ArcGIS Server $detectedversion: skipping web.xml /platform/* removal (version not in scope)."
    ;;
esac

# ------------------------------- 5) start ----------------------------------

echo "Starting ArcGIS Server..."
arcgis_server_action start || echo "WARNING: start reported a problem."

echo "Undeploy complete."
