prereqs_check(){ info "Running prerequisite checks...";local ok=0;if! command_exists docker;then err "Docker is not installed.";ok=1;fi;if!docker compose version >/dev/null 2>&1;then err "Docker Compose V2 plugin is not installed.";ok=1;fi;if! command_exists curl;then err "curl is not installed.";ok=1;fi;if[${ok}-ne 0 ];then err "Prerequisite checks failed.";exit 1;fi; success "All prerequisites are met.";}
prereqs_check(){ info "Running prerequisite checks...";local ok=0;if! command_exists docker;then err "Docker is not installed.";ok=1;fi;if!command_exists yq;then err "Dependency 'yq' is missing. Please install it.";ok=1;fi;if! command_exists curl;then err "curl is not installed.";ok=1;fi;if[${ok}-ne 0 ];then err "Prerequisite checks failed.";exit 1;fi; success "All prerequisites are met.";}
SELINUX_LABEL=""; setup_selinux_flag(){if command_exists sestatus && sestatus 2>/dev/null | grep-qi"SELinux status:.*enabled";then SELINUX_LABEL=",z"; info "SELinux is enabled. Appending ',z' to volume mounts.";fi;}
ask_confirm(){local prompt="$1";if["${yes_all}"=true];then info "[auto-yes] ${prompt} -> yes";return 0;fi;while true;do printf"%s [y/N]: ""${prompt}";read-r yn;case"${yn}"in[Yy]*)return 0 ;;[Nn]*|"")return 1 ;;*)echo"Please answer y or n.";;esac;done;}
# -------------------------
# Core Logic
# Core Action Functions
# -------------------------
download_map(){
action_prepare_map(){
# ... (same as v4.2)
info "Preparing map from source: ${map_source}"
local map_instance_dir="${work_dir}/${map_name}/dataset"
echo-e"${compose_content}"# Use -e to interpret newlines correctly
}
# -------------------------
# Command Implementations
# Main Execution Flow
# -------------------------
run_install(){
info "Starting OSRM installation for map instance: '${map_name}'"
if[-f"${COMPOSE_FILE}"]&&! ask_confirm "Instance '${map_name}' may exist. Re-running will update config and recreate/rebuild containers. Continue?";then info "Installation aborted.";exit 0;fi
err "Preprocessing for '${profile}' FAILED.";if! ask_confirm "Continue?";then err "Aborting.";exit 1;fi
for profile in"${PROFILE_ARR[@]}";do if[!-f"${map_instance_dir}/${profile}-data/${map_name}-${profile}.osrm.properties"];then plan_profiles_to_preprocess+=("${profile}");fi;done
if[["${plan_map_action}"!="none"]];then if[["${plan_map_action}"=="create"]];then info "[PLAN] Peta sumber belum ada; akan disiapkan dari '${map_source}'.";else info "[PLAN] Peta akan diubah dari '${existing_map_path:-<none>}' menjadi '${map_source}'.";fi; warn "[DEPENDENCY] Aksi ini krusial untuk preprocessing.";if ask_confirm "Lanjutkan dengan persiapan peta?";then decisions[map]=true;else decisions[map]=false;fi;else decisions[map]=true;fi
if[["${decisions[map]}"=="false"]];then info "Persiapan peta dilewati, preprocessing tidak dapat dilanjutkan.";map_changed=false;fi
for profile in"${plan_profiles_to_create[@]}";do info "[PLAN] File profil '${profile}.lua' akan dibuat."; warn "[DEPENDENCY] Jika dilewati, preprocessing untuk '${profile}' tidak dapat dilanjutkan.";if ask_confirm "Lanjutkan?";then decisions["profile_${profile}"]=true;else decisions["profile_${profile}"]=false;fi;done
for profile in"${plan_profiles_to_preprocess[@]}";do local profile_lua_exists=true;if[[" ${plan_profiles_to_create[*]} "=~ " ${profile} "]]&&[["${decisions[profile_${profile}]:-false}"=="false"]];then profile_lua_exists=false;fi;if[["${profile_lua_exists}"=="false"]];then warn "[SKIP] Preprocessing untuk '${profile}' dilewati karena pembuatan file .lua tidak disetujui."; decisions["preprocess_${profile}"]=false;continue;fi; info "[PLAN] Preprocessing akan dijalankan untuk profil '${profile}'."; warn "[DEPENDENCY] Jika dilewati, container backend untuk '${profile}' tidak akan dapat dimulai.";if ask_confirm "Lanjutkan? (Memakan waktu)";then decisions["preprocess_${profile}"]=true;else decisions["preprocess_${profile}"]=false;fi;done
if[["${plan_compose_update}"=="true"]];then info "[PLAN] File 'docker-compose.${map_name}.yml' akan diperbarui."; warn "[DEPENDENCY] Aksi ini krusial untuk semua perubahan container.";if ask_confirm "Lanjutkan?";then decisions[compose]=true;else decisions[compose]=false;fi;else decisions[compose]=true;fi
for profile in"${plan_profiles_to_preprocess[@]}";do if[["${decisions[preprocess_${profile}]:-false}"=="true"]];then action_run_preprocessing "${profile}"|| warn "Preprocessing untuk ${profile} gagal.";else info "Preprocessing untuk '${profile}' dilewati.";fi;done
# --- FIX IS HERE (v4.3) ---
# This block now correctly executes the container actions based on decisions.
run_remove(){ info "Starting removal of OSRM instance: '${map_name}'";if[!-f"${COMPOSE_FILE}"];then warn "Instance '${map_name}' not found.";fi;if ask_confirm "This will STOP and REMOVE all containers for instance '${map_name}'. Are you sure?";then if[-f"${COMPOSE_FILE}"];then docker compose -f"${COMPOSE_FILE}" down -v|| warn "Could not stop containers.";fi;if[["${do_purge}"=="true"]];then local instance_dir="${work_dir}/${map_name}";if ask_confirm "PURGE ENABLED. This will DELETE '${instance_dir}'. IRREVERSIBLE. Proceed?";then rm -rf"${instance_dir}"; rm -f"${COMPOSE_FILE}"; success "Instance data for '${map_name}' has been purged.";fi;fi;else info "Removal aborted by user.";fi;}