#!/usr/bin/perl

use strict;
use warnings;

use File::Find;

sub array_eq
{

  my $aref = shift;

  my $bref = shift;

  #
  # If the number of elements are not the same in both arrays then the arrays cannot be the same - need 
  # to change code to use single exit statement - poor coding style
  #
  if (@$aref != @$bref)
  {
     return 0
  }
 
  #
  # compare size
  #
  for my $i (0..$#$aref)
  {
     #
     # compare values
     #
     return 0 unless $$aref[$i] eq $$bref[$i];
  }

  return 1;
}

sub build_string
{
  my @array;
  my $array_size;

  @array = shift;

  my $start_index = shift;

  my $separator = shift;

  my $array_size = @$array;

  my $built_string = "";
 
  print "passed in array".$array[$start_index]."\n";

  while ($start_index < $array_size +1)
  {
     $built_string = $built_string.$array[$start_index];

     $start_index = $start_index + 1;
  }

  return $built_string;
}

use File::Find;


my @files;
my $directories = 0;
my $files       = 0;
my $size        = 0;


find sub
{
        if (-d) {
                $directories++;
                return;
        }


        if (-f) {
                $files++;
                $size += -s;
                return;
        }


        print "$File::Find::name is not a directory or file\n";
}, "c:\\";

my $OpenFailCount;
my $CompareCount;

my $LineIndex;
my $OpenStatus;
my $NumberLines;
my $FileRead;
my $FileCount;
my $DirectoryCount;
my $DriveIndex;

my $PrimaryFileIndex;
my $SecondaryFileIndex;

my $SecondaryFile;
my $LineSize;
my $PrimaryFile = "";
my $ByteCount;

my $Date;
my $Seconds; 
my $Minutes;
my $Hours;
my $Day;
my $Month;
my $Year;

my $NumberOfFiles;
my $Directory = "";
my $FileName = "";
my $DirCommand = "";
my $ErrorMessage = "";
my $CurrentDrive = "";
my $DuplicateFileName = "";

my $OpenFailedFileName;

my @DirectoryList;
my @FileSize;
my @ActualFiles;
my @PrimaryLines;
my @SecondaryLines;
my @DriveFileList;
my @FileDeleted;
my @FileDirectory;

my $num_args;

#
# Read the list of drives to go through
#

my $num_args = @ARGV;

my $DRIVE_LIST_FILE = "DriveList.txt";

open DRIVE_LIST_FILE, $DRIVE_LIST_FILE or die "Cannot open drive list file\n";

my @DriveList = (<DRIVE_LIST_FILE>);

my $DriveListSize = scalar(@DriveList);

close DRIVE_LIST_FILE;

#
# Build the date string to be used in the file name for files created
#
($Seconds,$Minutes,$Hours,$Day,$Month,$Year) = (localtime)[0,1,2,3,4,5];
$Year = $Year + 1900;

$Date = sprintf("%02d",$Month)."-";
$Date = $Date.sprintf("%02d",$Day)."-";
$Date = $Date.sprintf("%04d",$Year)."-";
$Date = $Date.sprintf("%02d",$Hours)."_";
$Date = $Date.sprintf("%02d",$Minutes)."_";
$Date = $Date.sprintf("%02d",$Seconds);

$DuplicateFileName = "Duplicate_File_List_".$Date;
#print $DuplicateFileName."\n";

$OpenStatus = 1;

#
# Open the Duplicate file name
# 
open DUPLICATE_FILE_NAME, ">".$DuplicateFileName or $OpenStatus = 0;
if ($OpenStatus == 0)
{
   print "$!";
   print " ";
   die "Unable to open duplicate file name file\n";
}

#
# Create the open failed file list file
#
$OpenFailedFileName = "Open_Failed_File_List_".$Date;

$OpenStaus = 1;

open OPEN_FAILED_FILE_NAME, ">".$OpenFailedFileName or $OpenStatus = 0;
if ($OpenStatus == 0)
{
   print "$!";
   print " ";
   die "Unable to open failed to open failed file name file\n";
}

#
# Create the open failed file list file
#
$OpenFailedFileName = "Open_Failed_File_List_".$Date;
#print $OpenFailedFileName."\n";

$OpenFailedFileName = "Open_Failed_File_List_".$Date;

$OpenStaus = 1;

$OpenLogFileName = "Log_File_".$Date;

open OPEN_LOG_FILE_NAME, ">".$OpenLogFileName or $OpenStatus = 0;
if ($OpenStatus == 0)
{
   print "$!";
   print " ";
   die "Unable to open failed to open log file name file\n";
}

#
# Create the list of files that will be checked
#

#
# Loop through each drive to get a list of files
#
while ($DriveIndex < $DriveListSize)
{
    $CurrentDrive = $DriveList[$DriveIndex];

    chomp $CurrentDrive;

    #
    # First we do a dir command of all the files on the drive - this is not great code as it is dos based
    # This is the first place where I want to change the code to use the File:Find call once I know how to 
    # invoke it
    $DirCommand ="dir ".$CurrentDrive.":\\ /S";

    # print $DirCommand."\n";

    #
    # Obtain the list of files in the drive
    #
    @DriveFileList = `$DirCommand`;

    print "Directory done\n";

    #
    # Now append the files to the file list - The code here goes through the list of file names. If it is a       
    # directory then it is added to the directory array. If it is a file the only the name of the file is added
    # and an entry is made into the file_directory array to point to the directory array. The purpose is to save
    # by keeping the name of each directory once. Also the code will have to find the size of the file so it can
    # save time later on.
    # 
    # Once the File:Find approach is solved above then the code below can be changed to do a check if the 
    # non empty string is either a file or a directory and the code can be simplied
    #
    foreach $FileName (@DriveFileList)
    {
        chomp $FileName;

        #print $FileName."\n";

        my @ParsedLine = split /\s+/,$FileName;
       
        # shift @parse_line;

        $LineSize = scalar(@ParsedLine);    

        if ($LineSize > 0)
        {
            #print $ParsedLine[0]."\n";
            #print $LineSize."\n";

            #
            # Determine if this is a directory and if so add it to the
            # directory array and increment the index
            #
            if ($ParsedLine[1] eq "Directory")
            {
                print "Directory is ".$ParsedLine[3]."\n";
                #
                # We have a new directory - make sure we have all of it in case there 
                # are spaces 
                $Directory = build_string(\@ParsedLine,3,"\\");

                #
                # Now add it to the list
                #
                $DirectoryList[$DirectoryCount] = $Directory."\\";
                # chomp $DirectoryList[$DirectoryCount];
                print "Adding directory ".$DirectoryList[$DirectoryCount]."\n";
                $DirectoryCount =$DirectoryCount + 1;
            }

            if ($LineSize == 5 &&
                $ParsedLine[3] ne "<DIR>" &&
                $ParsedLine[2] ne "File(s)")
            {
                #
                # This is a file to add to the list
                #
                $ActualFiles[$FileCount] = build_string(\@ParsedLine,4,"");
                # chomp $ActualFiles[$FileCount];
                $FileDirectory[$FileCount]= $DirectoryCount;
                print "Adding file ".$ActualFiles[$FileCount]."\n";
                print "Adding Bytes ".$ParsedLine[3]."\n";
                $FileSize[$FileCount] = $ParsedLine[3];
 
                #
                # File is not deleted yet
                #
                $FileDeleted[$FileCount] = 0;
                $ByteCount = $ByteCount + $ParsedLine[3];
                $FileCount = $FileCount + 1;
            } 
        }
    }

    #
    # Point to the next drive
    #
    $DriveIndex = $DriveIndex + 1;
}

#$FileCount = scalar(@ActualFiles);    
#$DirectoryCount = scalar(@DirectoryList);

# 
# Loop through each file and determine if there is an identical file out there
#
while ($PrimaryFileIndex < $FileCount)
{ 
   $PrimaryFile = $DirectoryList[$FileDirectory[$PrimaryFileIndex] - 1].$ActualFiles[$PrimaryFileIndex];
   #$PrimaryFile = $DirectoryList[$FileDirectory[$PrimaryFileIndex]].$ActualFiles[$PrimaryFileIndex];
   print "Primary file #".$PrimaryFileIndex." ".$PrimaryFile."\n";
   
   $FileRead = 0;
   
   #
   # Has the file been deleted yet
   #
   if ($FileDeleted[$PrimaryFileIndex] == 0)
   {
      $OpenStatus = 1;

      open PRIMARY_FILE, $PrimaryFile or $OpenStatus = 0;
      if ($OpenStatus == 0)
      {
         $ErrorMessage = "Cannot open primary file ".$PrimaryFile." - ".$!."\n";
         print $ErrorMessage;

         $OpenFailCount = $OpenFailCount + 1;

         #
         # Write file name to unable to open file
         #
         print OPEN_FAILED_FILE_NAME $ErrorMessage;
      }
      else
      {
         # print "File opened successfully\n";

         #
         # Now loop through the list of files to find any possible matching files compared to the primary file
         #
         $SecondaryFileIndex = $PrimaryFileIndex + 1;
       
         while ($SecondaryFileIndex < $NumberOfFiles)    
         {
            if ($FileSize[$PrimaryFileIndex] eq
                $FileSize[$SecondaryFileIndex])
            {
               #
               # File size and file name are the same for primary file and secondary file so now we compare these
               # files
               #
               $SecondaryFile = $DirectoryList[$FileDirectory[$SecondaryFileIndex] - 1].$ActualFiles[$SecondaryFileIndex];
               print "Checking against ".$SecondaryFile."\n";
               #
               # Has the file been read
               #
               if ($FileRead == 0)
               {       
                  #
                  # Read the file
                  #
                  # $_ = join '',(<PRIMARY_FILE>);
                  @PrimaryLines = (<PRIMARY_FILE>);
                  $NumberLines = scalar(@PrimaryLines);   

                  $LineIndex = 0;

                  #
                  # Not sure if chomping is needed
                  #
                  while ($LineIndex < $NumberLines)
                  {
                     chomp $PrimaryLines[$LineIndex];
                     $LineIndex = $LineIndex + 1;
                  }
                
                  #
                  # Mark the file as read to avoid reading it again 
                  #
                  $FileRead = 1;
               }
              
               #
               # Open the secondary file
               # 
               $OpenStatus = 1;
               open SECONDARY_FILE, $SecondaryFile or $OpenStatus = 0;

               if ($OpenStatus == 0)
               {
                  print "Cannot open secondary file ".$SecondaryFile."\n";
               }
               else
               {
                  #
                  # Read the secondary file
                  #
                  $CompareCount = $CompareCount + 1;
                  print "opened ".$SecondaryFile."\n";
 
                  #
                  # Now read the file
                  #
                  @SecondaryLines = (<SECONDARY_FILE>);

                  $NumberLines = scalar(@SecondaryLines);   
        
                  $LineIndex = 0;

                  while ($LineIndex < $NumberLines)
                  {
                     chomp $SecondaryLines[$LineIndex];
                     $LineIndex = $LineIndex + 1;
                  }

                  #
                  # Now we compare the primary file to the secondary file
                  #
                  $compare_result = array_eq(@PrimaryLines,@SecondaryLines);
 
                  if ($compare_result == 1)
                  {
                      #
                      # Secondary File is the same so it is marked as deleted
                      #
                      $FileDeleted[$Secondary_Index] = 1;
                      
                      #
                      # Write the filemname to the file so it can be deleted later
                      #
                      print DUPLICATE_FILE_NAME, $SecondaryFile."\n" ;
                  }
               }
  
            close SECONDARY_FILE;        
   
         }
         $SecondaryFileIndex = $SecondaryFileIndex + 1;
      }

      close PRIMARY_FILE;
      }
`
      $PrimaryFileIndex = $PrimaryFileIndex + 1;
   }
}

print "There are ".$DirectoryCount." directories\n";
print "There are ".$FileCount." files to compare\n";
print "Byte count ".$ByteCount."\n";
print "Unable to open ".$OpenFailCount." Files\n";
print "Compare Count ".$CompareCount."\n";

close OPEN_FAILED_FILE_NAME;
close LOG_FILE_NAME;
close DUPLICATE_FILE_NAME;