
import java.awt.*;
import java.awt.event.ActionEvent;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.util.Formatter;
import java.util.logging.Level;
import java.util.logging.Logger;
import ij.plugin.filter.ExtendedPlugInFilter;
import ij.plugin.filter.PlugInFilterRunner;
import ij.*;
import ij.gui.GenericDialog;
import ij.gui.DialogListener;
import ij.process.*;
import java.awt.event.ActionListener;
import java.io.*;
import java.util.*;

public class Plugin_Hash implements ExtendedPlugInFilter, DialogListener, ActionListener {

    private final static String[] TYPES = new String[] {"MD5", "SHA-1", "Entrambi"};
    private final static int MD5=0, SHA1=1, Entrambi=2;
    private final static int[] taskLists = new int[]{MD5, SHA1, Entrambi};
    private static int type = MD5;
    private int flags = DOES_ALL|CONVERT_TO_FLOAT|SNAPSHOT|SUPPORTS_MASKING|KEEP_PREVIEW|PARALLELIZE_STACKS;
    private int impType;
    private int nPasses = 1;
    private int pass;
    private Button pulsanteReport;
    private GenericDialog gd;
    private Panel pannello;
    private static String path;
    private static String directory;
    private static String nomeFile;
    private static String hashSHA1;
    private static String hashMD5;

    // Called by ImageJ for each stack slice (when processing a full stack); for RGB image also called once for each color.
    @Override
    public void run(ImageProcessor ip){

    }

    // Called by ImageJ after setup.
        @Override
    public int showDialog(ImagePlus imp, String command, PlugInFilterRunner pfr) {
        try {
            path = imp.getOriginalFileInfo().directory;
            directory = path;
            nomeFile = imp.getTitle();
            path += nomeFile;
            impType = imp.getType();
            int digits = (impType == ImagePlus.GRAY32) ? 2 : 0;
            gd = new GenericDialog(command+"...");
            gd.addDialogListener(this);
            hashMD5 = calcolaMD5(path);
            hashSHA1 = calcolaSHA1(path);
            gd.addMessage("MD5: " + hashMD5);
            gd.addMessage("SHA-1: " + hashSHA1);
            gd.addMessage("");
            gd.addChoice("Crea Report di", TYPES, TYPES[type]);
            pannello = new Panel();
            pulsanteReport = new Button("Genera Report");
            pulsanteReport.addActionListener(this);
            pannello.add(pulsanteReport);
            gd.addPanel(pannello);
            gd.showDialog();
            if (gd.wasCanceled()) return DONE;
            IJ.register(this.getClass());
        } catch (Exception ex) {
            Logger.getLogger(Plugin_Hash.class.getName()).log(Level.SEVERE, null, ex);
        }
        return IJ.setupDialog(imp, flags);
    }



    //Calculate report
    public void getReport() {
        try {
			type = gd.getNextChoiceIndex();
			String hashCode = "";
            String orario = getData();
            String titoloReport = "<h1>Plugin Hashcode</h1>";
            String file ="";
            String dettagli = "<h4><a name=\"ring1\">Dettagli</a><span style=\"font-style: italic;font-weight:normal\"> <ul>Directory del file : <b>"+ directory + "</b></ul>";
            if(type == Entrambi){
				 hashCode ="<ul>MD5: "+hashMD5 + "</ul><ul> SHA-1: " + hashSHA1 + "</ul>";
                 file = "HashcodeEntrambi"+ nomeFile + ".html";
                 dettagli += "<ul>Gli Hashcode dell'immagine " + nomeFile + ": <b>" + hashCode + "</b></ul>";
			}
            else if(type == MD5){
				hashCode = hashMD5;
                file = "HashcodeMD5"+ nomeFile + ".html";
            	dettagli += "<ul>Hashcode MD5 dell'immagine " + nomeFile + ": <b>" + hashCode + "</b></ul>";
			}
            else if(type == SHA1){
				hashCode = hashSHA1;
                file = "HashcodeSHA-1"+ nomeFile + ".html";
            	dettagli += "<ul>Hashcode SHA-1 dell'immagine " + nomeFile + ": <b>" + hashCode + "</b></ul>";
			}
            File report = new File(directory + file);

            FileWriter fw = new FileWriter(report);

			String titoloFiltro ="<h4><a name=\"ring1\">Hashcode</a>&nbsp&nbsp<ul><span style=\"font-style: italic;font-weight:normal\">Hashcode del file, viene calcolato con l'algoritmo MD5 o con l'algoritmo SHA-1. Tale codice è un identificatore, unico e sicuro, utilizzato per verificare l'integrità del file da processare.</ul></span></h4>";


            String reportHtml = "<html><body>"+titoloReport + orario + titoloFiltro + dettagli + "</body></html>";
            fw.write(reportHtml);
            fw.flush();
            fw.close();

            report.createNewFile();


        } catch (IOException ex) {
            Logger.getLogger(Plugin_Hash.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    //Calculate date and hours
    public String getData(){
        Calendar calendar = new GregorianCalendar();
        String orario;
        int giorno = calendar.get(Calendar.DAY_OF_MONTH);
        int mese = calendar.get(Calendar.MONTH);
        int anno = calendar.get(Calendar.YEAR);
        int ore = calendar.get(Calendar.HOUR);
        int minuti = calendar.get(Calendar.MINUTE);
        int secondi = calendar.get(Calendar.SECOND);
        if(calendar.get(Calendar.AM_PM) == 0)
            orario = "A.M.";
        else
            orario = "P.M.";
        String dataOra = "Report creato il " + giorno + "-" + (mese + 1) + "-" + anno+ ", alle " + ore + ":" + minuti + ":" + secondi + " " + orario;
        return dataOra;
 }

    //calculateHash calls to generate MD5 hash 
    private String calcolaMD5(String directory) throws Exception{

        String fileName = directory;
        MessageDigest md5  = MessageDigest.getInstance("MD5");
        return calculateHash(md5, fileName);

    }

    //calculateHash calls to generate SHA-1 hash 
    private String calcolaSHA1(String directory) throws Exception{
        String fileName = directory;
        MessageDigest sha1 = MessageDigest.getInstance("SHA1");
        return calculateHash(sha1, fileName);
    }

     /**
     * This method is called by ImageJ for initialization.
     * @param arg Unused here. For plugins in a .jar file this argument string can
     *            be specified in the plugins.config file of the .jar archive.
     * @param imp The ImagePlus containing the image (or stack) to process.
     * @return    The method returns flags (i.e., a bit mask) specifying the
     *            capabilities (supported formats, etc.) and needs of the filter.
     *            See PlugInFilter.java and ExtendedPlugInFilter in the ImageJ
     *            sources for details.
     */
    @Override
    public int setup(String arg, ImagePlus imp) {
        if (IJ.versionLessThan("1.38x"))
            return DONE;
        return flags;
    }


    //calculate and return the hashcode
    public static String calculateHash(MessageDigest algorithm, String fileName) throws Exception{
        FileInputStream     fis = new FileInputStream(fileName);
        BufferedInputStream bis = new BufferedInputStream(fis);
        DigestInputStream   dis = new DigestInputStream(bis, algorithm);
        while (dis.read() != -1);
        byte[] hash = algorithm.digest();
        return byteArray2Hex(hash);
    }

    // Convert Byte to Hex
    private static String byteArray2Hex(byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        return formatter.toString();
    }


    // Called after modifications to the dialog. Returns true if valid input.
    @Override
    public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
        return true;
    }

    /** Update the progress bar */
    private void showProgress(double percent) {
        if (nPasses == 0) return;
        percent = (double)pass/nPasses + percent/nPasses;
        IJ.showProgress(percent);
    }

    /** This method is called by ImageJ to set the number of calls to run(ip)
    *  corresponding to 100% of the progress bar */
    @Override
    public void setNPasses(int nPasses) {
    }

    //Get report calls to generate report after the click button  
    public void actionPerformed(ActionEvent e) {
        if(e.getActionCommand().equals("Genera Report")){
            getReport();
        }

    }

}