#!/usr/bin/perl

#v 1.07

use strict;
use warnings;
use Cwd;
use threads;
use threads::shared;
use Getopt::Long qw(GetOptions);
use Pod::Usage qw(pod2usage);

my $bytes = 0;
my $help = 0;
my $simulate = 0;
my $log = '';

GetOptions(
	'b|bytes' => \$bytes,
	'help' => \$help,
	's|simulate' => \$simulate,
	'l|log=s' => \$log
	) or pod2usage(2);

pod2usage(1) if $help;

my $dir = getcwd;

my $delfcount :shared = 0;
my $delfsize  :shared = 0;
my $deldcount :shared = 0;
my $totfcount :shared = 0;
my $totdcount :shared = 0;
my $totsize = 0;

my $logging = $log ne '';
if ($logging) {
	open (FLOG, ">$log") || die "$!\n";
}

$|=1;
print "\n\n\n\n";
my $thr = threads->create('Recur', $dir);
while ($thr->is_running()) {
	&PrintStatus;
}
&PrintStatus;
print "\n";
$thr->join;

if ($logging) {
	close (FLOG);
}

sub PrintStatus {
	my $txt = '';
	if ($bytes) {
		$txt = dig_split($delfsize).' bytes.';
	} else {
		my $size = $delfsize;
		foreach ('bytes','KB','MB','GB','TB','PB','EB') {
			if ($size < 1024) {
				$txt = sprintf("%.2f",$size)." $_" if $size < 1024;
				last;
			}
			$size /= 1024;
		}
	}
	print "\x1B[3F";
	printf ("Scaned %s files and %s dirs.\nDeleted %s files and %s dirs.\nReleased %s               \n", dig_split($totfcount), dig_split($totdcount), dig_split($delfcount), dig_split($deldcount), $txt);
	sleep(1);
}

sub InList {
	return 1 if /^$dir\/\$Recycle.Bin$/i;
	return 1 if /^$dir\/\$Windows\.~/i;
	return 1 if /^$dir\/MSOCache$/i;
	return 1 if /^$dir\/PerfLogs$/i;
	return 1 if /^$dir\/Recovery$/i;
	return 1 if /^$dir\/System Volume Information$/i;
	return 1 if /^$dir\/Windows\/SoftwareDistribution\/DataStore$/i;
	return 1 if /^$dir\/Windows\.old/i;
	return 1 if /\.bak$/i;
	return 1 if /\.temp$/i;
	return 1 if /\.tmp$/i;
	return 1 if /\.old$/i;
	return 1 if /\/~/;
	return 1 if /\/Cache$/i;
	return 1 if /\/Cookies$/i;
	return 1 if /\/Temp$/i;
	return 1 if /\/Temporary Internet Files/i;
	return 1 if /\/WER\/ReportArchive$/i;
	return 1 if /\/WER\/ReportQueue$/i;
	return 1 if /\/cache2$/i;
	return 1 if /\/found.\d\d\d$/i;
	return 1 if /\/hiberfil.sys$/i;
	return 1 if /\/pagefile.sys$/i;
	return 1 if /\/swapfile.sys$/i;

# Yandex Browser Cahce	
	return 1 if /\/YandexBrowser\/User Data\/Default\/Code Cache$/i;

	return 0;
}

sub RecurDel {
	my $dir = shift;
	opendir DIR, $dir or return;
	my @contents = map "$dir/$_", sort grep !/^\.\.?$/, readdir DIR;
	closedir DIR;
	foreach (@contents) {
		if (!-l && -d) {
			$totdcount++;
			&RecurDel($_);
			if ($simulate || rmdir ($_)) {
				$deldcount++;
				print FLOG "Delete dir: $_\n" if $logging;
			}
		} elsif (-l) {
			$totfcount++;
			if ($simulate || (unlink $_)) {
				$delfcount++;
				print FLOG "Delete link: $_\n" if $logging;
			}
		} else {
			$totfcount++;
			my $tempsize = -s $_;
			if (defined($tempsize)) {
				if ($simulate || (unlink $_)) {
					$delfcount++;
					$delfsize += $tempsize;
					print FLOG "Delete file: $_ \t(Size: $tempsize bytes)\n" if $logging;
				} else {
					print FLOG "WARNING!!! : file $_ not deleted!!!\n" if $logging;
				}
			} else {
				print FLOG "WARNING!!! : \$tempsize not defined!!!\n" if $logging;
			}
		}
	}
}

sub Recur {
	my $dir = shift;
	opendir DIR, $dir or return;
	my @contents = map "$dir/$_", sort grep !/^\.\.?$/, readdir DIR;
	closedir DIR;
	foreach (@contents) {
		if (!-l && -d) {
			$totdcount++;
			if (&InList($_)) {
				&RecurDel($_);
				$deldcount++ if ($simulate || rmdir ($_));
			} else {
				&Recur($_)
			};
		} else {
			$totfcount++;
			if (&InList($_)) {
				&RecurDel($_);
			}
		}
	}
}

sub dig_split {
	my $string = shift || return 0;
	my $length = shift || 3;
	my $sep = shift || ' ';
	$string  =~ s/(\d{1,$length}(?=(?:\d{$length})+(?!\d)))/$1$sep/g;
	return $string
}

__END__
=head1 NAME

clear-tmp - Clear Utility

=head1 SYNOPSIS

B<clear-tmp> [options]

B<clear-tmp> B<--help>

=head1 OPTIONS

=over 4

=item B<-b>, B<--bytes>

Print a file size in bytes.

=item B<--help>

Print a brief help message and exits.

=item B<-s>, B<--simulate>

Do not delete any objects. Only simulate.

=item B<-l>, B<--log>=I<filename>

Write a log to file with I<filename>.

=back

=head1 DESCRIPTION

B<This program> removes temp files and dirs created in Windows operation system.

=head1 AUTHOR

Ilya Tropin <tropin@ntechs.ru>


=cut
