package de.duehl.zipwithzip4j.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.io.File;
import java.io.IOException;

import de.duehl.basics.io.FileHelper;
import de.duehl.basics.io.zip.data.ZipArchive;

import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.EncryptionMethod;

/**
 * Diese Klasse kann Dateien und Verzeichnisse in ein Zip-Archiv verpacken.
 *
 * @version 1.01     2024-11-26
 * @author Christian Dühl
 */

public class ZipWithZip4J {

    /** Der Name des zu erstellenden Archivs und die zu verpackenden Dateien. */
    private final ZipArchive zipArchive;

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

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

    /** Die Parameter zum Verpacken der Dateien und Verzeichnisse. */
    private ZipParameters zipParameters;

    /**
     * Konstruktor.
     *
     * @param zipArchive
     *            Der Name des zu erstellenden Archivs und die zu verpackenden Dateien.
     */
    public ZipWithZip4J(ZipArchive zipArchive) {
        this.zipArchive = zipArchive;
    }

    /** Gibt an, dass die Datei verschlüsselt werden soll. */
    public void cypher(String password) {
        cypher = true;
        this.password = password;
    }

    /** Führt die Erstellung des Archivs durch. */
    public void zip() {
        if (cypher) {
            zipWithPassword();
        }
        else {
            zipWithoutPassword();
        }
    }

    private void zipWithPassword() {
        String zipFilename = zipArchive.getArchiveFilename();

        zipParameters = new ZipParameters();
        zipParameters.setEncryptFiles(true);
        zipParameters.setEncryptionMethod(EncryptionMethod.AES);
        // Below line is optional. AES 256 is used by default. You can override it to use AES 128.
        // AES 192 is supported only for extracting.
        zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256);

        try (ZipFile zip = new ZipFile(zipFilename, password.toCharArray())) {
            addToZip(zip);
        }
        catch (ZipException exception) {
            throw new RuntimeException(exception);
        }
        catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }

    private void zipWithoutPassword() {
        zipParameters = new ZipParameters();
        zipParameters.setEncryptFiles(false);

        String zipFilename = zipArchive.getArchiveFilename();

        try (ZipFile zip = new ZipFile(zipFilename)) {
            addToZip(zip);
        }
        catch (ZipException exception) {
            throw new RuntimeException(exception);
        }
        catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }

    private void addToZip(ZipFile zip) throws ZipException {
        for (String toZip : zipArchive.getFilesToZip()) {
            if (FileHelper.isDirectory(toZip)) {
                zip.addFolder(new File(toZip), zipParameters);
            }
            else if (FileHelper.isFile(toZip)) {
                zip.addFile(new File(toZip), zipParameters);
            }
            else {
                throw new RuntimeException("Der Eintrag in die Liste der zu verpackenden Dateien "
                        + "und Verzeichnisse ist weder als Datei noch als Verzeichnis vorhanden."
                        + "\n"
                        + "\t" + "toZip = " + toZip + "\n");
            }
        }
    }

}
