#!/bin/bash
# tldr client by Ray Lee, http://github.com/raylee/tldr
# a Sunday afternoon's project, I'm sure there's room for improvement. PRs welcome!

set -uf -o pipefail

# initialize globals, sanity check the environment, etc.
config() {
    init_term_cmds

    if [ -z $(which curl) ]; then
        echo "${red}tldr requires \`curl\` installed in your path$reset"
        exit 1
    fi

    configdir=~/.tldr
    [ -d ~/.config ] && configdir=~/.config/tldr

    platform=$(get_platform)
    base_url="https://raw.githubusercontent.com/tldr-pages/tldr/master/pages"
    index_url="http://tldr-pages.github.io/assets/index.json"
    index="$configdir/index.json"
    cache_days=14
    force_update=''

    #check if config folder exists, otherwise create it
    [ -d "$configdir" ] || mkdir -p "$configdir"

    [ ! -f $index ] && update_index
    auto_update_index
}

update_index() {
    curl -sf -o "$index" "$index_url"
    res=$?
    if [ $res -eq 22 ]; then
        echo "Could not download index from $index_url"
        exit 1
    fi
}

# if the file exists and is more recent than $cache_days old
recent() {
    exists=$(find "$1" -mtime -$cache_days 2>/dev/null)
    [ -n "$exists" -a -z "$force_update" ]
}

auto_update_index() {
    recent "$index" || update_index
}

# function contents via http://mywiki.wooledge.org/BashFAQ/037
init_term_cmds() {
    # only set if we're on an interactive session
    [[ -t 2 ]] && {
        reset=$(    tput sgr0   || tput me      ) # Reset cursor
        bold=$(     tput bold   || tput md      ) # Start bold
        under=$(    tput smul   || tput us      ) # Start underline
        italic=$(   tput sitm   || tput ZH      ) # Start italic
        eitalic=$(  tput ritm   || tput ZH      ) # End italic
        default=$(  tput op                     )
        back=$'\b'

        [[ $TERM != *-m ]] && {
            black=$(    tput setaf 0 || tput AF 0    )
            red=$(      tput setaf 1 || tput AF 1    )
            green=$(    tput setaf 2 || tput AF 2    )
            yellow=$(   tput setaf 3 || tput AF 3    )
            blue=$(     tput setaf 4 || tput AF 4    )
            magenta=$(  tput setaf 5 || tput AF 5    )
            cyan=$(     tput setaf 6 || tput AF 6    )
            white=$(    tput setaf 7 || tput AF 7    )

            onblue=$(   tput setab 4 || tput AB 4    )
            ongrey=$(   tput setab 7 || tput AB 7    )
        }
    } 2>/dev/null ||:

    # osx's termcap doesn't have italics. The below adds support for iTerm2
    # and is harmless on Terminal.app
    [ "$(get_platform)" = "osx" ] && {
        italic=$(echo -e "\033[3m")
        eitalic=$(echo -e "\033[23m")
    }
}

heading() {
    local line="$*"
    echo "$bold$red${line:2}$reset"
}

quotation() {
    local line="$*"
    echo "$under${line:2}$reset"
}

list_item() {
    local line="$*"
    echo "$line$reset"
}

code() {
    local line="$*"
    # I'm sure there's a better way to strip the first and last characters.
    line="${line:1}"
    line="${line%\`}"
    # convert {{variable}} to italics
    line=${line//\{\{/$italic}
    line=${line//\}\}/$eitalic}

    echo "$bold$line$reset"
}

text() {
    local line="$*"
    echo "$line"
}

# an idiot-level recognition of tldr's markdown. Needs improvement, or
# subcontracting out to a markdown -> ANSI formatting command
display_tldr() {
    # read one line at a time, don't strip whitespace ('IFS='), and process
    # last line even if it doesn't have a newline at the end
    while IFS= read -r line || [[ -n "$line" ]]; do
        start=${line:0:1}           # get the first character
        case "$start" in
            '#') heading "$line"
                ;;
            '>') quotation "$line"
                ;;
            '-') list_item "$line"
                ;;
            '`') code "$line"
                ;;
            *) text "$line"
                ;;
        esac
    done
}

# convert the local platorm name to tldr's version
get_platform() {
    case `uname -s` in
        Darwin) echo "osx"    ;;
        Linux)  echo "linux"  ;;
        SunOS)  echo "sunos"  ;;
        *)      echo "common" ;;
    esac
}

# extract the platform key from index.json, return preferred subpath to tldrpage
path_for_cmd() {
    local desc=$(tr '{' '\n' < $index | grep "\"name\":\"$1\"")
    # results in, eg, "name":"netstat","platform":["linux","osx"]},

    [ -z "$desc" ] && return

    # use the platform specific version of the tldr first
    if [[ $desc =~ \"$platform\" ]]; then
        echo "$platform/$1.md"
    elif [[ $desc =~ \"common\" ]]; then
        echo "common/$1.md"
    else
        # take the first one so we can show something, but warn the user
        local p=$(echo "$desc" | cut -d '"' -f 8)
        >&2 echo -e "${red}tldr page $1 not found in $platform or common, using page from platform $p instead$reset\n"
        echo "$p/$1.md"
    fi
}

# return the local cached copy of the tldrpage, or retrieve and cache from github
get_tldr() {
    local p="$(path_for_cmd $1)"
    cached="$configdir/$p"
    recent "$cached" || {
        mkdir -p $(dirname $cached)
        curl -sf -o "$cached" "$base_url/$p"
    }
    # if the curl failed for some reason, keep cat from whinging
    cat "$cached" 2>/dev/null
}


config

usage() {
    cmd=$(basename $0)
    cat <<EOF
USAGE: $cmd [options] <command>

[options]
    -l, --list:      show all available pages
    -p, --platform:  show page from specific platform rather than autodetecting
    -u, --update:    update, force retrieving latest copies of locally cached files
    -h, -?, --help:  this help overview

<command>
    Show examples for this command

The client caches a copy of all pages and the index locally under
$configdir. By default, the cached copies will expire in $cache_days days.

EOF
exit 0
}

while [ $# -gt 0 ]
do
    case "$1" in
        -l|--list)
            >&2 echo -e "Known tldr pages: \n"
            tr '{' '\n' < "$configdir/index.json" | cut -d '"' -f4 | column
            exit 0
            ;;
        -u|--update)
            force_update=yes
            update_index
            ;;
        -h|-\?|--help)
            usage
            ;;
        -p|--platform)
            shift
            platform=$1
            ;;
        -*)
            usage
            ;;
        *)
            page=${1:-''}
            ;;
    esac
    shift
done

[ -z ${page:-} ] && usage

tldr="$(get_tldr $page)"

if [ -z "$tldr" ]; then
    echo "tldr page for command $page not found"
    exit 1
fi

display_tldr <<< "$tldr"
echo
