/*
 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import java.util.Base64;
import java.util.jar.JarOutputStream;

public class Checksum {

    private static final int BUFFER_SIZE = 8192;

    private static String getFileChecksum(File f, String algorithm)
        throws NoSuchAlgorithmException, IOException {
        BufferedInputStream bis = null;
        if (algorithm == null) {
            algorithm = "SHA-256";
        }
        try {
            MessageDigest digest = MessageDigest.getInstance(algorithm);
            bis = new BufferedInputStream(new FileInputStream(f));
            byte [] buffer = new byte[BUFFER_SIZE];
            int n;
            int left = buffer.length;
            while ((left > 0) &&
                   ((n = bis.read(buffer, 0, buffer.length)) != -1)) {
                digest.update(buffer, 0, n);
                left -= n;
            }
            return Base64.getMimeEncoder().encodeToString(digest.digest());
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static File decompressTmpFile(File inFile) throws IOException {
        File outFile = File.createTempFile("Temp", ".jar");
        BufferedInputStream bis = null;
        OutputStream out = null;
        JarOutputStream jarout = null;
        ZipInputStream zin = null;
        try {
            out = new BufferedOutputStream(new FileOutputStream(outFile));
            bis = new BufferedInputStream(new FileInputStream(inFile));
            jarout = new JarOutputStream(out);
            zin = new ZipInputStream(bis);
            decompressWrite(zin, jarout);
            return outFile;
        } finally {
            if (zin != null) {
                zin.close();
            } else if (bis != null) {
                bis.close();
            }
            if (jarout != null) {
                jarout.close();
            } else if (out != null) {
                out.close();
            }
        }
    }

    private static void decompressWrite(ZipInputStream in, ZipOutputStream out)
            throws IOException {

        byte[] buffer = new byte[BUFFER_SIZE];
        ZipEntry entry = in.getNextEntry();
        while (entry != null) {
            ZipEntry outEntry = (ZipEntry)entry.clone();
            outEntry.setCompressedSize(-1);
            out.putNextEntry(outEntry);

            int read = 0;

            while((read = in.read(buffer, 0, buffer.length)) != -1) {
                out.write(buffer, 0, read);
            }

            out.closeEntry();
            entry = in.getNextEntry();
        }
        out.flush();
    }


    public static void main(String [] argv) {
        if (argv.length !=1) {
            System.out.println("Usage: Checksum <file>");
        }
        try {
            File originalFile = new File(argv[0]);
            File tmpFile = decompressTmpFile(originalFile);
            if (tmpFile != null) {
                String checksum1 = getFileChecksum(originalFile, "SHA-256");
                System.out.println("checksum for originalFile: " +
                                    originalFile + " is:\n" + checksum1);
                String checksum2 = getFileChecksum(tmpFile, "SHA-256");
                System.out.println("checksum for compression level 0 file: " +
                                    tmpFile + " is:\n" + checksum2);
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

}
