package LatexIndent::BackUpFileProcedure;

#	This program is free software: you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation, either version 3 of the License, or
#	(at your option) any later version.
#
#	This program is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	GNU General Public License for more details.
#
#	See http://www.gnu.org/licenses/.
#
#	Chris Hughes, 2017-2025
#
#	For all communication, please visit: https://github.com/cmhughes/latexindent.pl
use strict;
use warnings;
use LatexIndent::GetYamlSettings qw/%mainSettings/;
use LatexIndent::Switches        qw/%switches/;
use LatexIndent::LogFile         qw/$logger/;
use File::Basename;    # to get the filename and directory path
use File::Copy;        # to copy the original file to backup (if overwrite option set)
use Exporter qw/import/;
use Encode   qw/decode/;
our @EXPORT_OK = qw/create_back_up_file check_if_different/;

use LatexIndent::UTF8CmdLineArgsFileOperation
    qw/copy_with_encode exist_with_encode open_with_encode  zero_with_encode read_yaml_with_encode/;
use utf8;

# copy main file to a backup in the case of the overwrite switch being active

sub create_back_up_file {
    my $self = shift;

    return unless ( ${$self}{overwrite} );

    # if we want to overwrite the current file create a backup first
    $logger->info("*Backup procedure (-w flag active):");

    my $fileName = ${$self}{fileName};

    # grab the file extension preferences
    my %fileExtensionPreference = %{ $mainSettings{fileExtensionPreference} };

    # sort the file extensions by preference
    my @fileExtensions
        = sort { $fileExtensionPreference{$a} <=> $fileExtensionPreference{$b} } keys(%fileExtensionPreference);

    # backup file name is the base name
    my $backupFileNoExt = basename( ${$self}{fileName}, @fileExtensions );

    # add the user's backup directory to the backup path
    $backupFileNoExt = "${$self}{cruftDirectory}/$backupFileNoExt";
    $backupFileNoExt =~ s/\\/\//g;
    $backupFileNoExt =~ s/\/{2,}/\//g;
    if ( $^O eq 'MSWin32' ) {
        $backupFileNoExt =~ s/\//\\/g;
    }

    # local variables, determined from the YAML settings
    my $onlyOneBackUp       = $mainSettings{onlyOneBackUp};
    my $maxNumberOfBackUps  = $mainSettings{maxNumberOfBackUps};
    my $cycleThroughBackUps = $mainSettings{cycleThroughBackUps};
    my $backupExtension     = $mainSettings{backupExtension};

    # if both onlyOneBackUp and maxNumberOfBackUps are set, then we have a conflict
    # err on the side of caution and turn off onlyOneBackUp
    if ( $onlyOneBackUp and $maxNumberOfBackUps >= 1 ) {
        $logger->warn("*onlyOneBackUp=$onlyOneBackUp and maxNumberOfBackUps=$maxNumberOfBackUps");
        $logger->warn("setting onlyOneBackUp=0 which will allow you to reach $maxNumberOfBackUps backups");
        $onlyOneBackUp = 0;
    }

    # determine the backup file name by adjoining backupExtension
    my $backupFile = $backupFileNoExt . $backupExtension;

    # if onlyOneBackUp is *not* set, add a number to the backup file name
    if ( !$onlyOneBackUp ) {
        my $backupCounter = 0;

        # if the file already exists, increment the number until either
        # the file does not exist, or you reach the maximal number of backups
        while ( exist_with_encode( $backupFile . $backupCounter ) and $backupCounter != ( $maxNumberOfBackUps - 1 ) ) {
            $logger->info("$backupFile$backupCounter already exists, incrementing by 1 (see maxNumberOfBackUps)");
            $backupCounter++;
        }
        $backupFile .= $backupCounter;
    }

    # if the backup file already exists, output some information in the log file
    # and proceed to cycleThroughBackUps if the latter is set
    if ( exist_with_encode($backupFile) ) {
        if ($onlyOneBackUp) {
            $logger->info("$backupFile will be overwritten (see onlyOneBackUp)");
        }
        else {
            $logger->info("$backupFile will be overwritten (maxNumberOfBackUps reached, see maxNumberOfBackUps)");

            # some users may wish to cycle through backup files, e.g.:
            #    copy myfile.bak1 to myfile.bak0
            #    copy myfile.bak2 to myfile.bak1
            #    copy myfile.bak3 to myfile.bak2
            #
            #    current backup is stored in myfile.bak4
            if ($cycleThroughBackUps) {
                $logger->info("cycleThroughBackUps detected (see cycleThroughBackUps)");
                my $oldBackupFile;
                my $newBackupFile;
                for ( my $i = 1; $i < $maxNumberOfBackUps; $i++ ) {
                    $oldBackupFile = $backupFileNoExt . $backupExtension . $i;
                    $newBackupFile = $backupFileNoExt . $backupExtension . ( $i - 1 );

                    # check that the oldBackupFile exists
                    if ( exist_with_encode($oldBackupFile) ) {
                        $logger->info("Copying $oldBackupFile to $newBackupFile...");
                        if ( !( copy_with_encode( $oldBackupFile, $newBackupFile ) ) ) {
                            $logger->fatal("*Could not write to backup file $newBackupFile. Please check permissions.");
                            $logger->fatal("Exiting, no indentation done.");
                            $self->output_logfile();
                            exit(5);
                        }
                    }
                }
            }
        }
    }

    # output these lines to the log file
    $logger->info("Backing up $fileName to $backupFile...");
    $logger->info("$fileName will be overwritten after indentation");
    if ( !( copy_with_encode( $fileName, $backupFile ) ) ) {
        $logger->fatal("*Could not write to backup file $backupFile. Please check permissions.");
        $logger->fatal("Exiting, no indentation done.");
        $self->output_logfile();
        exit(5);
    }
}

sub check_if_different {
    my $self = shift;

    if ( ${$self}{originalBody} eq ${$self}{body} ) {
        $logger->info("*-wd switch active");
        $logger->info("Original body matches indented body, NOT overwriting, no backup files created");
        return;
    }

    # otherwise, continue
    $logger->info("*-wd switch active");
    $logger->info("Original body is *different* from indented body");
    $logger->info("activating overwrite switch, -w");
    ${$self}{overwrite} = 1;
    $self->create_back_up_file;
}

1;
