package de.duehl.basics.io.zip;

/*
 * Copyright 2024 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

import java.util.ArrayList;
import java.util.List;

import de.duehl.basics.io.FileHelper;
import de.duehl.basics.io.zip.data.ZipArchive;
import de.duehl.basics.logic.PrintErrorHandler;
import de.duehl.basics.system.starter.CmdStarter;
import de.duehl.basics.text.Text;

/**
 * Diese Klasse kann Dateien mit Hilfe des Programms 7zip in ein Zip-Archiv verpacken.
 *
 * @version 1.01     2024-08-12
 * @author Christian Dühl
 */

public class ZipFilesWith7Zip {

    /** Default-Pfad zur ausführbaren 7zip-Datei. */
    static final String DEFAULT_PATH_TO_7_ZIP = "\\\\Cluster1\\Projekte1\\"
            + "HRTag\\HR_Strukt_HuP\\CD\\auslieferung\\bin\\7z\\7za.exe";

    /** Pfad zur ausführbaren 7zip-Datei. */
    private final String pathTo7Zip;

    /** Die Liste mit den Namen der beim Verpacken zusätzlich angelegten Dateien. */
    private List<String> createdFilenames;

    /** Gibt an, ob das Archiv verschlüsselt werden soll. */
    private boolean cypher;

    /** Das Password im Fall, dass verschlüsselt werden soll. */
    private String password;

    /**
     * Gibt an, ob ein *.7z-Archiv erstellt werden soll. Anderenfalls wird ein .zip-Archiv
     * erstellt.
     */
    private boolean create7zFile;

    /** Das ausgeführte Kommando. */
    private String command;

    /** Konstruktor, nutzt den Default-Pfad für 7zip. */
    public ZipFilesWith7Zip() {
        this(DEFAULT_PATH_TO_7_ZIP);
    }

    /**
     * Konstruktor.
     *
     * @param pathTo7Zip
     *            Pfad zur ausführbaren 7zip-Datei.
     */
    public ZipFilesWith7Zip(String pathTo7Zip) {
        this.pathTo7Zip = pathTo7Zip;

        createdFilenames = new ArrayList<>();
        cypher = false;
        create7zFile = false;
        command = "";
    }

    /** Gibt an, dass die Datei verschlüsselt werden soll. */
    public void cypher(String password) {
        if (password.contains(" ")) {
            throw new IllegalArgumentException("Das Passwort darf keine Leerzeichen beinhalten, "
                    + "weil sonst die Verwendung auf der Kommandozeile nicht wie gewünscht "
                    + "funktioniert.");
        }
        cypher = true;
        this.password = password;
    }

    /**
     * Gibt an, dass ein *.7z-Archiv erstellt werden soll. Anderenfalls wird ein .zip-Archiv
     * erstellt.
     */
    public void create7zFile() {
        create7zFile = true;
    }

    /**
     * Führt die Erstellung des Ziparchivs durch.
     *
     * @param zipArchive
     *            Name des Archivs und der zu verpackenden Dateien.
     */
    public void zip(ZipArchive zipArchive) {
        String archiveFilename = zipArchive.getArchiveFilename();
        createCommandLine(zipArchive);

        CmdStarter starter = new CmdStarter(new PrintErrorHandler());
        String dir = FileHelper.getDirName(archiveFilename);
        String bareZipName = FileHelper.getBareName(archiveFilename);
        String logBareName = "zip_" + FileHelper.exchangeExtension(bareZipName, ".txt");
        String errBareName = "zip_" + FileHelper.exchangeExtension(bareZipName, ".err");
        String log = FileHelper.concatPathes(dir, logBareName);
        String err = FileHelper.concatPathes(dir, errBareName);
        starter.runAndWait(command, log, err); // wartet wie der Name sagt darauf, dass
                                               // der Prozess fertig ist!
        createdFilenames.add(log);
        createdFilenames.add(err);
    }

    private void createCommandLine(ZipArchive zipArchive) {
        String targetZip;
        if (create7zFile) {
            targetZip = "-t7z ";
        }
        else {
            targetZip = "-tzip ";
        }

        String cypherCommandlinePart;
        if (cypher) {
            String mhe;
            if (create7zFile) {
                mhe = "-mhe ";
            }
            else {
                mhe = "";
            }
            cypherCommandlinePart = "-p" + password + " " + mhe;
        }
        else {
            cypherCommandlinePart = "";
        }

        String archiveFilename = zipArchive.getArchiveFilename();

        command = pathTo7Zip + " a " + cypherCommandlinePart + targetZip + archiveFilename
                + " " + Text.joinWithBlank(zipArchive.getFilesToZip());
        //System.out.println("command: '" + command + "'");
    }

    /** Getter für die Liste mit den Namen der beim Verpacken zusätzlich angelegten Dateien. */
    public List<String> getCreatedFilenames() {
        return createdFilenames;
    }

    /**
     * Getter für das ausgeführte Kommando.
     *
     * Achtung, bitte nur an den passenden Stellen einsetzen, kann Passworte im Klartext enthalten!
     */
    public String getCommand() {
        return command;
    }

}
