#!/usr/bin/perl -w

my $VERSION;
$VERSION="2.1";


use strict;
use DBI;
use Getopt::Long;
use File::Path;
use fontlinge::Filebasics;
use fontlinge::Fontling;

no utf8;
use bytes;

my $sth;
my $dbh;
my $row;
#my $last;
my $cmd;
my $mode="";		# DUPE		: find duplicate fonts /folders
			# REUNION	: find folders to be completet from same but more complete
my $filesystem_was_changed='no';
my $mode1;
my $mode2;
my $really=0;
#my $view_working=1;
my $help;
my $dupecount=0;
my $verbose=0;

GetOptions (	'dupe' 		=> \$mode1,
		'reunion' 	=> \$mode2,
		'really' 	=> \$really,
		'verbose|v'=> \$verbose,
		'help'	 	=> \$help
) || exit -1 ;




$mode='';
if($help) {
	&usage;
	exit;
}

my %config = fontlinge_Get_Config();
$dbh = fontlinge_Open_Database (
	$config{'username'},
	$config{'password'},
	$config{'mysqlserver'},
	$config{'database'}
);




if($mode1) {
	$mode.='DUPE';
	if ($0=~/fontlinge_reunion$/gis) {
		print "Warning: Option --dupe overwrote filename-based operation.\n";
	}
}
if($mode2) {
	$mode.='REUNION';
	if ($0=~/fontlinge_dupe$/gis) {
		print "Warning: Option --reunion overwrote filename-based operation.\n";
	}
}

if ($mode eq '') {
	if ($0=~/fontlinge_reunion$/gis) {	$mode='REUNION';	}
	if ($0=~/fontlinge_dupe$/gis) {	$mode='DUPE';	}
}

if ( ($mode ne 'DUPE') && ($mode ne 'REUNION') ) {
	print "\nNothing to do: $mode\n";
	&usage;
	exit;
}



#$last={};
#$last->{font_path}		="";
#$last->{font_filetype}	="";
#$last->{font_name}		="";
#
#$sth = $dbh->prepare("SELECT font_id,font_path,font_name,font_datatype,font_filetype,font_kategorie,font_complete FROM fonts ORDER BY font_name,font_datatype");
#$sth->execute();
#while($row = $sth->fetchrow_hashref) {
#	if(	($last->{font_name} 		ne $row->{font_name}			) ||
#			($last->{font_datatype}	ne $row->{font_datatype}	) 
#			 )		 {
#			&dupecheck($row->{font_id});
#	}
#	$last=$row;
#}
#$sth->finish;


my %fontcount;
my %fontcount_id;

my $sth_type;
$sth_type = $dbh->prepare("SELECT DISTINCT font_datatype FROM fonts");
$sth_type->execute();
# walk through db fonttype by fonttype, since a ttf is never a dupe of an ps, i.e.
while( my $type_row = $sth_type->fetchrow_hashref) {
	%fontcount=();
	%fontcount_id=();
	$sth = $dbh->prepare("SELECT font_name, font_id FROM fonts WHERE BINARY font_datatype=?");
	$sth->execute($type_row->{"font_datatype"});
	while($row = $sth->fetchrow_hashref) {
		$fontcount{ $row->{"font_name"}	}++;
		$fontcount_id{ $row->{"font_name"}	} = $row->{"font_id"};
	}
	$sth->finish;

	# check the font that occur more than twice
	foreach my $fontname ( keys %fontcount ) {
		if ( $fontcount{ $fontname } > 1 ) {
			dupecheck( $fontcount_id{ $fontname } );
		}
	}

}
$sth_type->finish;



fontlinge_Close_Database($dbh);

if ( $mode eq 'DUPE' ) {
	&dupestatistics;
}

sub dupecheck {
	my $sth2;
	my $id=shift(@_);
	my @row;
	my $count=0;
	my $i;
	my $t;
	my $delresult;
	
	$sth2 = $dbh->prepare("SELECT font_id,font_path,font_name,font_datatype,font_filetype,font_kategorie,font_complete FROM fonts WHERE font_id=$id");
	$sth2->execute();
	$row = $sth2->fetchrow_hashref;
#	print "\nsearching dupes of ".$row->{'font_path'}."\n";
	my $tmp=
		'SELECT font_id,font_path,font_name,font_datatype,font_filetype,font_kategorie,font_complete FROM fonts WHERE '.
		'    BINARY font_name		 = "'.quotemeta($row->{font_name}).		'" '.
		'AND font_datatype = "'.quotemeta($row->{font_datatype}).'" '.
		' ORDER BY font_id DESC';
	$sth2 = $dbh->prepare($tmp);
	if( $sth2->execute() > 1) {

	  if($mode eq 'DUPE') {
		while($row[$count] = $sth2->fetchrow_hashref) {
			$row[$count]->{delete}='no';
			$count++;
		}
		for ($i=0 ; $i<$count-1 ; $i++) {
			for ($t=$i+1 ; $t<$count ; $t++) {
				if ( ($row[$i]->{delete} eq 'no') && ($row[$t]->{delete} eq 'no') ) {
					if( ! fontlinge_Diff($row[$i]->{font_path},$row[$t]->{font_path}) ) {
						$row[$i]->{delete}='yes';
					}
				}
			}
		}


		for ($i=0 ; $i<$count ; $i++) {
			&table($row[$i]->{delete} eq "yes"?'DEL':'keep',4);
			&table($row[$i]->{font_path},70);
			&table($row[$i]->{font_name},16);
			
#			if ( $really eq '1' ) {
				if ($row[$i]->{delete} eq "yes") {
					if ( -d $row[$i]->{font_path} ) {
						$delresult=my_rmtree($row[$i]->{font_path}, 0, 0);
						$delresult=$delresult>0?'done':'ERROR';
					} elsif ( -f $row[$i]->{font_path} ) {
						$delresult=my_unlink($row[$i]->{font_path});
						$delresult=$delresult>0?'done':'ERROR';
					} else {
						$delresult="NoFile!";
					}
				} else {
			  		$delresult='keep';
				}
#			} else {
#				$delresult='simulate';
#			}
			&table($delresult,8);
			&linebreak();
		}
		print_( "\n" );
	  } elsif($mode eq 'REUNION') {
	   $count=0;
		while($row[$count] = $sth2->fetchrow_hashref) {
			$count++;
		}
		for ($i=0 ; $i<$count-1 ; $i++) {
			for ($t=$i+1 ; $t<$count ; $t++) {
				if ( $row[$i]->{font_datatype} eq $row[$t]->{font_datatype} ) {
					if ( $row[$i]->{font_filetype} eq 'multi' ) {
						print_( "CHECKING $row[$i]->{font_path}\t$row[$t]->{font_path}\n");
						foldercompare($row[$i]->{font_path},$row[$t]->{font_path});
					}
				}
			}
		}
		if ($filesystem_was_changed ne 'no') {
			print "\nFilesystem was changed.\n";
		    print "Please rebuild your database (fontlinge_base --dbinsert).\n";
		}
	  }
	}
}
 

sub foldercompare {
	my @folder=@_;
	my $ident='yes';
	my $i;
	my $t;
	my @files;
	my $d0; my $d1;
	
	print_( "$folder[0]\n$folder[1]\n" );

	foreach $t (0,1) {
		if ($t==0) 	{$d0=$folder[0];$d1=$folder[1];}
		else			{$d1=$folder[0];$d0=$folder[1];}
		opendir(DIR, $d0) || die "can't opendir $d0: $!";
		@files = readdir(DIR);
		closedir DIR;
		for($i=0 ; $i<(@files) ; $i++) {
			if (	($files[$i] ne '.')		&&
					($files[$i] ne '..')		&&
					(-e "$d1$files[$i]")		
				) {
					if( fontlinge_Diff_File("$d0$files[$i]","$d1$files[$i]")) {
					$ident='no';
					print_( "\t$d0$files[$i]\n\t$d1$files[$i] DIFFER\n" );
				}
			}
		}
	}

	if ($ident eq 'yes') {
		print_( "can" );
	} else {
		print_( 'can NOT' );
	}
	print_( " be reunioned\n" );
	if ($ident eq 'yes') {
		&folderreunion($folder[0],$folder[1]);
	}
	print_( "\n" );
}



sub folderreunion {
	my @folder=@_;
	my $i;
	my $t;
	my @files;
	my $d0; my $d1;
	
	foreach $t (0,1) {
		if ($t==0) 	{$d0=$folder[0];$d1=$folder[1];}
		else			{$d1=$folder[0];$d0=$folder[1];}
		opendir(DIR, $d0) || die "can't opendir $d0: $!";
		@files = readdir(DIR);
		closedir DIR;
		for($i=0 ; $i<(@files) ; $i++) {
			if (	($files[$i] ne '.')		&&
					($files[$i] ne '..')		&&
					(! -e "$d1$files[$i]")		
				) {
				$cmd= "cp -a '$d0$files[$i]' '$d1$files[$i]'";
				$filesystem_was_changed='yes';
#				print_( "$cmd\n" );
				$cmd=`$cmd`;
			}
		}
	}
}

sub usage {
	print << 'END_OF_HELP';

fontlinge_dupe --[reunion|dupe] [--really] [--verbose]

--verbose   Be verbose
--really    Just simulate delete if NOT given
            (for  --dupe only)

You can use the commands fontlinge_dupe or fontlinge_reunion
instead of giving a mode.

END_OF_HELP
}


sub table {
	my $text=shift(@_);
	my $len=shift(@_);
	my $space=" " x $len;
	$space=substr($text.$space,0,$len);
	print_( "$space | " );
}

sub linebreak {
	print_( "\n" );
}


sub my_rmtree {
	my $file=shift;
	$dupecount++;
	if ($really eq '1') {
		return rmtree($file, 0, 0);
	} else {
		return 1;
	}
}

sub my_unlink {
	my $file=shift;
	$dupecount++;
	if ($really eq '1') {
		return unlink($file);
	} else {
		return 1;
	}
}





sub dupestatistics {
	my $dupestat="";

	if ($dupecount == 0) {
		$dupestat .= "No duplicates";
	} elsif ($dupecount == 1) {
		$dupestat .= "1 duplicate";
	} else {
		$dupestat .= "$dupecount duplicates";
	}
	
	if ($dupecount > 0 && $really ne '1') {
		$dupestat .= " found, but not deleted (--really not given).\n";
	} elsif ($dupecount > 0 && $really eq '1') {
		$dupestat .= " deleted.\n";
	} else {
		$dupestat .= " found.\n";
	}

	if ($really eq '1' && $dupecount > 0) {
		$dupestat .= "Please rebuild your database (fontlinge_base --dbinsert).\n";
	} else {
		$dupestat .= "No need to rebuild the database.\n";
	}
	print ( $dupestat );
}

sub print_ {
	if ($verbose) {
		print @_;
	}
}
