import ij.*;
import ij.process.*;
import ij.gui.*;
import java.awt.*;
import ij.plugin.filter.*;
import java.awt.event.*;
import java.io.FileWriter;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import java.util.*;


/**
 *
 * @authors Maria Oliva
 *          Roberta Maccarrone
 */


public class Measurement1D implements PlugInFilter {

	ImagePlus imp;

	public int setup(String arg, ImagePlus imp) {
		this.imp = imp;
		return DOES_ALL;
	}

	public void run(ImageProcessor ip) {
		imp.updateAndDraw();
		Measurement m=new Measurement(imp);
	}

}

//Classe che si occupa della misurazione 1D
class Measurement extends MouseAdapter{

    //contatore che serve per gestire i click del mouse
    private int count=0;

    //salva le coordinate della misura di riferimento
    private int[] ch=new int[4];        

    //salva le coordinate della misura
    private int[] ch2=new int[4];
    private ImageCanvas canvas;
    private ImagePlus img;

    //disegna la linea per la misura di riferimento
    private DrawLine line1=null;

    //disegna la linea per la misura reale
    private DrawLine line2=null;

    //variabile della lunghezza di riferimento
    private float rif;

    //variabile del calcolo della misura
    private float measure;                
    

    public Measurement(ImagePlus im){

        img=im;
        canvas=im.getCanvas();
        canvas.addMouseListener(this);

    }

    /*Il metodo mousePressed cattura le coordinate delle linee.
      Il count viene incrementato ad ogni click del mouse e vengono
      catturate le coordinate.
      Quando il count=4 viene resettato, in quanto sono state
      catturate tutte le coordinate*/
    @Override
     public void mousePressed(MouseEvent e){

       increaseCount();

	int x = e.getX();
	int y = e.getY();

            if(getCount()==1){

                ch[0] = x;
                ch[1] = y;

            }

            if(getCount()==2){

                ch[2] = x;
                ch[3] = y;

                //disegna la linea di riferimento
                line1=new DrawLine(img,0,ch);
                line1.draw(ch,0);

               //Gestisce l'eccezione nel caso in cui non si inserisce un valore valido
               try{
                   //Permette all'utente di inserire la misura di riferimento
                   rif=Float.parseFloat(JOptionPane.showInputDialog("Misura di riferimento: "));
                }
                catch(Exception ex){
                    JOptionPane.showMessageDialog(null,"Errore "+ex);
			resetCount();
                }

            }

            if(getCount()==3){

                ch2[0] = x;
                ch2[1] = y;

            }

            if(getCount()==4){

                ch2[2] = x;
                ch2[3] = y;


               //disegna la linea da misurare
               line2=new DrawLine(img,1,ch2);
               line2.draw(ch2,1);


               //Calcolo delle lunghezze (distanza tra due punti)
               float length1=(float)Math.sqrt(Math.abs((ch[2]-ch[0])^2+(ch[3]-ch[1])^2));

               float length2=(float)Math.sqrt(Math.abs((ch2[2]-ch2[0])^2+(ch2[3]-ch2[1])^2));
               //

               //calcola la misura reale mediante una proporzione
               measure=(float)(length2*(rif/length1));
               JOptionPane.showMessageDialog(null,"Misura: "+measure);

               
               line1=new DrawLine(img,0,ch);
               line1.draw(ch, 0);
               line2.draw(ch2,1);

             

               //Genera la finestra di dialogo
                try {
                    createWindow();
                } catch (IOException ex) {
                    Logger.getLogger(Measurement.class.getName()).log(Level.SEVERE, null, ex);
                }

                resetCount();

            }
        }



    //funzioni che gestiscono il contatore
    public void increaseCount(){count++;}

    public void resetCount(){count=0;}

    public int getCount(){return count;}
    //

    //Scrive il report html
     public String report()throws IOException{

        String name=JOptionPane.showInputDialog("Nome del file: ");
        String directory=IJ.getDirectory("image");
        String nameFile=directory+name+".html";
        FileWriter outfile=null;
        String rifCoordinates=""+ch[0]+" "+ch[1]+"\t"+ch[2]+" "+ch[3];
        String measureCoordinates=""+ch2[0]+" "+ch2[1]+"\t"+ch2[2]+" "+ch2[3];
        String details=" La Misurazione 1D calcola una distanza nel mondo reale a partire da un'immagine planare. L'immagine non deve presentare alcun tipo di distorsione ottica e prospettica.";


        Calendar c = Calendar.getInstance();
        int day = c.get(c.DAY_OF_MONTH);
        int month = c.get(c.MONTH)+1;
        int year = c.get(c.YEAR);
        int hour = c.get(java.util.Calendar.HOUR_OF_DAY);
        int minutes = c.get(java.util.Calendar.MINUTE);
        int seconds = c.get(java.util.Calendar.SECOND);
        String Date = ""+day+"/"+month+"/"+year+" "+hour+":"+minutes+":"+seconds;

		try{
			outfile = new FileWriter(nameFile);


                        outfile.write("<html><head><title>"+nameFile+"</title></head>"
                                + "<body><font size="+5+"><b>IMAGEJ REPORT</b></font><br><br>"
                                + "<font size="+4+"><b>1D Measurement</b></font><br>"
                                + "<table cellspacing="+20+"><tr><td><b>Utente: </b></td><td>"+System.getProperty("user.name")+"</td></tr>"
                                + "<tr><td><b>Nome Report: </b></td><td>"+nameFile+"</td></tr>"
                                + "<tr><td><b>Data: </b></td><td>"+Date+"</td></tr></table>"
                                + "<b>Descrizione</b>"
                                + "<br><table cellspacing="+10+"><tr><td></td><td>"+details+"</td></tr></table>"
                                + "<b>Parametri: </b><br>"
                                + "<table cellspacing="+20+"><tr><td><b>Nome dell'immagine caricata:</b></td><td>"+img.getTitle()+"</td></tr>"
                                + "<tr><td><b>Linea di riferimento:</b></td><td>"+rifCoordinates+"</td></tr>"
                                + "<tr><td><b>Lunghezza di riferimento</b></td><td>"+rif+"</td></tr>"
                                + "<tr><td><b>Linea da misurare:</b></td><td>"+measureCoordinates+"</td></tr>"
                                + "<tr><td><b>Lunghezza misurata:</b></td><td>"+measure+"</td></tr></table></body></html>");
		}
		catch (IOException e){
			System.out.println("Errore nella creazione del file: "+e);
                        return null;

		}
		finally{
			if(outfile!=null) outfile.close();
                        return directory;
		}
    }

     //Funzione che genera la finestra di dialogo per l'eventuale scrittura del report
     public void createWindow() throws IOException{
     GenericDialog gd=new GenericDialog("Misurazione");
        String label="Menu";
        String[] items={"Genera report","Non generare report"};
        gd.addChoice(label, items,items[0]);
        gd.showDialog();
        if(gd.wasCanceled()) return;

         String str=gd.getNextChoice();
         if(str.compareTo("Non generare report")==0){

            JOptionPane.showMessageDialog(null,"Il report non e' stato generato");
         }
        else if(str.compareTo("Genera report")==0){

            String directory=this.report();
            JOptionPane.showMessageDialog(null,"Il report e' stato generato nella cartella"+directory);
        }
    }

   //

}

//Classe che si occupa di disegnare le linee sull'immagine
class DrawLine{

    //array delle coordinate della linea da disegnare
    private int coord[];
    private int color;
    private Graphics g;
    private ImagePlus imp;
    private ImageCanvas canvas;

    public DrawLine(ImagePlus im, int c,int coordinates[]){

        imp=im;
        canvas=imp.getCanvas();
        color=c;
        coord=coordinates;
        g=canvas.getGraphics();

    }

    //Disegna la linee
    public void draw(int ch[], int color){

        Graphics2D gf = (Graphics2D) g;
        gf.setStroke(new BasicStroke(5F));
        switch (color){
            case 0:
                gf.setColor(Color.red);
                break;
            case 1:
                gf.setColor(Color.BLUE);
                break;
        }

        gf.drawLine(ch[0],ch[1],ch[2],ch[3]);
        gf.dispose();
    }
}