package de.nplusc.izc.tools.IOtools;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
/**
 *
 * @author LH
 */
import de.nplusc.izc.tools.baseTools.Tools;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import javax.swing.JProgressBar;

public class ZipFileHandler
{

    private ZipFile zipFile;
    String zfl = "";

    public ZipFileHandler(String zipFileLocation)
    {
        zfl = zipFileLocation;
        try
        {
            zipFile = new ZipFile(zipFileLocation);
        }
        catch (IOException e)
        {
            Tools.DebugHelperPrint("Unable to load zip file at location: " + zipFileLocation, true, "Toolkit.enableCoreDebug");
        }
    }

    /**
     * Entzippt die angegebene datei in das zielverzeichnis und gint den
     * Fortschritt in ner JProgressbar an (gedacht für UI-Handling
     *
     * @param outDir wohin gezippt werden soll
     * @param monitorBar fprs monitoring via GUI;kann auch null sein
     */
    public void extractAllToDiskWithMonitoringProgressbar(String outDir, JProgressBar monitorBar)
    {
        if (monitorBar == null)
        {
            monitorBar = new JProgressBar();//Dummy-Bar um NPXe zu stoppen
        }
        ArrayList<ZipEntry> data = new ArrayList<>();
        Enumeration<ZipEntry> tmp = (Enumeration<ZipEntry>) zipFile.entries();
        while (tmp.hasMoreElements())
        {
            data.add(tmp.nextElement());
        }
        long completeSize = 0;
        long bytesRead = 0;
        int PromlilleDone = 0;
        for (ZipEntry entry : data)
        {
            completeSize += entry.getSize();
        }
        Tools.DebugHelperPrint(completeSize+"", true, "Toolkit.enableCoreDebug");
        monitorBar.setMinimum(0);
        monitorBar.setMaximum(1000);//umrechnun gerfolgt automatisch
        monitorBar.setValue(0);
        for (ZipEntry entry : data)
        {
            if (entry.isDirectory())
            {
                continue;
            }

            //bytesRead +=entry.getSize();
            try
            {
                String path = entry.getName();//name->Pfad!!!!!
                File trg = new File(outDir + "\\" + path);
                FileTK.ensuredirExistence(trg);
                FileOutputStream fos = new FileOutputStream(trg);
                trg.createNewFile();
                Tools.DebugHelperPrint(path, true, "Toolkit.enableFinerDebug");

                BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry));
                // byte[] finalByteArray = new byte[(int)entrySize];

                int bufferSize = 2048;
                byte[] buffer = new byte[2048];
                int chunkSize = 0;
                int bytesSinceLastPbarUpdate = 0;
                while (true)
                {
                    //Read chunk to buffer
                    chunkSize = bis.read(buffer, 0, bufferSize); //read() returns the number of bytes read
                    if (chunkSize == -1)
                    {
                        //read() returns -1 if the end of the stream has been reached
                        break;
                    }

                    //Write that chunk to the finalByteArray
                    //System.arraycopy(src, srcPos, dest, destPos, length)
                    fos.write(buffer);//buffer, bufferSize, bytesRead);

                    bytesRead += chunkSize;
                    Tools.DebugHelperPrint(bytesRead+"", true, "Toolkit.enableFinerDebug");
                    bytesSinceLastPbarUpdate += chunkSize;
                    int oldPbarVal = monitorBar.getValue();
                    PromlilleDone = (int) (((float) bytesRead / (float) completeSize) * (float) 1000);
                    if (PromlilleDone > oldPbarVal && bytesSinceLastPbarUpdate > 100000)//maximales update alle 100 kb
                    {
                        Tools.DebugHelperPrint(PromlilleDone+"", true, "Toolkit.enableCoreDebug");
                        monitorBar.setValue(PromlilleDone);
                        bytesSinceLastPbarUpdate = 0;//Zähler resetten
                    }
                }
                monitorBar.setValue(PromlilleDone);//am ende jeder datei auch aktulisieren
                bytesSinceLastPbarUpdate = 0;//Zähler resetten
                bis.close(); //close BufferedInputStream
                fos.close();
            }
            catch (IOException e)
            {
                Tools.DebugHelperPrint("fickfotze", true, "Toolkit.enableCoreDebug");
                e.printStackTrace();
            }

        }
    }

    /**
     * entzippert eine Datei in einen String
     *
     * @param filePath Welche datei aus der Tsip
     * @return der inhalt
     */
    public String getStringEntry(String filePath)
    {
        byte[] tempdata = getEntry(filePath);
        String out = "";
        for (byte b : tempdata)
        {
            out += (char) b;
        }
        return out;
    }

    /**
     * entzippt Datei in ein Byte[] array
     *
     * @param filePath Pfad innerhalb der gezippten datei
     * @return Bytearray des inhalts
     *
     */
    public byte[] getEntry(String filePath)
    {
        ZipEntry entry = zipFile.getEntry(filePath);
        int entrySize = (int) entry.getSize();
        try
        {
            BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry));
            byte[] finalByteArray = new byte[entrySize];

            int bufferSize = 2048;
            byte[] buffer = new byte[2048];
            int chunkSize = 0;
            int bytesRead = 0;

            while (true)
            {
                //Read chunk to buffer
                chunkSize = bis.read(buffer, 0, bufferSize); //read() returns the number of bytes read
                if (chunkSize == -1)
                {
                    //read() returns -1 if the end of the stream has been reached
                    break;
                }

                //Write that chunk to the finalByteArray
                //System.arraycopy(src, srcPos, dest, destPos, length)
                System.arraycopy(buffer, 0, finalByteArray, bytesRead, chunkSize);

                bytesRead += chunkSize;
            }

            bis.close(); //close BufferedInputStream

            Tools.DebugHelperPrint("Entry size: " + finalByteArray.length, true, "Toolkit.enableCoreDebug");

            return finalByteArray;
        }
        catch (IOException e)
        {
            Tools.DebugHelperPrint("No zip entry found at: " + filePath, true, "Toolkit.enableCoreDebug");
            return null;
        }
    }

    public void CreateZipFile(String[] files, JProgressBar monitorBar)
    {
        if (monitorBar == null)
        {
            monitorBar = new JProgressBar();//Dummy-Bar um NPXe zu stoppen
        }
        monitorBar.setMinimum(0);
        monitorBar.setMaximum(1000);
        monitorBar.setValue(0);
        int read = 0;
        FileInputStream in;
        Long totalSize = 0L;//gesamtdatenmenge die gezippsert wird
        Long writtenSize = 0L;
        int readsinceLastRefresh = 0;
        int PromlilleDone = 0;
        byte[] data = new byte[1024];
        try
        {
            // Zip-Archiv mit Stream verbinden
            ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zfl));
            for (String file : files)
            {
                
                totalSize+= new File(file).length();//summiert die gesamtgröße die gezippt wird auf
            }
            // Archivierungs-Modus setzen
            out.setMethod(ZipOutputStream.DEFLATED);
            // Hinzufügen der einzelnen Einträge
            for (String file : files)
            {
                try
                {
                    // Eintrag für neue Datei anlegen
                    ZipEntry entry = new ZipEntry(file);
                    in = new FileInputStream(file);
                    // Neuer Eintrag dem Archiv hinzufügen
                    out.putNextEntry(entry);
                    // Hinzufügen der Daten zum neuen Eintrag
                    while ((read = in.read(data, 0, 1024)) != -1)
                    {
                        System.err.println(read);
                        out.write(data, 0, read);
                        writtenSize+=(long)read;
                        readsinceLastRefresh += (long)read;
                        int oldPbarVal = monitorBar.getValue();
                        PromlilleDone = (int) (((float) writtenSize / (float) totalSize) * (float) 1000);
                        if (PromlilleDone > oldPbarVal && readsinceLastRefresh > 100000)//maximales update alle 100 kb
                        {
                            Tools.DebugHelperPrint(PromlilleDone+"", true, "Toolkit.enableFinerDebug");
                            monitorBar.setValue(PromlilleDone);
                            readsinceLastRefresh = 0;//Zähler resetten
                        }
                    }
                    monitorBar.setValue(PromlilleDone);//am ende jeder datei auch aktulisieren
                    readsinceLastRefresh = 0;//Zähler resetten
                    out.closeEntry(); // Neuen Eintrag abschließen
                    in.close();
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
            out.close();
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
        }
    }
}
