#!/bin/bash
# :mode=shellscript:
# @file
# @brief Uses: ack, awk, perl to count source lines of code

me=$(basename $(readlink -f $0))

# Counters
type_tick=0
file_tick=0

code_tick=0
hash_tick=0 # Hash Comments
line_tick=0 # Line Comments
wide_tick=0 # Wide/Range Comments
void_tick=0 # Blank Lines
full_tick=0 # Total Lines

opt_type=""
opt_file_list=""
opt_verb=0

function echo_help()
{
    cat <<EOF
sloc.sh - http://sloc.sh/
Counts Source Lines of Code

$0 [option] [files]
    --help      -h   Help
    --type=TYPE -t=  Specific Types
    --verbose   -v   Verbose

EOF
}

function echo_verb()
{
    if [[ $opt_verb -ge $1 ]]
    then
        echo "$2"
    fi
}

function update()
{
    curl -qs http://sloc.sh/$me > $me
}

#
# @todo Don't count '#' comments when evaluating HTML or XML or CSS files
# @todo 
function sloc_file()
{
    echo_verb 1 "File: $1"

    eval $(awk '/^\s*#/ { hash_tick++; next; } \
    /^\s*\/\/|^\s*\-\-/ { line_tick++; next; } \
    /^\s*$/ { void_tick++; next; }
    /\/\*/ { wide_flag=1; } \
    /\*\// { wide_flag=0; } \
    wide_flag { wide_tick++; next; }
    /./ { code_tick++; next; }
    END {
        print "code=" code_tick
        print "hash=" hash_tick
        print "line=" line_tick
        print "wide=" wide_tick
        print "void=" void_tick
        print "full=" NR
    }' $1)

    # eval $(perl -n -e)

    if [ -z "$code" ]; then code="0"; fi
    if [ -z "$hash" ]; then hash="0"; fi
    if [ -z "$line" ]; then line="0"; fi
    if [ -z "$wide" ]; then wide="0"; fi
    if [ -z "$void" ]; then void="0"; fi
    if [ -z "$full" ]; then full="0"; fi

    type_file_tick=$(( $type_file_tick + 1))

    type_code_tick=$(( $type_code_tick + $code ))
    type_hash_tick=$(( $type_hash_tick + $hash ))
    type_line_tick=$(( $type_line_tick + $line ))
    type_wide_tick=$(( $type_wide_tick + $wide ))
    type_void_tick=$(( $type_void_tick + $void ))
    type_full_tick=$(( $type_full_tick + $full ))
}

function type_list()
{
    if [ -n "$opt_type" ]; then
        echo $opt_type | sed 's/ /\n/g'
        return
    fi
    # ack --help-types |awk '/\-\-/ { print $1 " "; for(i=2;i<=NF;++i) print $i " "}'

    # ack --help-types \
    #     | sed 's/\[no\]//' \
    #     | awk '/\-\-/ { print $1 " " substr($0, index($0,$2)) } '
    ack --help-types \
        | perl -n -e '/^\s+\-\-\[no](\w+)\s+(.+)$/ && print "$1\n" unless /(binary|skipped|text)/'
}

#
# Process Cella Options
if [ $# == 0 ]; then
    echo_help
fi
for opt in $@
do
    case "${opt}" in
    --help|-h)
        echo_help
        exit
        ;;
    --type=*|-t=*)
        x=${opt#*=}
        opt_type="${opt_type}${x} "
        ;;
    --verbose|-v)
        opt_verb=$(( $opt_verb + 1 ))
        ;;
    *)
        if [ -f "$opt" ]; then
            opt_type="-"
            opt_file_list="${opt_file_list}${opt}
"
        fi
        ;;
    esac
done

# echo -e "Types: $opt_type"
# echo "Files: $opt_file_list"
echo "File List: $opt_file_list";

IFS=$'\n'

for type in $(type_list)
do
    # Type Counters
    type_tick=$(( $type_tick + 1))
    type_file_tick=0

    type_code_tick=0
    type_hash_tick=0
    type_line_tick=0
    type_wide_tick=0
    type_void_tick=0
    type_full_tick=0

    # Iterate Files
    if [ -z "$opt_file_list" ]
    then
        for f in $(ack --nofollow --recurse --type=$type -f)
        do
            sloc_file $f
        done
    else
        for f in "$opt_file_list"
        do
            sloc_file $f
        done
    fi


    if [[ $type_file_tick > 0 ]]; then

        echo "Files ($type): $type_file_tick"
        echo "    Code: $type_code_tick"
        echo "    Hash: $type_hash_tick"
        echo "    Line: $type_line_tick"
        echo "    Wide: $type_wide_tick"
        echo "    Void: $type_void_tick"
        echo "    Full: $type_full_tick"

    fi

    file_tick=$(( $file_tick + $type_file_tick))
    code_tick=$(( $code_tick + $type_code_tick))
    hash_tick=$(( $hash_tick + $type_hash_tick))
    line_tick=$(( $line_tick + $type_line_tick))
    wide_tick=$(( $wide_tick + $type_wide_tick))
    void_tick=$(( $void_tick + $type_void_tick))
    full_tick=$(( $full_tick + $type_full_tick))

done

if [ $type_file_tick -ne $file_tick ]
then
    echo "Total Files: $file_tick"
    echo "    Code: $code_tick"
    echo "    Comments: $hash_tick / $line_tick / $wide_tick (#, //, /**/)"
    echo "    Blank Lines: $void_tick"
    echo "    Total Lines: $full_tick"
fi
