#!/bin/bash

ScriptFile=$(readlink -f "${BASH_SOURCE[0]}")
ScriptDir=$(dirname "${ScriptFile}")
SearchDir="${ScriptDir}"
FileExts="h;in;hpp;inl;c;cpp;make;cmake;txt;json;js;jsx;ts;tsx;html;tpl;css"
Verbose=0

function Log()
{
    printf "$@\n"
}

function Error()
{
    >&2 printf "$@\n"
}

function Panic()
{
    Error "$@"
    exit 1
}

function PrintHelp()
{
    printf "
This is a tool to calculate the number of code lines within a certain folder.

The tool looks for a 'CMakeLists.txt' or a 'Makefile' in the subfolders.
If such a file exists, the folder is treated as subproject.
Subprojects have their own counters.

Parameters:

    -d|--dir <directory>
        Directory to search in
        (default ${SearchDir}).

    -e|--ext <file extension>
        File extension to look for
        (default: ${FileExts})

    -v|--verbose
        Verbose output (Print lines of code for each file extension)
        (default: false)

    -?|-h|--help
        Print this help.

"
}

# Parse arguments
while [ $# -gt 0 ]; do
    case $1 in
        "-d" | "--dir" )
            if [ $# -lt 2 ]; then
                Panic "Parameter $1 expects exactly one parameter!"
            fi
            SearchDir=$(readlink -m "$2")
            shift
            ;;

        "-e" | "--ext" )
            if [ $# -lt 2 ]; then
                Panic "Parameter $1 expects exactly one parameter!"
            fi
            FileExts="$2"
            shift
            ;;

        "-v" | "--verbose" )
            Verbose=1
            ;;

        "-h" | "-?" | "--help" )
            PrintHelp
            exit 0
            ;;

        * )
            Panic "Invalid or unknown parameter: $1"
            ;;
    esac
    shift
done

OLD_IFS=${IFS}
IFS=';'
read -ra Exts <<< "${FileExts}"
IFS=${OLD_IFS}

Projects="$(find ${SearchDir} -type d -exec sh -c 'test -f "$1/CMakeLists.txt" || test -f "$1/Makefile"' -- {} \; -print -prune)"
First=1
declare -A ExtLines
TotalLines=0
echo "======================================="
echo "=            Lines of Code            ="
echo "======================================="
for Project in ${Projects[@]}; do
    Name=${Project#"$SearchDir"}

    if [ "$Verbose" -eq 1 ]; then
        if [ "$First" -eq 1 ]; then
            echo "_______________________________________"
        fi
        printf "%-30s\n" "${Name:-root}:"
        echo "  \`+-----------------------------------"
    fi

    ProjectLines=0
    for ext in "${Exts[@]}"; do
        Lines=$(find ${Project} \
            -type f \
            -iname *.${ext} \
            2>/dev/null \
            | xargs cat 2>/dev/null \
            | wc -l)

        if [ "$Verbose" -eq 1 ] && [ "$Lines" -gt 0 ]; then
            printf "   |%-26s %8d\n" "${ext}" ${Lines}
        fi

        if [ "$First" -eq 1 ]; then
            ExtLines[$ext]=$Lines
        else
            let ExtLines[$ext]=${ExtLines[$ext]}+${Lines}
        fi

        let ProjectLines=${ProjectLines}+${Lines}
    done

    if [ "$Verbose" -eq 1 ]; then
        echo "   +-----------------------------------"
        printf "   |%-26s %8d\n" "total:" ${ProjectLines}
    else
        printf "%-30s %8d\n" "${Name:-root}:" ${ProjectLines}
    fi

    First=0

    let TotalLines=${TotalLines}+${ProjectLines}
done

echo "======================================="

if [ "$Verbose" -eq 1 ]; then
    printf "%-30s\n" "total:"
    echo "  \`+-----------------------------------"

    for ext in "${Exts[@]}"; do
        if [ "${ExtLines[$ext]}" -gt 0 ]; then
            printf "   |%-26s %8d\n" "${ext}" ${ExtLines[$ext]}
        fi
    done

    echo "   +-----------------------------------"
    printf "   |%-26s %8d\n" "total:" ${TotalLines}
else
    printf "%-30s %8d\n" "total:" ${TotalLines}
fi

echo "======================================="
