#!/usr/bin/env bash

http_version=0.5.1 # this script version.

set -o monitor   # for job control.
set -o errexit   # exit if error occurs.

# Defaults
HOST=0.0.0.0
PORT=8000
DIR=$PWD

# Check Python 3
if ! hash python3 2>/dev/null; then
    echo -e "$0: Python 3 executable not found." >&2
    exit 1
fi

http_print_help() {
    cat <<-EOF
Run Python 3 builtin HTTP Server.

Usage: http [-v|--version] [-h|--help] [-c|--cgi] [-f|--firefox]
            [<host>[:<port>]] [<port>] [<dir>]

Options:
    -c, --cgi       run as CGI Server.
    -f, --firefox   open URL in Firefox.
    -h, --help      print this help message and exit.
    -v, --version   print version and exit.

Arguments:
    <host>          host to bind. Default: 0.0.0.0
    <port>          port to bind. Default: 8000
    <dir>           directory to serve. Default: current directory.
EOF
    exit 0
}

while (( "$#" )); do
    case "$1" in
        -c|--cgi)
            CGI='--cgi';;
        -f|--firefox)
            FOX=1;;
        -h|--help)
            http_print_help;;
        -v|--version)
            echo "http v$http_version"; exit 0;;
        -*|--*)
            echo -e "$0: Bad option: $1" >&2
            exit 1
            ;;
        *)
            if [ -d "$1" ]
            then
                # If direcory exists set it as root DIR.
                DIR="$1"
            elif [[ "$1" =~ ^[0-9]+$ ]]
            then
                # If value is integer set it as PORT.
                PORT="$1"
            elif [[ "$1" =~ \
                ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]
            then
                # Value like IPv4 address. Not necessary.
                HOST="$1"
            elif [[ "$1" == 'localhost' ]]
            then
                # Nuff said.
                HOST="$1"
            elif [ "$(grep -o : <<<"$1")" ]
            then
                # If value like 'localhost:4000'
                HOST="$(echo "$1" | cut -d ":" -f 1)"
                PORT="$(echo "$1" | cut -d ":" -f 2)"
            else
                echo -e "$0: Bad option: $1$" >&2
                exit 1
            fi
            ;;
    esac
    shift
done

# Check available port and retry 3 times.
retries=1
while [ "$(ss -tanp | grep -o "$PORT")" ]; do
    if [[ "$retries" == 4 ]]
    then
        echo -e "Max number of retries reached! Exiting." >&2
        exit 1
    else
        :
    fi

    # Increase port if is already in use.
    PORT_USED="$PORT"
    let PORT++
    echo -e "Port $PORT_USED is already in use!
        Switching to: $PORT" | sed 's/^ *//g' >&2

    let retries++
done

# Run Python http.server.
echo -e "Serve: $DIR\tPress ^C to stop serving."
python3 -m http.server $CGI --bind $HOST $PORT --directory $DIR &
[[ "$FOX" == 1 ]] && firefox http://$HOST:$PORT/
fg
