#!/usr/bin/env bash

set -o pipefail

# tmux requires unrecognized OSC sequences to be wrapped with DCS tmux;
# <sequence> ST, and for all ESCs in <sequence> to be replaced with ESC ESC. It
# only accepts ESC backslash for ST. We use TERM instead of TMUX because TERM
# gets passed through ssh.
function print_osc() {
    if [[ $TERM == screen* || $TERM == tmux* ]]; then
        printf "\033Ptmux;\033\033]"
    else
        printf "\033]"
    fi
}

# More of the tmux workaround described above.
function print_st() {
    if [[ $TERM == screen* || $TERM == tmux* ]]; then
        printf "\a\033\\"
    else
        printf "\a"
    fi
}

function load_version() {
    if [ -z ${IT2CAT_BASE64_VERSION+x} ]; then
        IT2CAT_BASE64_VERSION=$(base64 --version 2>&1)
        export IT2CAT_BASE64_VERSION
    fi
}

function b64_encode() {
    load_version
    if [[ $IT2CAT_BASE64_VERSION =~ GNU ]]; then
        # Disable line wrap
        base64 -w0
    else
        base64
    fi
}

function b64_decode() {
    load_version
    if [[ $IT2CAT_BASE64_VERSION =~ fourmilab ]]; then
        BASE64ARG=-d
    elif [[ $IT2CAT_BASE64_VERSION =~ GNU ]]; then
        BASE64ARG=-di
    else
        BASE64ARG=-D
    fi
    base64 $BASE64ARG
}

# print_file filename base64contents type mode
#   filename: Filename to convey to client
#   base64contents: Base64-encoded contents
#   type: type hint
#   mode: wide or regular
function print_file() {
    print_osc
    printf "1337;File=inline=1"
    printf ";size=%d" $(printf "%s" "$2" | b64_decode | wc -c)
    [ -n "$1" ] && printf ";name=%s" "$(printf "%s" "$1" | b64_encode)"
    [ -n "$3" ] && printf ";type=%s" "$3"
    [ -n "$4" ] && printf ";mode=%s" "$4"
    printf ":%s" "$2"
    print_st
    printf '\n'
    did_print=t
}

function error() {
    errcho "ERROR: $*"
}

function errcho() {
    echo "$@" >&2
}

function show_help() {
    errcho
    errcho "Usage: it2cat [-w] [-t file-type] [-u] [-f] filename ..."
    errcho "       cat filename | it2cat [-w] [-t file-type]"
    errcho
    errcho "Display a text file with native rendering."
    errcho
    errcho "Options:"
    errcho
    errcho "    -h, --help                      Display help message"
    errcho "    -u, --url                       Interpret following filename arguments as remote URLs"
    errcho "    -f, --file                      Interpret following filename arguments as regular Files"
    errcho "    -t, --type file-type            Provides a type hint"
    errcho "    -w, --wide                      Render in wide mode with a horizontal scrollbar"
    errcho
    errcho "    If a type is provided, it is used as a hint to disambiguate."
    errcho "    The file type can be a mime type like text/markdown, a language name like Java, or a file extension like .c"
    errcho "    The file type can usually be inferred from the extension or its contents. -t is most useful when"
    errcho "    a filename is not available, such as whe input comes from a pipe."
    errcho
    errcho "Examples:"
    errcho
    errcho "    $ it2cat file.txt"
    errcho "    $ cat graph.png | it2cat"
    errcho "    $ it2cat -u http://example.com/path/to/file.txt -f otherfile.txt"
    errcho "    $ cat url_list.txt | xargs it2cat -u"
    errcho "    $ it2cat -w -t application/json config.json"
    errcho
}

function check_dependency() {
    if ! (builtin command -V "$1" >/dev/null 2>&1); then
        error "missing dependency: can't find $1"
        exit 1
    fi
}

## Main

if [ -t 0 ]; then
    has_stdin=f
else
    has_stdin=t
fi

# Show help if no arguments and no stdin.
if [ $has_stdin = f ] && [ $# -eq 0 ]; then
    show_help
    exit
fi

check_dependency base64
check_dependency wc
file_type=""
mode=regular

# Look for command line flags.
while [ $# -gt 0 ]; do
    case "$1" in
    -h | --h | --help)
        show_help
        exit
        ;;
    -w | --w | --wide)
        mode=wide
        ;;
    -f | --f | --file)
        has_stdin=f
        is_url=f
        ;;
    -u | --u | --url)
        check_dependency curl
        has_stdin=f
        is_url=t
        ;;
    -t | --t | --type)
         file_type="$2"
         shift
         ;;
    -*)
        error "Unknown option flag: $1"
        show_help
        exit 1
        ;;
    *)
        if [ "$is_url" == "t" ]; then
            encoded_file=$(curl -fs "$1" | b64_encode) || {
                error "Could not retrieve file from URL $1, error_code: $?"
                exit 2
            }
        elif [ -r "$1" ]; then
            encoded_file=$(cat "$1" | b64_encode)
        else
            error "it2cat: $1: No such file or directory"
            exit 2
        fi
        has_stdin=f
        print_file "$1" "$encoded_file" "$file_type" "$mode"
        ;;
    esac
    shift
done

# Read and print stdin
if [ $has_stdin = t ]; then
    print_file "" "$(cat | b64_encode)" "$file_type" "$mode"
fi

if [ "$did_print" != "t" ]; then
    error "No file provided. Check command line options."
    show_help
    exit 1
fi

exit 0
