##########################################################
# Copyright (c) 2001-2025 Alexey Kuryakin daqgroup@mail.ru
##########################################################

##########################################################
# Common library for assoc, ftype, find-app, find-icon.
# References:
# 1) XDG Desktop Menu Specification.
# 2) XDG Base Directory Specification.
# 3) XDG Icon Theme Specification.
# 4) XDG Icon Naming Specification.
# 5) XDG Shared MIME-info Database.
# 6) XDG Desktop Entry Specification.
##########################################################

function skip(){
 return;
};

function fatal(){
 1>&2 echo -ne "\n$2\n\n";
 exit $1;
};

declare mime_list_files="";
declare app_search_dirs="";
declare ico_search_dirs="";
declare mim_search_dirs="";
declare readini="readini";
declare -i opt_path=0;
declare -i opt_exec=0;
declare -i opt_icon=0;
declare -i opt_link=0;
declare -i appdepth=2;
declare -i icodepth=9;
declare -i opt_def=0;
declare -i opt_cmd=0;
declare opt_theme="";
declare opt_size="";

function check_readini(){
 if unix which $readini >/dev/null 2>&1; then return 0; fi;
 readini="readcfg";
 if unix which $readini >/dev/null 2>&1; then return 0; fi;
 fatal 1 "Error: not found (readini|readcfg) utility";
};

function read_inifile_section(){
 local inifile="$1"; local section="$2";
 if [[ -r $inifile ]] && [[ -n $section ]]; then
  unix $readini "$inifile" "$section" | sed 's/\s*=\s*/=/';
 fi;
};

function drop_key_equal(){
 sed 's/.*=//';
};

function list_xdg_data_dirs(){
 local dirs="${XDG_DATA_HOME:-$HOME/.local/share}:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}";
 if [[ -n $1 ]]; then echo "${dirs//:/$1}"; else echo "$dirs"; fi;
};

function list_xdg_config_dirs(){
 local dirs="${XDG_CONFIG_HOME:-$HOME/.config}:${XDG_CONFIG_DIRS:-/etc/xdg}";
 if [[ -n $1 ]]; then echo "${dirs//:/$1}"; else echo "$dirs"; fi;
};

function enum_app_search_dirs(){
 if [[ -n $app_search_dirs ]]; then
  echo "$app_search_dirs";
  return 0;
 fi;
 local sublist="applications applnk";
 local dirlist="$(list_xdg_data_dirs ' ')";
 for sub in $sublist; do
  for dir in $dirlist; do
   local subdir="$dir/$sub";
   if [[ -e $subdir ]]; then
    subdir="$(realpath "$subdir" 2>/dev/null)";
    if [[ -d $subdir ]]; then
     if [[ -z $app_search_dirs ]]; then
      app_search_dirs="$subdir";
     else
      app_search_dirs+=" $subdir";
     fi;
    fi;
   fi;
  done;
 done;
 if [[ -n $app_search_dirs ]]; then
  echo "$app_search_dirs";
  return 0;
 fi;
 return 1;
};

function print_fapp(){
 local fapp="$1";
 if [[ -n $fapp ]]; then
  if [[ $opt_link -eq 1 ]]; then
   fapp="$(realpath "$fapp" 2>/dev/null)";
  fi;
  echo "$fapp";
 fi;
};

function find_app_handler(){
 local app="$1";
 if [[ -n $app ]]; then
  if [[ $appdepth -gt 0 ]]; then
   local fapp="$(find -L $(enum_app_search_dirs) -maxdepth $appdepth -type f -and -readable -and -name "$app" 2>/dev/null | head -n1)";
   if [[ -r $fapp ]]; then
    print_fapp "$fapp";
    return 0;
   fi;
  else
   for dir in $(enum_app_search_dirs); do
    local fapp="$dir/$app";
    if [[ -r $fapp ]]; then
     print_fapp "$fapp";
     return 0;
    fi;
   done;
  fi;
 fi;
 return 1;
};

function xdg_desktop(){
 local dm="";
 if [[ -z $dm ]]; then dm="$XDG_CURRENT_DESKTOP"; fi;
 if [[ -z $dm ]]; then dm="$XDG_SESSION_DESKTOP"; fi;
 if [[ -z $dm ]]; then dm="$(unix wmquery DesktopManager)"; fi; 
 if [[ -n $dm ]]; then echo "${dm,,}"; fi;
};

function enum_mime_list_files(){
 if [[ -n $mime_list_files ]]; then
  echo "$mime_list_files";
  return 0;
 fi;
 local flist=""; local desktop="$(xdg_desktop)";
 local reflist="$desktop-mimeapps.list mimeapps.list";
 local dirlist="$(list_xdg_config_dirs ' ') $(enum_app_search_dirs)";
 for dir in $dirlist; do for ref in $reflist; do flist+=" $dir/$ref"; done; done;
 for f in $flist; do
  if [[ -e $f ]]; then
   local fn="$(realpath $f 2>/dev/null)";
   if [[ -f $fn ]]; then
    if [[ -z $mime_list_files ]]; then
     mime_list_files="$fn";
    else
     mime_list_files+=" $fn";
    fi;
   fi;
  fi;
 done;
 if [[ -n $mime_list_files ]]; then
  echo "$mime_list_files";
  return 0;
 fi;
 return 1;
};

function enum_ico_search_dirs(){
 if [[ -n $ico_search_dirs ]]; then
  echo "$ico_search_dirs";
  return 0;
 fi;
 local dir="$HOME/.icons";
 if [[ -d $dir ]]; then ico_search_dirs="$dir"; fi;
 local sublist="icons";
 local dirlist="$(list_xdg_data_dirs ' ')";
 for sub in $sublist; do
  for dir in $dirlist; do
   local subdir="$dir/$sub";
   if [[ -e $subdir ]]; then
    subdir="$(realpath "$subdir" 2>/dev/null)";
    if [[ -d $subdir ]]; then
     if [[ -z $ico_search_dirs ]]; then
      ico_search_dirs="$subdir";
     else
      ico_search_dirs+=" $subdir";
     fi;
    fi;
   fi;
  done;
 done;
 if [[ -e /usr/share/pixmaps ]]; then
  ico_search_dirs+=" /usr/share/pixmaps";
 fi;
 if [[ -n $ico_search_dirs ]]; then
  echo "$ico_search_dirs";
  return 0;
 fi;
 return 1;
};

function enum_mime_search_dirs(){
 if [[ -n $mim_search_dirs ]]; then
  echo "$mim_search_dirs";
  return 0;
 fi;
 local sublist="mime";
 local dirlist="$(list_xdg_data_dirs ' ')";
 for sub in $sublist; do
  for dir in $dirlist; do
   local subdir="$dir/$sub";
   if [[ -e $subdir ]]; then
    subdir="$(realpath "$subdir" 2>/dev/null)";
    if [[ -d $subdir ]]; then
     if [[ -z $mim_search_dirs ]]; then
      mim_search_dirs="$subdir";
     else
      mim_search_dirs+=" $subdir";
     fi;
    fi;
   fi;
  done;
 done;
 if [[ -n $mim_search_dirs ]]; then
  echo "$mim_search_dirs";
  return 0;
 fi;
 return 1;
};

function gio_def_app(){
 env LANG=en_US.UTF-8 gio mime "$1" 2>/dev/null | grep '^Default application .*:' | sed 's/.*:\s*//';
};

function xdg_def_app(){
 env LANG=en_US.UTF-8 xdg-mime query default "$1" 2>/dev/null | grep -v '^fail$';
};

function sys_def_app(){
 local mime="$1"; local app="";
 if [[ -z $mime ]]; then return 1; fi;
 if [[ -z $app ]]; then app="$(gio_def_app "$mime")"; fi;
 if [[ -z $app ]]; then app="$(xdg_def_app "$mime")"; fi;
 if [[ -n $app ]]; then echo "$app"; return 0; fi;
 return 1;
};

function subst_exec_args(){
 local exec="$1";
 if [[ $# -le 1 ]]; then
  echo "$exec" | sed 's/%[fFuU]//' | xargs;
 else
  shift;
  local exec1="$(echo "$exec" | sed 's/\s%[fFuU]\b.*//' | xargs)";
  local exec2="$(echo "$exec" | sed 's/.*\s%[fFuU]\b//' | xargs)";
  if [[ $exec1 = $exec2 ]]; then
   echo "$exec" "$@";
  else
   echo "$exec1" "$@" "$exec2";
  fi;
 fi;
};

##############
## END OF FILE
##############
