#!/usr/bin/bash
#shellcheck disable=SC1090

. "$(sfpath)" || exit 3

shellfu import pretty
shellfu import sfdoc


usage() {
    mkusage "$@" \
        "[options] MODULE"                                              \
        "[options] --ls [MODULE]"                                       \
        "[options] --ls{var|fun} MODULE"                                \
        "[options] --which MODULE"                                      \
        "[options] --lsmod"                                             \
        "[options] -s|--src MODULE"                                     \
        "[options] --export FMT MODULE"                                 \
        -c                                                              \
            "-l, --ls [MODULE]  list contents of MODULE if specified,"  \
            "                   otherwise of all modules"               \
            "-L, --lsmod        show list of modules"                   \
            "--lsfun MODULE     show list of functions in MODULE"       \
            "--lsvar MODULE     show list of variables in MODULE"       \
            "--which MODULE     show path to MODULE file"               \
            "-s, --src MODULE   show MODULE source code"                \
            "-e, --export FMT MODULE   export MODULE documentation in"  \
            "                   format FMT: 'markdown', 'manpage' and"  \
            "                   'pod' are supported"                    \
            "-E FMT FILE        export documentation from FILE in FMT"  \
            "                   format (see -e), and re-embed it into"  \
            "                   the same file."                         \
        -o                                                              \
            "-O, --object       Treat MODULE as function or variable"   \
            "                   name and find respective module first." \
            "-d, --debug        Turn on debugging"                      \
            "-h, --hide REGEX   Use REGEX to determine what is hidden." \
            "                   (See also -a and 'sfdoc sfdoc'.)"       \
            "-a, --all          Don't ignore hidden (starting with"     \
            "                   underscore) modules or objects"         \
            "--encoding ENC     Override encoding of the source text"   \
            "                   (default: utf8)"                        \
            "--name NAME        Override module name (useful when"      \
            "                   exporting from a file and the filename" \
            "                   is not helpful)"                        \
            "-I PTH, --include PTH  Include path PTH when searching"    \
            "                   for modules; can be specified multiple" \
            "                   times."                                 \
            "-o PTH, --only-from PTH  Search only under path PTH."      \
        --                                                              \
        "Without command specified, will try to display documentation"  \
        "in man(1) pager."
}

select_mfile() {
    #
    # Find and/or verify file that holds module $1
    #
    local module=$1
    local mfile
    case $module in
        */*)    mfile="$module" ;;
        *)      mfile=$(shellfu _select_mfile "$module") ;;
    esac
    debug -v mfile
    test -n "$mfile" || { warn "no such module found: $module"; return 3; }
    test -f "$mfile" || { warn "no such file found: $mfile"; return 3; }
    echo "$mfile"
}

find_lesspipe() {
    #
    # Output correct path to src-hilite-lesspipe.sh
    #
    find \
      /usr/bin/src-hilite-lesspipe.sh \
      /usr/share/source-highlight/src-hilite-lesspipe.sh \
     2>/dev/null
}

find_by() {
    #
    # Find module by object type $1 and name $2
    #
    local name=$1
    sfdoc -a -l \
      | grep ":$name$" \
      | cut -d: -f1 \
      | grep .
}

main() {
    local action            # what to do
    local format            # export format
    local module            # module name or path/to/module.sh
    local mspec             # module/function name or path/to/module.sh
    local m                 # module helper var
    local RealModuleName    # name to override eg. if accessing via filename
    local encoding          # encoding
    local mpath             # path to module file
    local jump              # jump to first occurence of this
    action=man
    format=markdown
    encoding=utf8
    spectype=mod
    #shellcheck disable=SC2034
    while true; do case "$1" in
        -O|--object)    spectype=obj;               shift ;;
        -d|--debug)     PRETTY_DEBUG=true;          shift ;;
        -a|--all)       SFDOC_SHOW_HIDDEN=true;     shift ;;
        -h|--hide)      SFDOC_SHOW_HIDDEN=false; SFDOC_HIDE_REGEX="$2"; shift 2 || usage -w "no REGEX?" ;;
        -I|--include)   SHELLFU_PATH="$2:$SHELLFU_PATH"; shift 2 || usage -w "no PTH?" ;;
        -s|--src)       action=src;                 shift; break ;;
        -l|--ls)        action=lsx;                 shift; break ;;
        -L|--lsmod)     action=lsm;                 shift; break ;;
        --which)        action=wch;                 shift; break ;;
        -o|--only-from) SHELLFU_PATH="$2"; SHELLFU_INCLUDE=""; shift 2 || usage -w "no PTH?" ;;
        --lsvar)        action=lsv;                 shift; break ;;
        --lsfun)        action=lsf;                 shift; break ;;
        -e|--export)    action=exp; format="$2";    shift 2 || usage -w "no FMT?"; break ;;
        --encoding)     encoding="$2";              shift 2 || usage -w "no ENC?" ;;
        --name)         RealModuleName="$2";        shift 2 || usage -w "no NAME?" ;;
        -*)                                         usage -w "unknown argument: $1" ;;
        *)                                          break ;;
    esac done
    mspec="$1"; shift
    debug -v SHELLFU_INCLUDE SHELLFU_PATH SFDOC_SHOW_HIDDEN
    debug -v action format module RealModuleName
    case $action:$mspec in
        lsx:*|lsm:*)    true ;;
        *:)             usage -w "no MODULE?" ;;
    esac
    case $spectype in
        obj) module=$(find_by "$mspec") \
              || die "no module found with: $mspec"
             jump="$mspec"
             ;;
        *)   module=$mspec ;;
    esac
    case $action in
        lsm)    : ;;
        *)      mpath=$(select_mfile "$module") || die ;;
    esac
    case $action in
        exp)    # --export
            grep -qwe "$format" <<<manpage,markdown,pod \
             || die "unknown format: $format"
            sfdoc__export "$format" "${RealModuleName:-$module}" "$mpath" "$encoding"
            ;;
        lsm)    # --lsmod
            sfdoc__ls_m | LC_ALL=C sort
            ;;
        lsv)    # --lsvar MODULE
            sfdoc__ls v "$mpath" | LC_ALL=C sort
            ;;
        lsf)    # --lsfun MODULE
            sfdoc__ls f "$mpath" | LC_ALL=C sort
            ;;
        lsx)    # --ls [MODULE]
            case $module in
                "") shellfu _list_mfiles ;;
                *)  echo "$mpath" ;;
            esac \
              | while read -r m;
                do
                    sfdoc__ls v "$m"
                    sfdoc__ls f "$m"
                done \
              | LC_ALL=C sort
            ;;
        man)
            command -v pod2man &>/dev/null \
             || die "pod2man is missing; cannot use man page mode"
            manfile=$(mktemp -t "sfdoc.manfile.XXXXXXXX")
            sfdoc__export manpage "${RealModuleName:-$module}" "$mpath" "$encoding" >"$manfile"
            manless="$LESS"
            test -n "$jump" && manless+=" +/$jump"
            LESS="$manless" man "$manfile"
            rm "$manfile"
            ;;
        src)
            local lesspipe
            lesspipe=$(find_lesspipe)
            if test -n "$lesspipe";
            then
                LESS="$LESS -R " \
                LESSOPEN="| $lesspipe %s" \
                    less "$mpath"
            else
                less "$mpath"
            fi
            ;;
        wch)
            echo "$mpath"
            ;;
    esac
}

main "$@"
