#!/usr/bin/perl -w

#############################################################
#
# Author: Artur Krzywanski
# WWW: www.krzywanski.net
#
# You can do whatever you want with this script,
# however it would be nice to hear about it ;)
#
#############################################################

use strict;
use Number::Bytes::Human qw(format_bytes);
use Getopt::Long;

my $dir = "/";
my $limit = 10;
my $mode = "dirs";

GetOptions (
	'dir|d=s' => \$dir,
	'limit|l=i' => \$limit,
	'mode|m=s' => \$mode
);

my @du = ();
if ($mode eq "files")
{
	print "Analyzing files in $dir";
	@du = qx(du -a $dir | cut -f 1,2 --output-delimiter=";");
}
elsif ($mode eq "dirs")
{
	if ($dir =~ m/!^\//)
	{
		print "Path has to be absolute !\n";
		exit 1;
	}
	elsif ($dir !~ m/\/$/)
	{
		$dir .= "/";
	}
	print "Analyzing dirs in $dir";
	@du = qx(for dir in \$(ls -1 $dir); do size=`du -ca $dir\$dir | tail -n 1`; echo \$size \$dir; done | cut -d ' ' -f 1,3 --output-delimiter=";");
}
else
{
	print "Unknown mode\n";
	exit 1;	
}

my @dirs_unsorted;

foreach my $in (@du)
{
	chomp $in;
	my ($size,$name) = split(/;/,$in);
	push(@dirs_unsorted,{name => $name, size => $size});	
}  

# sort array
my @dirs_sorted = sort by_size (@dirs_unsorted);
@dirs_sorted = reverse(@dirs_sorted);

my $j = 1;

print "\n---\n";

for (my $i = 0; $i < scalar @dirs_sorted; $i++)
{
	my $name = $dirs_sorted[$i]{'name'};
	my $size = $dirs_sorted[$i]{'size'};
	$size = format_bytes($size*1000);
	if ($mode eq "files")
	{
		next unless -f $name;
		print "$size\t$name\n";
	}
	else
	{
		print "$size\t$dir$name\n";
	}
	last if $j == $limit;
	$j++;
}

# SUBROUTINE

sub by_size 
{
	return 0 if (!exists($a->{"name"}));
	return 0 if (!exists($b->{"name"}));
	return 0 if (!exists($a->{"size"}));
	return 0 if (!exists($b->{"size"}));
	# sort by size (then by name if size is identical)
	return ($a->{"size"} - $b->{"size"}) || ($a->{"name"} cmp $b->{"name"});
}

