#!/usr/bin/env perl

# Script:      ds
# Lang:        perl
# Description: calculates and displays the size of a given directory in a human
#              readable format

# Copyright Frederick Boniface 2023 - fredboniface.co.uk
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

use strict;
use warnings;
use File::Find;
use Cwd;
use Getopt::Long;

my $version = "0.0.1";

my $help;
my $verbose;

my $usage = "Usage: $0 <directory_path>\n";

GetOptions(
    'help|h' => \$help,
    'verbose|v' => \$verbose,
) or die $usage;

if ($help) {
    print <<EOF;
\nds - $version - Copyright Frederick Boniface 2023
\n$usage
Calculate the size of a directory and its contents.\n

Note: Sizes are reported in bytes, Kilobytes, Megabytes...

Options:
  -h, --help        Show this help message and exit
  -v, --verbose     List all files and folders encountered
EOF
    exit;
}

if (@ARGV != 1) {
    die $usage;
}

my $dir_path = $ARGV[0];

$dir_path = Cwd::abs_path($dir_path);

unless (-d $dir_path) {
    die "$dir_path is not a directory\n"
}

if ($dir_path eq '/') {
    die "You are not able to run 'ds' on the root directory\n"
}

my $total_size = 0;

sub calculate_size {
    my $file = $File::Find::name;

    return if -l $file;

    if (-f $file) {
        $total_size += -s $file;
        if ($verbose) {
            print "File: $file\n"
        }
    }

    if (-d $file) {
        if ($verbose) {
            print "Directory: $file\n"
        }
    }
}

find(\&calculate_size, $dir_path);

sub format_size {
    my $size = shift;
    my @units = qw(B KB MB GB TB);
    my $unit_index = 0;

    while ($size >= 1024 && $unit_index < @units -1) {
        $size /= 1024;
        $unit_index++;
    }

    return sprintf("%.2f %s", $size, $units[$unit_index]);
}

print "Total size of $dir_path:\n", format_size($total_size), "\n"