#! /usr/bin/env bash

#' port4me: Get the Same, Personal, Free TCP Port over and over
#' 
#' Usage:
#'  port4me [options]
#' 
#' Options:  
#'  --help             Display the full help page with examples
#'  --version          Output version of this software
#'  --debug            Output detailed debug information
#'
#'  --user=<string>    User name (default: $USER)
#'  --tool=<string>    Name of software tool
#'
#'  --include=<ports>  Set of ports to be included
#'                     (default: 1024-65535)
#'  --exclude=<ports>  Set of ports to be excluded
#'  --prepend=<ports>  Set of ports to be considered first
#'
#'  --skip=<n>         Number of ports to skip
#'  --list=<n>         List the first 'n', available or not, ports
#'
#'  --test=<port>      Return 0 if port is available, otherwise 1
#'
#' Examples:
#' port4me --version
#'
#' port4me
#' port4me --tool=rstudio
#' port4me --include=11000-11999 --exclude=11500,11509 --tool=rstudio
#' port4me rstudio    ## short for --tool=rstudio
#'
#' rserver --www-port "$(port4me --tool=rstudio)"
#' jupyter notebook --port "$(port4me --tool=jupyter-notebook)"
#'
#' port4me --test=8087 && echo "free" || echo "taken"
#'
#' Warning:
#' Then smaller the set of ports that --include=<ports> and
#' --exclude=<ports> define, the longer the run time will be.
#'
#' Requirements:
#' * Bash (>= 4)
#'
#' Version: {{ version }}
#' Copyright: Henrik Bengtsson (2022-2024)
#' License: MIT

this="${BASH_SOURCE%/}"
[[ -L "${this}" ]] && this=$(readlink "${this}")

## Import bash utility functions
incl="$(dirname "${this}")/incl"

# shellcheck source=incl/port4me.bash
source "${incl}/port4me.bash"


# -------------------------------------------------------------------------
# CLI utility functions
# -------------------------------------------------------------------------
function _p4me_version {
    local version
    version=$(grep -E "^#'[ ]*Version:[ ]*" "${incl}/port4me.bash" | sed "s/#'[ ]*Version:[ ]*//g")
    echo "${version}"
}

function _p4me_help {
    local what res

    what=$1
    res=$(grep "^#'" "$0" | cut -b 4- | sed -E "s/[{][{] version [}][}]/$(_p4me_version)/")

    if [[ $what == "full" ]]; then
        res=$(echo "$res" | sed '/^---/d')
    else
        res=$(echo "$res" | sed '/^---/Q')
    fi

    printf "%s\\n" "${res[@]}"
}


# -------------------------------------------------------------------------
# Parse command-line options
# -------------------------------------------------------------------------
action=port
PORT4ME_DEBUG=${PORT4ME_DEBUG:-false}
tool_specified=false

_p4me_parse_cli_args() {
    local key value
    
    while (($# > 0)); do
        ## Options (--flags):
        if [[ "$1" == "--help" ]]; then
            action=help
        elif [[ "$1" == "--version" ]]; then
            action=version
        elif [[ "$1" == "--debug" ]]; then
            PORT4ME_DEBUG=true
        ## Options (--key=value):
        elif [[ "$1" =~ ^--.*=.*$ ]]; then
            key=${1//--}
            key=${key//=*}
            value=${1//--[[:alpha:]]*=}
            if [[ -z ${value} ]]; then
                _p4m_error "Option '--${key}' must not be empty"
            fi
            if [[ "${key}" == "user" ]]; then
                PORT4ME_USER=${value}
            elif [[ "${key}" == "tool" ]]; then
                PORT4ME_TOOL=${value} 
                tool_specified=true
            elif [[ "${key}" == "exclude" ]]; then
                PORT4ME_EXCLUDE=${value}
            elif [[ "${key}" == "include" ]]; then
                PORT4ME_INCLUDE=${value}
            elif [[ "${key}" == "prepend" ]]; then
                PORT4ME_PREPEND=${value}
            elif [[ "${key}" == "skip" ]]; then
                PORT4ME_SKIP=${value}
            elif [[ "${key}" == "list" ]]; then
                PORT4ME_LIST=${value}
            elif [[ "${key}" == "test" ]]; then
                PORT4ME_TEST=${value}
            else
                _p4m_error "Unknown option: $1"
            fi
        elif ! $tool_specified; then
            PORT4ME_TOOL=${1}
            tool_specified=true
        else
            _p4m_error "The \"--tool\" option has already been specified: $1"
        fi
        shift
    done
}


# -------------------------------------------------------------------------
# Main
# -------------------------------------------------------------------------
_p4me_parse_cli_args "$@"

if [[ $action == "help" ]]; then
    _p4me_help ""
elif [[ $action == "version" ]]; then
    _p4me_version
else
    port4me
fi

res=$?

if ${PORT4ME_DEBUG}; then
    echo "port4me exit code: $res"
fi

exit $res
