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.system.starter.ProgramStarter;
import de.duehl.basics.text.Text;

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

public class ZipFilesWith7ZipDirectProgramStart {

    private static final boolean DEBUG = false;


    /** Das 7zip-Executable mit Pfad. */
    private final String sevenZipExecutable;

    /** 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;

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

    /**
     * Konstruktor.
     *
     * @param sevenZipExecutable
     *            Das 7zip-Executable mit Pfad.
     */
    public ZipFilesWith7ZipDirectProgramStart(String pathTo7Zip) {
        this.sevenZipExecutable = pathTo7Zip;

        createdFilenames = new ArrayList<>();
        cypher = false;
        create7zFile = false;
        say("sevenZipExecutable = " + sevenZipExecutable);
    }

    /** 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();
        List<String> parameters = createParametersString(zipArchive);

        String bareZipName = FileHelper.getBareName(archiveFilename);
        String logBareFilename = "zip_" + FileHelper.exchangeExtension(bareZipName, ".txt");
        String errBareFilename = "zip_" + FileHelper.exchangeExtension(bareZipName, ".err");
        String dir = FileHelper.getDirName(archiveFilename);
        String logFilename = FileHelper.concatPathes(dir, logBareFilename);
        String errorLogfilename = FileHelper.concatPathes(dir, errBareFilename);

        say("starte Programm ... ");
        ProgramStarter starter = new ProgramStarter(sevenZipExecutable, parameters,
                logFilename, errorLogfilename);
        starter.runAndWait(); // wartet wie der Name sagt darauf, dass
                              // der Prozess fertig ist!
        say("Programm beendet");

        createdFilenames.add(logFilename);
        createdFilenames.add(errorLogfilename);
    }

    private List<String> createParametersString(ZipArchive zipArchive) {
        String archiveFilename = zipArchive.getArchiveFilename();
        List<String> parameters = new ArrayList<>();

        parameters.add("a");

        if (cypher) {
            if (create7zFile) {
                parameters.add("-mhe");
            }
            parameters.add("-p" + password);
        }

        if (create7zFile) {
            parameters.add("-t7z");
        }
        else {
            parameters.add("-tzip");
        }

        if (archiveFilename.contains(" ")) {
            parameters.add("\"" + archiveFilename + "\"");
        }
        else {
            parameters.add(archiveFilename);
        }

        for (String toZip : zipArchive.getFilesToZip()) {
            if (toZip.contains(" ")) {
                parameters.add("\"" + toZip + "\"");
            }
            else {
                parameters.add(toZip);
            }
        }

        say("parameters = " + parameters);
        return parameters;
    }

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

    private static void say(String message) {
        if (DEBUG) {
            Text.say(message);
        }
    }

}
