#!/bin/sh
set -e

die() {
    echo "$1" >&2
    exit 1
}

cachedir="${XDG_CACHE_HOME:-$HOME/.cache}/llpp"
test -d "$cachedir" || die "cache directory '$cachedir' does not exist"

caspsuf=
type=

executable_p() { command -v "$1" >/dev/null 2>&1; }

missing() {
    executable_p $1 || \
        eval "$1() { die \"$2 is needed for \$type conversion\"; }"
}

text() {
    cat <<EOF
<pre style="font-size: ${1}pt;">
=== $1 ===
EOF
    test -n "$2" && cat $2 || cat <<EOF
S9 З3Ӡʒ Il1
~
ЁЖЗ

abcdefghijklmnopqrstwxyz
ABCDEFGHIJKLMNOPQRSTWXYZ
абвгдеёжзийклмнопрстуфхцчшщэюя
АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЭЮЯ
инпипнишпнипшнипнпншпнпинпипнпипщнпипипин
иннициатива шиорокошарикоподшипниковый взбзднуть гидроаэроионизация
телегаммааппарат фельдъегерь четырёхсотпятидесятисемимиллиметровое
превысокомногорассмотрительствующий вскользь забулдыжничество
цецецница
Σομε πσθδο γρεεκ
\`1234567890-=\\
~!@#\$$%^&*()_+|
[];',./
{}:"&lt;&gt;?"
S in S9 59 S9 is like 5
final fjord flair ft
3ЗЭэзээз3ЗqgO0o ijklI1| bgqpykvwlliliiijil1 lLLl
01234567890 3ДС ЗДС ӠДС ʒДС
rnrmnnmrrrnmmr <i>Nürnberg</i> (rn -> m)
Apay Арау
örök für
- - (~-) ~ ~ (-~)
curly vs plain braces {} () {} →

kerning
    echo \${@:5}
    life           [l i fe]
    lambdabot      [l a mb]
    Commutative    [Co mm utative]
    weird          [we i rd]
    Before         [Bef ore, Be for e]
    higher         [gh, h i gher, hi gher]
    multi          [mu lti]
    till           [ti ll]
    language       [an]
    plan           [la]
    when           [wh]
    kerning        [rn | ng]
    мне            [мн е]
    oiled          [oi led]
    mkfifo         [mk f i fo, mk f i fo]
    didn't         [di dn't]
    argumnet (sic) []
    more           [mo re]
    CmmCall        [CmmC a l l]
    -Wvla          [-Wv la]
    align          [a l i gn]
    Compiling      [Co mp iling]
    print          [pr int]
    fcmono         [f cmono]
    Mail           [M ail]
    xsrc           [x src]
    Pokorna
    buildglyphs.js [buil dg lyphs]
    Dollar         [Do ll ar]
    signed         [s i gned]
    Pine           [Pi ne]
    right          [r i ght]
    ugliness
    Nigeria        [Ni g eria]
    Nothing        [Nothi ng]
    modify         [mo dify]
    mplus          [mp lus]
    Apostolic      [A postolic]
    коде           [к о де]
    Прокофьевну    [Пра ко фьевну]
    Хэлп           [X элп]
    коснулся       [ко снулся]
    обьявляным     [об ья вленым]
    Queen          [Qu een]
    etymological   [et ymologoical]
    sigh           [s i gh]
    git            [gi t]
    некочевого     [не ко чевого]
    Розовое        [Ро зо вое]
    Trump          [Tru mp]
    покрытие       [по кр ытие]
    Julia          [J ulia | Jul i a]

almost kerning
    hope doesn't
    Illegal
    automatically effective
    Ilium is the Latin for Ilion.

(from UTF8-demo.txt)
Box drawing alignment tests:                                          █
                                                                      ▉
  ╔══╦══╗  ┌──┬──┐  ╭──┬──╮  ╭──┬──╮  ┏━━┳━━┓  ┎┒┏┑   ╷  ╻ ┏┯┓ ┌┰┐    ▊ ╱╲╱╲╳╳╳
  ║┌─╨─┐║  │╔═╧═╗│  │╒═╪═╕│  │╓─╁─╖│  ┃┌─╂─┐┃  ┗╃╄┙  ╶┼╴╺╋╸┠┼┨ ┝╋┥    ▋ ╲╱╲╱╳╳╳
  ║│╲ ╱│║  │║   ║│  ││ │ ││  │║ ┃ ║│  ┃│ ╿ │┃  ┍╅╆┓   ╵  ╹ ┗┷┛ └┸┘    ▌ ╱╲╱╲╳╳╳
  ╠╡ ╳ ╞╣  ├╢   ╟┤  ├┼─┼─┼┤  ├╫─╂─╫┤  ┣┿╾┼╼┿┫  ┕┛┖┚     ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳
  ║│╱ ╲│║  │║   ║│  ││ │ ││  │║ ┃ ║│  ┃│ ╽ │┃  ░░▒▒▓▓██ ┊  ┆ ╎ ╏  ┇ ┋ ▎
  ║└─╥─┘║  │╚═╤═╝│  │╘═╪═╛│  │╙─╀─╜│  ┃└─╂─┘┃  ░░▒▒▓▓██ ┊  ┆ ╎ ╏  ┇ ┋ ▏
  ╚══╩══╝  └──┴──┘  ╰──┴──╯  ╰──┴──╯  ┗━━┻━━┛  ▗▄▖▛▀▜   └╌╌┘ ╎ ┗╍╍┛ ┋  ▁▂▃▄▅▆▇█
                                               ▝▀▘▙▄▟

https://mirrors.zju.edu.cn/CTAN/fonts/gofonts/doc/gofonts.pdf (page 2)
"""
DIN Legibility Standard

The recent German DIN 1450 legibility standard
recommends several features for font legibility, including
differentiation of letter shapes to reduce confusion. The Go fonts
conform to the 1450 standard by carefully differentiating zero from
capital O; numeral 1 from capital I (eye) and lowercase l (ell);
numeral 5 from capital S; and numeral 8 from capital B. The shapes of
bowls of b d p q follow the natural asymmetries of legible Renaissance
handwriting, aiding differentiation to reduce confusion. [5]
"""

Mistaking S for a 5 (at certain sizes) is more of a problem... but... Ze Germans

(https://en.wikipedia.org/wiki/Jabberwocky
 Idea from the aforementioned gofonts paper)

    Бе сгладне и честлинните комбурси  Það leið að stekju, og slýgir greðlar
    търляха се и сврецваха във плите;  sig snældu og böluðu um slöffruna,
    съвсем окласни бяха тук щурпите    og angurvært sungu sópfiðrungar
    и отма равапсатваха прасурси.      við sífgelt týðmana svíræna.

(https://en.wikipedia.org/wiki/Typeface)

For the rational mind, type design can be a maddening game
of drawing things differently in order to make them appear the
same.
</pre>
EOF
}

maketext() {
    # https://github.com/react-boilerplate/react-boilerplate/issues/1340
    test -d "$cachedir/fonts" || mkdir "$cachedir/fonts"
    filename="$(basename "$1")"
    textfilename="$2"
    cat >"$cachedir/fonts/text.html" <<EOF
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>$filename</title>
    <style type="text/css">
      @font-face { font-family: moo; src: url('$1'); }
      pre { font-family: moo; }
    </style>
  </head>
  $filename
  <body>
EOF
    for size in 6 8 10 12 4 2; do
        text $size $textfilename >>"$cachedir/fonts/text.html"
    done
    cat >>"$cachedir/fonts/text.html" <<EOF
    <br/>
    $(fc-scan -f '%{fullname} %{style} %{slant} %{file} %{fontversion} %{capability} %{lang}' "$1" || file "$1")
  </body>
</html>
EOF
}

trap 'test -n "$casp" && rm -f "$casp"' 0

while getopts s:c:m:t:fu opt; do
    case $opt in
        m) mime=$OPTARG;;
        t) type=$OPTARG;;
        f) force=true;;
        c) css="-s $OPTARG";;
        s) textfilename="$OPTARG";;
        ?) die "usage: $0 [-c css] [-m mime/type] [-t filter] [-f] [-s textfile] [path|url]";;
    esac
done
shift $(($OPTIND - 1))
test -z "$1" && die "usage $0: path"

origin="$1"
if ${force-test ! -e "$1"} && expr >/dev/null "$1" : "\(ftp\|https\?\)://"; then
    if executable_p wget; then
        dl() { wget -q $1 -O $2; }
    elif executable_p curl; then
        dl() { curl -L $1 -o $2; }
    else
        die "no program to fetch remote urls found"
    fi

    hashof="$cachedir/$(basename "$1")"
    dl "$1" "$hashof" || test -e "$md5of"
    shift
    set -- "$hashof" "$@"
else
    hashof="$1"
fi

test -z "$type" && { ft=$(file -L --mime-type -b "$1") || die "$ft"; }

case $ft in
    application/x-gzip | application/x-compress) dc=zcat;;
    application/x-xz) dc=xzcat;;
    application/x-bzip2) dc=bzcat;;
    *) unset dc || true;;
esac

filt='"${dc-cat}" "$1" |'

typeofmime() {
    case "$1" in
        application/postscript) type=ps;;
        application/pdf) type=pdf;;
        image/vnd.djvu) type=djvu;;
        text/html) type=html;;
        text/plain) type=text;;
        application/msword) type=word;;
        application/vnd.openxmlformats-officedocument.*  \
            | application/vnd.ms-powerpoint              \
            | application/vnd.ms-excel                   \
            | application/vnd.oasis.opendocument.*) type=uno;;
        image/svg+xml) type=svg;;
        image/png | image/jpeg) test -n "$dc" && type="image" || type="image2";;
        image/*) type=image;;
        application/x-dvi) type=dvi;;
        application/x-font-ttf                  \
            | application/vnd.ms-opentype       \
            | application/font-sfnt) type=font;;
        *) return 1;;
    esac
    return 0
}

if test -z "$type"; then
    test -z "$mime" &&                                          \
        mime=$(file -L --mime-type -b "$1" || die "$mime") ||   \
            $(file -L --mime-type -bz "$1" || die "$mime")
    typeofmime "$mime" || die "unhandled file type: '$mime'"
fi

caspsuf=".pdf"
case $type in
    ps) conv='ps2pdf - "$casp"';;
    image2|pdf) test -z "$dc" && exec llpp "$@" || conv='cat >"$casp"';;
    texi) {
        missing texi2html "texi2html(http://www.nongnu.org/texi2html/)"
        missing prince "PrinceXML(http://www.princexml.com/)"
        conv='texi2html - -o - | prince $css - -o "$casp"'
    };;
    djvu) {
        missing ddjvu "ddjvu(http://djvu.sourceforge.net/doc/man/ddjvu.html)"
        conv='ddjvu -format=pdf - "$casp"'
    };;
    html) {
        missing prince "Prince(http://www.princexml.com/)"
        conv='prince $css - -o "$casp"'
    };;
    html2epub) {
        missing pandoc "pandoc(http://pandoc.org)"
        caspsuf=".epub"
        conv='pandoc -r html - -w epub2 -o "$casp"'
    };;
    word) {
        if executable_p unoconv && test -z "$dc"; then
            unset filt
            conv='unoconv -o "$casp" "$1"'
        else
            missing antiword "antiword or unoconv"
            conv='antiword -m 8859-1.txt -a a4 - >"$casp"'
        fi
    };;
    uno) {
        test -n "$dc" && die "cannot convert compressed '$mime'"
        unset filt
        missing unoconv "unoconv(http://dag.wiee.rs/home-made/unoconv/)"
        conv='unoconv -o "$casp" "$1"'
    };;
    svg) {
        if executable_p inkscape && test -z "$dc"; then
            unset filt
            conv='inkscape -z -A "$casp" "$1"'
        else
            missing rsvg-convert "rsvg-convert"
            conv='rsvg-convert -f pdf -o "$casp"'
        fi
    };;
    font) {
        maketext "$1" "$textfilename"
        exec llpp -origin $1 -layout-height 0 "$cachedir/fonts/text.html"
    };;
    image) {
        missing convert "convert(http://www.imagemagick.org/script/convert.php)"
        conv='convert - pdf:"$casp"'
    };;
    dvi) {
        test -n "$dc" && die "cannot convert compressed '$mime'"
        unset filt
        missing dvipdf "dvipdf(http://ghostscript.com/)"
        conv='dvipdf "$1" "$casp"'
    };;
    text) {
        missing pandoc "pandoc(http://pandoc.org/)"
        conv='pandoc -t epub2 - -o "$casp"'
        caspsuf=.epub
    };;
    *) die "unhandled filter type: '$type'";;
esac

hash=$(cksum "$hashof") || die "$hash"
casp=$cachedir/${hash%% *}$caspsuf

{ test -n "$force" || test ! -e "$casp"; } && eval "$filt" "$conv"
shift

exec llpp -origin $origin "$@" "$casp"
