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.logic.PrintErrorHandler;
import de.duehl.basics.system.starter.CmdStarter;

/**
 * Diese Klasse kann Zip-Dateien mit Hilfe des Programms 7zip entpacken.
 *
 * @version 1.01     2024-11-22
 * @author Christian Dühl
 */

public class UnzipWith7Zip {

    /** 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 die erzeugten Dateien (out und err) neben das Zip-File gelegt werden (default).
     * Anderenfalls muss man ein Verzeichnis angeben.
     */
    private boolean useZipFileDirForCreatedFiles;

    /**
     * Das Verzeichnis für die erzeugten Dateien (out und err). Nur relevant, falls
     * useZipFileDirForCreatedFiles false ist.
     */
    private String dirForCreatedFiles;

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

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

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

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

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

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

    /** Gibt an, dass die Datei entschlü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;
    }

    /**
     * Setzt das Verzeichnis für die erzeugten Dateien (out und err).
     *
     * Wird diese Methode nicht benutzt, so werden die Dateien neben das Zip-File gelegt.
     */
    public void setDirForCreatedFiles(String dirForCreatedFiles) {
        useZipFileDirForCreatedFiles = false;
        this.dirForCreatedFiles = dirForCreatedFiles;
    }

    /**
     * Führt das Entpacken des Ziparchivs durch.
     *
     * @param archiveFilename
     *            Name der zu entpackenden Archivdatei (endet auf zip oder 7z).
    * @param targetDirectory
    *            Das Verzeichnis in das entpackt wird.
     */
    public void unzip(String archiveFilename, String targetDirectory) {
        if (archiveFilename.contains(" ")) {
            throw new IllegalArgumentException("Der Dateiname des Archivs darf keine Leerzeichen "
                    + "beinhalten, weil sonst die Verwendung auf der Kommandozeile nicht wie "
                    + "gewünscht funktioniert.");
        }
        if (targetDirectory.contains(" ")) {
            throw new IllegalArgumentException("Das Zielverzeichnis darf keine Leerzeichen "
                    + "beinhalten, weil sonst die Verwendung auf der Kommandozeile nicht wie "
                    + "gewünscht funktioniert.");
        }

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

        command = pathTo7Zip + " x " + cypherCommandlinePart + archiveFilename + " -o"
                + targetDirectory;
        //System.out.println("command: '" + command + "'");

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

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

}
