#!/bin/bash

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
#   ocelot -- The cute alternative to cat (with headers!)   #
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
#  Author: binaryDiv                                        #
#  Version: 1.1.0                                           #
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #

# Strict mode
set -euo pipefail
IFS=$'\n\t'

BASENAME=$(basename $0)

# Global options
STYLE=big
PREFIXCHAR='#'
LINECHAR='~'


# Helper functions
# ----------------

# Prints help text
function usage {
    cat << END_OF_HELPTEXT
Usage: $BASENAME [OPTION] FILE...

Prints all FILEs with their filename as a header. Like cat but more cute.
If FILE is '-', it reads from standard input.

General options:
  -h            print this help message

Style options:
  -b            show big headers (with lines above and under filename; default)
  -s            show single lined headers (only prefix and filename)
  -n            no style, just print filename and content
  -p PREFIX     use PREFIX in front of the header lines (default: '#')
  -l LINECHAR   use LINECHAR as character for lines in big headers (default: '~')
END_OF_HELPTEXT
}

# Print a single file with header
function print_file_with_header {
    file=$1

    print_header $file
    print_file $file
    echo
}

# Prints a header
function print_header {
    text=$1

    if [[ $text == '-' ]]; then
        text='STDIN'
    fi
    
    case $STYLE in
        big)
            header_style_big "$text"
            ;;

        singleline)
            header_style_singleline "$text"
            ;;

        none | *)
            header_style_none "$text"
            ;;
    esac
}

# Print error message
function print_error {
    text=$1
    echo "${PREFIX}[$text]"
}

# Prints content of file
function print_file {
    file=$1

    if [[ -f $file || -p $file || $file == '-' ]]; then
        cat $file
    elif [[ -d $file ]]; then
        print_error "File is a directory"
    else
        print_error "File does not exist"
    fi
}


# Define header styles
# --------------------

function header_style_none {
    text=$1
    echo $text
}

function header_style_singleline {
    text=$1
    echo "${PREFIX}${text}"
}

function header_style_big {
    text=$1
    length=${#text}

    echo -n "${PREFIX}"; characterline $LINECHAR $length
    echo    "${PREFIX}${text}"
    echo -n "${PREFIX}"; characterline $LINECHAR $length
}

# Print a line of characters (e.g. `characterline '#' 32`)
function characterline {
    char=$1
    count=$2

    for (( i = 0; i < $count; i++ )); do echo -n $char; done
    echo
}



# Main program
# ------------

if [[ "$@" == "--help" ]]; then
    usage
    exit 0
fi

# Parse shell arguments and set global variables
while getopts ":hbsnp:l:" option; do
    case $option in
        h)
            usage
            exit 0
            ;;

        b) STYLE=big ;;
        s) STYLE=singleline ;;
        n) STYLE=none ;;

        p) PREFIXCHAR="$OPTARG" ;;
        l) LINECHAR="$OPTARG" ;;

        :)
            echo "$BASENAME: option -$OPTARG requires an argument" >&2
            echo "Try '$BASENAME --help' for more information." >&2
            exit 1
            ;;

        ?)
            echo "$BASENAME: invalid option: -$OPTARG" >&2
            echo "Try '$BASENAME --help' for more information." >&2
            exit 1
            ;;
    esac
done

# Remove parsed options from arguments
shift $(($OPTIND - 1))

# Set some global variables
PREFIX=
if [[ $PREFIXCHAR != '' ]]; then
    PREFIX="$PREFIXCHAR "
fi

# Print all files
for file in $@; do
    print_file_with_header $file
done

