#!/usr/bin/env bash
###############################################################################
# @file make_fortran_stats.sh
# @brief Compute structural statistics for a Fortran source tree.
# @details
#   Purpose:
#   Analyze a Fortran source tree and compute structural and size statistics
#   for each source file and directory.
#
#   File-level metrics include:
#   - total lines
#   - code lines (internal metric)
#   - percentage of code lines in the file
#   - percentage contribution to the total code base
#   - number of programs/modules/subroutines/functions
#   - branching and I/O operation counts
#   - average lines per subroutine
#   - average branching per procedure
#   - complexity density (branches per kLOC)
#   - public API surface estimate
#   - argument complexity score
#   - memory risk indicator
#
#   Directory-level metrics aggregate totals and ratios by directory.
#   Global metrics report number of files, total lines, min/max/avg file size.
#
#   Code-line definition:
#   - non-empty
#   - not a full-line Fortran comment starting with '!'
#
#   Branch complexity proxy detects common constructs:
#   IF, ELSEIF, ELSE, SELECT CASE, CASE, DO, DO WHILE, WHERE, FORALL,
#   CYCLE, EXIT.
#
#   Supported source extensions:
#   *.f90 *.F90 *.f *.F *.for *.f95 *.inc
#
#   Usage:
#   ./make_fortran_stats.sh
#   ./make_fortran_stats.sh --csv
#
#   CSV outputs (with --csv):
#   - code_filestats.csv: per-file statistics
#   - code_dirstats.csv: aggregated directory statistics
###############################################################################

# -----------------------------------------------------------------------------
# Options
# -----------------------------------------------------------------------------

WRITE_CSV=false

if [[ "${1:-}" == "--csv" ]]; then
    WRITE_CSV=true
fi

csv_file="code_filestats.csv"
directory_csv="code_dirstats.csv"

# -----------------------------------------------------------------------------
# Global counters
# -----------------------------------------------------------------------------

total_all=0
total_code=0
file_count=0

min_code=""
max_code=""

min_lines=""
max_lines=""
sum_lines=0

declare -a files_stats

declare -A directory_code
declare -A directory_all
declare -A directory_subs
declare -A directory_lines_per_sub_sum
declare -A directory_file_count
declare -A directory_modules
declare -A directory_programs
declare -A directory_functions
declare -A directory_branches
declare -A directory_io
declare -A directory_public_api
declare -A directory_arg_complexity_sum
declare -A directory_memory_risk_sum

# Force C locale so grep/awk range expressions and numeric formatting are stable.
export LC_ALL=C
export LC_NUMERIC=C
export LC_COLLATE=C

# @brief Compute structural metrics for one Fortran source file.
# @param arg1 Path to a Fortran source file.
# @details
#   Returns a tab-separated vector with:
#   code_lines, total_lines, modules, programs, subroutines, functions,
#   branches, io_operations, lines_per_subroutine, branches_per_procedure,
#   complexity_density_per_kloc, public_api_surface, argument_complexity,
#   memory_risk_indicator.

count_fortran_metrics() {

    local file="$1"

    # --------------------------------
    # Code / total lines
    read code total <<< "$(awk '
        {
            total++
            if ($0 !~ /^\s*$/ && $0 !~ /^\s*!/) code++
        }
        END {print code "\t" total}
    ' "$file")"
    clean_code=$(sed 's/!.*$//' "$file")

    # --------------------------------
    # Structural elements
    modules=$(echo "$clean_code" | grep -Ei '^\s*module\s+[a-zA-Z_]' | grep -vi "procedure" | wc -l)
    programs=$(echo "$clean_code" | grep -Ei '^\s*program\s+' | wc -l)
    subroutines=$(echo "$clean_code" | grep -Ei '^\s*subroutine\s+[a-zA-Z_]' | grep -vi '^\s*end' | wc -l)
    functions=$(echo "$clean_code" | grep -Ei '^\s*function\s+[a-zA-Z_]' | grep -vi '^\s*end' | wc -l)
    procedures=$((subroutines + functions))

    # --------------------------------
    # Branch complexity proxy
    branches=$(echo "$clean_code" | grep -Eio '\b(if|elseif|else|select\s+case|case|do\s+|do\s+while|where|forall|cycle|exit)\b' | wc -l)

    # --------------------------------
    # I/O operations
    io_ops=$(echo "$clean_code" | grep -Eio '\b(read|write|open|close)\b' | wc -l)

    # --------------------------------
    # Derived metrics
    lines_per_sub=0
    branches_per_procedure=0
    complexity_density=0
    public_api_surface=0
    argument_complexity=0
    memory_risk=0

    if (( subroutines > 0 )); then
        lines_per_sub=$(awk -v code="$code" -v s="$subroutines" 'BEGIN{printf "%.1f", code/s}')
    fi

    if (( procedures > 0 )); then
        branches_per_procedure=$(awk -v b="$branches" -v p="$procedures" 'BEGIN{printf "%.1f", b/p}')
    fi

    if (( code > 0 )); then
        complexity_density=$(awk -v b="$branches" -v c="$code" 'BEGIN{printf "%.2f", (b*1000)/c}')
    fi

    default_private=$(echo "$clean_code" | grep -Eic '^[[:space:]]*private[[:space:]]*$')

    public_list_count=$(echo "$clean_code" | awk '
        BEGIN{IGNORECASE=1}
        /^[[:space:]]*public[[:space:]]*::/ {
            line=$0
            sub(/^[[:space:]]*public[[:space:]]*::[[:space:]]*/, "", line)
            gsub(/[[:space:]]/, "", line)
            n=split(line, a, ",")
            for(i=1;i<=n;i++) if(a[i] != "") c++
        }
        END{print c+0}
    ')

    public_proc_count=$(echo "$clean_code" | grep -Eic '^[[:space:]]*public[[:space:]]+(subroutine|function)[[:space:]]+[a-zA-Z_]')
    public_api_surface=$(( public_list_count + public_proc_count ))
    if (( default_private == 0 && public_api_surface == 0 )); then
        public_api_surface=$procedures
    fi

    args_total=$(echo "$clean_code" | awk '
        BEGIN{IGNORECASE=1}
        /^[[:space:]]*(subroutine|function)[[:space:]]+[A-Za-z_][A-Za-z0-9_]*[[:space:]]*\(/ && $0 !~ /^[[:space:]]*end[[:space:]]/ {
            line=$0
            sub(/^[^(]*\(/, "", line)
            sub(/\).*/, "", line)
            gsub(/[[:space:]]/, "", line)
            if(line == "") next
            n=split(line, a, ",")
            for(i=1;i<=n;i++) if(a[i] != "") c++
        }
        END{print c+0}
    ')

    inout_count=$(echo "$clean_code" | grep -Eic 'intent[[:space:]]*\([[:space:]]*inout[[:space:]]*\)')
    optional_count=$(echo "$clean_code" | grep -Eic '\<optional\>')
    avg_args=0
    if (( procedures > 0 )); then
        avg_args=$(awk -v a="$args_total" -v p="$procedures" 'BEGIN{printf "%.2f", a/p}')
    fi

    argument_complexity=$(awk -v avg="$avg_args" -v io="$inout_count" -v op="$optional_count" -v p="$procedures" '
        BEGIN {
            if (p > 0) {
                printf "%.2f", avg + (io/p)*0.70 + (op/p)*0.30
            } else {
                printf "0.00"
            }
        }
    ')

    alloc_decl_count=$(echo "$clean_code" | grep -Eic '\<allocatable\>')
    allocate_count=$(echo "$clean_code" | grep -Eic '\<allocate[[:space:]]*\(')
    deallocate_count=$(echo "$clean_code" | grep -Eic '\<deallocate[[:space:]]*\(')
    assumed_shape_count=$(echo "$clean_code" | grep -Eic 'dimension[[:space:]]*\([[:space:]]*:[^)]*\)')
    expr_call_count=$(echo "$clean_code" | grep -Eic '^[[:space:]]*call[[:space:]]+[a-zA-Z_][a-zA-Z0-9_]*[[:space:]]*\([^)]*[-+*/][^)]*\)')

    allocate_leak_risk=0
    if (( allocate_count > deallocate_count )); then
        allocate_leak_risk=$(( allocate_count - deallocate_count ))
    fi

    memory_risk=$(awk -v ad="$alloc_decl_count" -v ac="$allocate_count" -v ash="$assumed_shape_count" -v ex="$expr_call_count" -v leak="$allocate_leak_risk" '
        BEGIN{printf "%.1f", ad*1.0 + ac*2.2 + ash*1.0 + ex*2.6 + leak*1.4}
    ')

    echo -e "$code\t$total\t$modules\t$programs\t$subroutines\t$functions\t$branches\t$io_ops\t$lines_per_sub\t$branches_per_procedure\t$complexity_density\t$public_api_surface\t$argument_complexity\t$memory_risk"
}

# @brief Traverse source tree and aggregate all per-file metrics.
# @details
#   Collects file-level metrics, updates global counters, and accumulates
#   directory-level statistics used by the reporting functions.

gather_stats() {

    mapfile -t files < <(
    find . -type f \
    \( -iname "*.f90" -o -iname "*.F90" \
       -o -iname "*.f"   -o -iname "*.F" \
       -o -iname "*.for" -o -iname "*.f95" \
       -o -iname "*.inc" \)
    )

    if [[ ${#files[@]} -eq 0 ]]; then
        echo "No Fortran files found."
        exit 0
    fi

    for file in "${files[@]}"; do

        read code total modules programs subs funcs branches io_ops lines_per_sub branches_per_procedure complexity_density public_api_surface argument_complexity memory_risk <<< \
            "$(count_fortran_metrics "$file")"

        (( total == 0 || code == 0 )) && continue

        percent_file=$(awk "BEGIN {printf \"%.1f\", ($code/$total)*100}")

        files_stats+=("$code"$'\t'"$total"$'\t'"$modules"$'\t'"$programs"$'\t'"$subs"$'\t'"$funcs"$'\t'"$branches"$'\t'"$io_ops"$'\t'"$lines_per_sub"$'\t'"$branches_per_procedure"$'\t'"$complexity_density"$'\t'"$public_api_surface"$'\t'"$argument_complexity"$'\t'"$memory_risk"$'\t'"$file")

        total_all=$((total_all + total))
        total_code=$((total_code + code))
        ((file_count++))

        [[ -z "$min_lines" || total -lt min_lines ]] && min_lines=$total
        [[ -z "$max_lines" || total -gt max_lines ]] && max_lines=$total
        sum_lines=$((sum_lines + total))

        directory=$(dirname "$file")

        directory_code["$directory"]=$(( ${directory_code["$directory"]:-0} + code ))
        directory_all["$directory"]=$(( ${directory_all["$directory"]:-0} + total ))
        directory_subs["$directory"]=$(( ${directory_subs["$directory"]:-0} + subs ))
        directory_modules["$directory"]=$(( ${directory_modules["$directory"]:-0} + modules ))
        directory_programs["$directory"]=$(( ${directory_programs["$directory"]:-0} + programs ))
        directory_functions["$directory"]=$(( ${directory_functions["$directory"]:-0} + funcs ))
        directory_branches["$directory"]=$(( ${directory_branches["$directory"]:-0} + branches ))
        directory_io["$directory"]=$(( ${directory_io["$directory"]:-0} + io_ops ))
        directory_public_api["$directory"]=$(( ${directory_public_api["$directory"]:-0} + public_api_surface ))

        directory_lines_per_sub_sum["$directory"]=$(awk \
            -v prev=${directory_lines_per_sub_sum["$directory"]:-0} \
            -v new="$lines_per_sub" \
            'BEGIN{printf "%.1f", prev+new}')

        directory_arg_complexity_sum["$directory"]=$(awk \
            -v prev=${directory_arg_complexity_sum["$directory"]:-0} \
            -v new="$argument_complexity" \
            'BEGIN{printf "%.2f", prev+new}')

        directory_memory_risk_sum["$directory"]=$(awk \
            -v prev=${directory_memory_risk_sum["$directory"]:-0} \
            -v new="$memory_risk" \
            'BEGIN{printf "%.1f", prev+new}')

        directory_file_count["$directory"]=$(( ${directory_file_count["$directory"]:-0} + 1 ))
    done
}

# @brief Print global codebase statistics summary.
# @details
#   Reports analyzed file count, total lines, and min/max/average file size.

print_global_stats() {

    avg_lines=0
    if (( file_count > 0 )); then
        avg_lines=$(awk -v s="$sum_lines" -v n="$file_count" 'BEGIN{printf "%.1f", s/n}')
    fi

    echo
    echo "GLOBAL STATISTICS"
    echo "-----------------"
    printf "%-20s %10d\n" "Files analysed:" "$file_count"
    printf "%-20s %10d\n" "Total lines:" "$total_all"
    printf "%-20s %10d\n" "Min file size:" "$min_lines"
    printf "%-20s %10d\n" "Max file size:" "$max_lines"
    printf "%-20s %10s\n" "Avg file size:" "$avg_lines"
}

# @brief Print per-file metrics table sorted by contribution to code volume.
# @details
#   Outputs a formatted table including structural counts and derived complexity
#   indicators, sorted by each file's contribution to total code volume.

print_file_table() {

    IFS=$'\n' sorted=($(for entry in "${files_stats[@]}"; do
        code=$(echo -e "$entry" | cut -f1)
        percent_total=$(awk "BEGIN {printf \"%.1f\", ($code/$total_code)*100}")
        echo -e "$percent_total\t$entry"
    done | sort -nr -k1,1))
    unset IFS

    printf "\n%-26s %6s %6s %6s %4s %4s %5s %5s %7s %5s %7s %7s %7s %6s %7s %8s\n" \
    "File" "Lines" "%Code" "%Tot" "Prog" "Mod" "Subs" "Func" "Branch" "IO" "L/Sub" "Br/Proc" "Br/kL" "PubAPI" "ArgCx" "MemRisk"

    printf "%-26s %6s %6s %6s %4s %4s %5s %5s %7s %5s %7s %7s %7s %6s %7s %8s\n" \
    "----" "-----" "-----" "-----" "----" "---" "----" "----" "------" "--" "-----" "-------" "-----" "------" "-----" "-------"

    total_subs=0
    total_programs=0
    total_modules=0
    total_funcs=0
    total_branches=0
    total_io=0
    total_public_api=0
    total_arg_complexity=0
    total_memory_risk=0

    for line in "${sorted[@]}"; do

        percent_total=$(echo -e "$line" | cut -f1)
        code=$(echo -e "$line" | cut -f2)
        total=$(echo -e "$line" | cut -f3)
        modules=$(echo -e "$line" | cut -f4)
        programs=$(echo -e "$line" | cut -f5)
        subs=$(echo -e "$line" | cut -f6)
        funcs=$(echo -e "$line" | cut -f7)
        branches=$(echo -e "$line" | cut -f8)
        io_ops=$(echo -e "$line" | cut -f9)
        lines_per_sub=$(echo -e "$line" | cut -f10)
        branches_per_procedure=$(echo -e "$line" | cut -f11)
        complexity_density=$(echo -e "$line" | cut -f12)
        public_api_surface=$(echo -e "$line" | cut -f13)
        argument_complexity=$(echo -e "$line" | cut -f14)
        memory_risk=$(echo -e "$line" | cut -f15)
        file=$(echo -e "$line" | cut -f16-)
        percent_code=$(awk "BEGIN {printf \"%.1f\", ($code/$total)*100}")

        if [ ${#file} -gt 26 ]; then
            file="...${file: -23}"
        fi

        total_subs=$(( total_subs + subs ))
        total_programs=$(( total_programs + programs ))
        total_modules=$(( total_modules + modules ))
        total_funcs=$(( total_funcs + funcs ))
        total_branches=$(( total_branches + branches ))
        total_io=$(( total_io + io_ops ))
        total_public_api=$(( total_public_api + public_api_surface ))
        total_arg_complexity=$(awk -v t="$total_arg_complexity" -v v="$argument_complexity" 'BEGIN{printf "%.2f", t+v}')
        total_memory_risk=$(awk -v t="$total_memory_risk" -v v="$memory_risk" 'BEGIN{printf "%.1f", t+v}')

        printf "%-26s %6d %6s %6s %4d %4d %5d %5d %7d %5d %7s %7s %7s %6s %7s %8s\n" \
        "$file" "$total" "$percent_code" "$percent_total" \
        "$programs" "$modules" "$subs" "$funcs" "$branches" "$io_ops" \
        "$lines_per_sub" "$branches_per_procedure" "$complexity_density" "$public_api_surface" "$argument_complexity" "$memory_risk"
    done

    total_percent_code=$(awk "BEGIN {printf \"%.1f\", ($total_code/$total_all)*100}")
    total_complexity_density=$(awk -v b="$total_branches" -v c="$total_code" 'BEGIN{if(c>0) printf "%.2f", (b*1000)/c; else printf "0.00"}')
    avg_arg_complexity=0
    if (( file_count > 0 )); then
        avg_arg_complexity=$(awk -v s="$total_arg_complexity" -v n="$file_count" 'BEGIN{printf "%.2f", s/n}')
    fi

    printf "%-26s %6d %6s %6s %4s %4s %5d %5s %7s %5s %7s %7s %7s %6s %7s %8s\n" \
    "TOTAL" "$total_all" "$total_percent_code" "100.0" \
    "$total_programs" "$total_modules" "$total_subs" "$total_funcs" "$total_branches" "$total_io" "-" "-" \
    "$total_complexity_density" "$total_public_api" "$avg_arg_complexity" "$total_memory_risk"
}

# @brief Print aggregated per-directory metric table.
# @details
#   Outputs aggregated directory totals with complexity/API/memory indicators.

print_directory_table() {

    printf "\n%-26s %10s %10s %7s %11s %9s %8s %7s %8s %10s\n" \
        "Directory" "CodeLines" "AllLines" "Subs" "AvgL/Sub" "Br/kL" "PubAPI" "ArgCx" "MemRisk" "% of Total"

    printf "%-26s %10s %10s %7s %11s %9s %8s %7s %8s %10s\n" \
        "---------" "---------" "--------" "----" "----------" "-----" "------" "-----" "-------" "----------"

    total_subs=0

    for directory in "${!directory_code[@]}"; do

        code=${directory_code["$directory"]}
        total=${directory_all["$directory"]}
        subs=${directory_subs["$directory"]}

        total_subs=$(( total_subs + subs ))

        lines_per_sub_sum=${directory_lines_per_sub_sum["$directory"]}
        public_api=${directory_public_api["$directory"]:-0}
        arg_complexity_sum=${directory_arg_complexity_sum["$directory"]:-0}
        memory_risk_sum=${directory_memory_risk_sum["$directory"]:-0}
        file_count_dir=${directory_file_count["$directory"]:-0}

        avg_lines_sub=0
        if (( subs > 0 )); then
            avg_lines_sub=$(awk -v sum="$lines_per_sub_sum" -v subs="$subs" \
                'BEGIN{printf "%.1f", sum/subs}')
        fi

        complexity_density_dir=0
        if (( code > 0 )); then
            complexity_density_dir=$(awk -v b="${directory_branches["$directory"]:-0}" -v c="$code" 'BEGIN{printf "%.2f", (b*1000)/c}')
        fi

        avg_arg_complexity_dir=0
        if (( file_count_dir > 0 )); then
            avg_arg_complexity_dir=$(awk -v s="$arg_complexity_sum" -v n="$file_count_dir" 'BEGIN{printf "%.2f", s/n}')
        fi

        percent_total=$(awk "BEGIN {printf \"%.1f\", ($code/$total_code)*100}")

        display_directory="$directory"
        if [ ${#directory} -gt 26 ]; then
            display_directory="...${directory: -23}"
        fi

        printf "%-26s %10d %10d %7d %11s %9s %8d %7s %8s %9s%%\n" \
            "$display_directory" "$code" "$total" "$subs" "$avg_lines_sub" "$complexity_density_dir" "$public_api" "$avg_arg_complexity_dir" "$memory_risk_sum" "$percent_total"

    done | sort -nr -k10,10
}

# @brief Export per-file and per-directory metrics as CSV outputs.
# @details
#   Generates code_filestats.csv and code_dirstats.csv for external analysis
#   in spreadsheets or scientific tools.

write_csv() {

    echo

    echo "File,Code,Total,%Code,%Total,Modules,Programs,Subroutines,Functions,Branches,IO,Lines/Sub,Branches/Proc,Branches/kLOC,PublicAPI,ArgComplexity,MemoryRisk" > "$csv_file"

    for entry in "${files_stats[@]}"; do

        code=$(echo -e "$entry" | cut -f1)
        total_lines=$(echo -e "$entry" | cut -f2)
        modules=$(echo -e "$entry" | cut -f3)
        programs=$(echo -e "$entry" | cut -f4)
        subs=$(echo -e "$entry" | cut -f5)
        funcs=$(echo -e "$entry" | cut -f6)
        branches=$(echo -e "$entry" | cut -f7)
        io_ops=$(echo -e "$entry" | cut -f8)
        lines_per_sub=$(echo -e "$entry" | cut -f9)
        branches_per_procedure=$(echo -e "$entry" | cut -f10)
        complexity_density=$(echo -e "$entry" | cut -f11)
        public_api_surface=$(echo -e "$entry" | cut -f12)
        argument_complexity=$(echo -e "$entry" | cut -f13)
        memory_risk=$(echo -e "$entry" | cut -f14)
        file=$(echo -e "$entry" | cut -f15-)

        percent_code=$(awk "BEGIN {printf \"%.1f\", ($code/$total_lines)*100}")
        percent_total=$(awk "BEGIN {printf \"%.1f\", ($code/$total_code)*100}")

        echo "\"$file\",$code,$total_lines,$percent_code,$percent_total,$modules,$programs,$subs,$funcs,$branches,$io_ops,$lines_per_sub,$branches_per_procedure,$complexity_density,$public_api_surface,$argument_complexity,$memory_risk" \
        >> "$csv_file"
    done

    echo "File stats CSV saved to $csv_file"

    echo "Directory,Code,Total,%Total,Modules,Programs,Subroutines,Functions,Branches,IO Ops,Avg Lines/Sub,Branches/kLOC,PublicAPI,Avg ArgComplexity,MemoryRisk" \
        > "$directory_csv"

    total_subs=0
    total_modules=0
    total_programs=0
    total_funcs=0
    total_branches=0
    total_io=0
    total_public_api=0
    total_arg_complexity_sum=0
    total_memory_risk=0
    total_dir_files=0

    for directory in "${!directory_code[@]}"; do

        code=${directory_code["$directory"]}
        total=${directory_all["$directory"]}
        subs=${directory_subs["$directory"]}
        modules=${directory_modules["$directory"]}
        programs=${directory_programs["$directory"]}
        funcs=${directory_functions["$directory"]}
        branches=${directory_branches["$directory"]}
        io_ops=${directory_io["$directory"]}
        public_api=${directory_public_api["$directory"]:-0}
        arg_complexity_sum=${directory_arg_complexity_sum["$directory"]:-0}
        memory_risk_sum=${directory_memory_risk_sum["$directory"]:-0}
        file_count_dir=${directory_file_count["$directory"]:-0}

        total_subs=$(( total_subs + subs ))
        total_modules=$(( total_modules + modules ))
        total_programs=$(( total_programs + programs ))
        total_funcs=$(( total_funcs + funcs ))
        total_branches=$(( total_branches + branches ))
        total_io=$(( total_io + io_ops ))
        total_public_api=$(( total_public_api + public_api ))
        total_arg_complexity_sum=$(awk -v s="$total_arg_complexity_sum" -v v="$arg_complexity_sum" 'BEGIN{printf "%.2f", s+v}')
        total_memory_risk=$(awk -v s="$total_memory_risk" -v v="$memory_risk_sum" 'BEGIN{printf "%.1f", s+v}')
        total_dir_files=$(( total_dir_files + file_count_dir ))

        lines_per_sub_sum=${directory_lines_per_sub_sum["$directory"]}

        avg_lines_sub=0
        if (( subs > 0 )); then
            avg_lines_sub=$(awk -v sum="$lines_per_sub_sum" -v subs="$subs" \
                'BEGIN{printf "%.1f", sum/subs}')
        fi

        complexity_density_dir=0
        if (( code > 0 )); then
            complexity_density_dir=$(awk -v b="$branches" -v c="$code" 'BEGIN{printf "%.2f", (b*1000)/c}')
        fi

        avg_arg_complexity_dir=0
        if (( file_count_dir > 0 )); then
            avg_arg_complexity_dir=$(awk -v s="$arg_complexity_sum" -v n="$file_count_dir" 'BEGIN{printf "%.2f", s/n}')
        fi

        percent_total=$(awk "BEGIN {printf \"%.1f\", ($code/$total_code)*100}")

        echo "\"$directory\",$code,$total,${percent_total}%,$modules,$programs,$subs,$funcs,$branches,$io_ops,$avg_lines_sub,$complexity_density_dir,$public_api,$avg_arg_complexity_dir,$memory_risk_sum" \
            >> "$directory_csv"
    done

    total_complexity_density=$(awk -v b="$total_branches" -v c="$total_code" 'BEGIN{if(c>0) printf "%.2f", (b*1000)/c; else printf "0.00"}')
    total_avg_arg_complexity=0
    if (( total_dir_files > 0 )); then
        total_avg_arg_complexity=$(awk -v s="$total_arg_complexity_sum" -v n="$total_dir_files" 'BEGIN{printf "%.2f", s/n}')
    fi

    echo "\"TOTAL\",$total_code,$total_all,100%,$total_modules,$total_programs,$total_subs,$total_funcs,$total_branches,$total_io,-,$total_complexity_density,$total_public_api,$total_avg_arg_complexity,$total_memory_risk" >> "$directory_csv"

    echo "Directory stats CSV saved to $directory_csv"
}

# =============================================================================
# Main program
# =============================================================================

gather_stats
print_global_stats
print_file_table
print_directory_table

if $WRITE_CSV; then
    write_csv
fi
