/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package eu.dnetlib.espas.sos.client;

import edu.emory.mathcs.backport.java.util.Arrays;
import eu.dnetlib.espas.sos.client.utils.QuotaMonitor;
import eu.dnetlib.espas.sos.client.utils.RequestQuotaException;
import eu.dnetlib.espas.sos.client.utils.SOSRequestStatusListenerIF;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.filefilter.FileFileFilter;

/**
 *
 * @author georgeathanasopoulos
 */
public class SOSSweZipHandler extends SOSTransformationHandler{
    public static final String DEFAULT_NAME = "swe_bundle";
    private int COMPRESSION_LEVEL=8;

    public SOSSweZipHandler(String requestId, String userId, String transformationName, InputStream transformationRulesStream, SOSRequestStatusListenerIF statusListener, QuotaMonitor quotaMonitor) {
        super(requestId, userId, transformationName, new ByteArrayInputStream(new byte[]{}), statusListener, quotaMonitor);
    }
    
    @Override
    protected void transform(InputStream contentStream, InputStream transformationRulesStream) throws TransformerConfigurationException, TransformerException, IOException, RequestQuotaException {
        File resultBundle = this.quotaMonitor.getDmSpaceUtils().getRequestResultSWEBundle(requestId);
        File bundlePathRoot = this.quotaMonitor.getDmSpaceUtils().getRequestResultSWEArchiveRoot(requestId);
        writeBundleToOutputStream(bundlePathRoot,resultBundle);
        
    }
    
    /** Constructs the zip bundle out of the temporarily downloaded files and streams the produced zip bundle to the requestor.
     */
    private void writeBundleToOutputStream(File bundlePath, File outputZip) throws FileNotFoundException, IOException {
//        first zip the downloaded files
        List<File> totalListOfFiles = getSubFiles(bundlePath);
        outputZip.setWritable(true);
        ZipOutputStream bundleFileOutStream = new ZipOutputStream(new FileOutputStream(outputZip));
        bundleFileOutStream.setMethod(ZipOutputStream.DEFLATED);

        bundleFileOutStream.setLevel(COMPRESSION_LEVEL);
        for (File listFile : totalListOfFiles) {
            try {
//                append entries in the bundle zip; do not add the contents of the bundle in the bundle
                if (!listFile.getCanonicalPath().equalsIgnoreCase(bundlePath.getCanonicalPath())) {
//                    reletivise the file paths
                    bundleFileOutStream.putNextEntry(new ZipEntry(listFile.getCanonicalPath().replace(bundlePath.getParentFile().getCanonicalPath()+File.separator, "./")));
                    InputStream listFileStream = new FileInputStream(listFile);
//                    transfer byte data from files to the zip
                    IOUtils.copy(listFileStream, bundleFileOutStream);
                    bundleFileOutStream.closeEntry();
                    listFileStream.close();
//                    listFile.delete();
                }
            } catch (IOException ex) {
                _logger.error(null, ex);
                continue;
            }
        }
        
        bundleFileOutStream.finish();
        bundleFileOutStream.close();
}
 /** Utility method used for retrieving the list of files stored in a file system tree starting from a given root point.
     */
    protected List<File> getSubFiles(File path) {
        List<File> subDirs = Arrays.asList(path.listFiles((FileFilter) DirectoryFileFilter.DIRECTORY));
        LinkedList<File> totalFiles = new LinkedList<File>(Arrays.asList(path.listFiles((FileFilter) FileFileFilter.FILE)));
        for (File subDir : subDirs)
            totalFiles.addAll(getSubFiles(subDir));
        return totalFiles;
    }
       
    
}
