/**-------------------------------------------------------*
 * Plugin Disallineamento per ImageJ                      *
 * Programmatore: Sammartino Domenico (ziosamma@gmail.com)*
 * -------------------------------------------------------**/

/* modifiche da effettuare: 
 * 1) Diminuire la dimensione delle scrollbar e delle textlabel. Effettuare altre migliorie alla GUI.(fatto)
 * 2) salvare in automatico il report e aprirlo subito dopo (fatto)
 * 3) Dopo l'applicazione del filtro eliminare la ROI linea (fatto)
 * 4) Migliorare la gestione dell'evento mouse, impedendo i conflitti con gli altri tool di IJ (fatto)
 */


import ij.*;
import ij.process.*;
import ij.plugin.BrowserLauncher;
import ij.plugin.filter.PlugInFilter;
import ij.IJ;
import ij.gui.*;

import java.io.*;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class Disallineamento_ implements PlugInFilter, MouseListener {
	boolean enableMouse = false;
	boolean relase = false;
	ImagePlus img;
	ImageCanvas canvas;
	ImageProcessor ip;
	int line = 0;
	int jump = 0;
	int firstPx = 0;
	int seconPx = 0;
	int clickcount = 1;
	
	private javax.swing.JButton about;
    private javax.swing.JButton addOp;
    private javax.swing.JButton delOp;
    private javax.swing.JLabel label1;
    private javax.swing.JLabel label2;
    private javax.swing.JScrollPane jScrollPane2;
    private java.awt.List lista;
    private javax.swing.JButton onListener;
    private javax.swing.JButton report;
    private javax.swing.JScrollBar scrollL;
    private javax.swing.JScrollBar scrollR;
    private javax.swing.JTextField textL;
    private javax.swing.JTextField textR;
	
	public int setup(String arg, ImagePlus img) {
		if(arg.equals("about")) {
			showAbout();
			return DONE;
		}
		this.img = img;
		return DOES_ALL+SUPPORTS_MASKING;
	}
	public void run(ImageProcessor ip) {
		this.ip = ip; //init world variable imageProcessor ip 
		//implements mouse listeners on image
		ImageWindow win = img.getWindow();
		canvas = win.getCanvas();
		canvas.addMouseListener(this);
		initComponents();
		
	}
	
	void showAbout() {
		IJ.showMessage("About Inverter_...",
				"Plugin by: Sammartino domenico (ziosamma@gmail.com)" +
				"\nEffettua una traslazione orizzontale di n-pixel di una linea dell'immagine."
				);
	}
	//Motore plugin vero e proprio che funziona con immagini sia 8-bit che RGB (testate)
	void pluginDis(int jump, int line) {
		
		int width = ip.getWidth(); 
		int[] array = new int[width];
		
		//switch a sinistra
		if(jump < 0) {
			jump = jump * -1; //jump diventa positivo
			for(int j = 0; j < width-1; j++) {
				int l = (width-1)-j; //index del pixel da switchare 
				if(l - jump > 0) array[l-jump] = ip.getPixel(l, line);
				else if(l - jump <= 0) array[(l-jump)+(width-1)] = ip.getPixel(l, line);
			}
		for(int h = 0; h < width; h++) 
			ip.putPixel(h, line, array[h]);
		}
		else if(jump > 0) {
		//switch a destra
		for(int j = (width-1); j >= 0; j--) {
			int l = (width-1) - j; //index del pixel da switchare
			if(l+jump <= (width-1)) array[l+jump] = ip.getPixel(l, line);
			else if(l+jump > (width-1)) array[(l+jump)-(width-1)] = ip.getPixel(l, line);
		}
		for(int h = 0; h < width; h++) 
			ip.putPixel(h, line, array[h]);
		}
		img.updateAndDraw();
		
	}
	//funzione che avvia il plugin
	public void addOperation() {
		//controlla se i valori sono validi
		if((!textR.getText().equals("range") && !textL.getText().equals("line")) &&
				(Integer.parseInt(textR.getText())<=ip.getWidth() && Integer.parseInt(textR.getText())>=-ip.getWidth() && 
						Integer.parseInt(textL.getText())<=ip.getHeight())) {
		pluginDis(Integer.parseInt(textR.getText()),
				Integer.parseInt(textL.getText()));
		String stringa = "" + textR.getText() + "          " + textL.getText();
		lista.add(stringa);
		return;
		}
		else {
			IJ.error("Errore", "Valori range e line non validi!");
		}
	}
	//metodo che crea il report HTML
	public void creaReportFile() {
		//scrittura vera e propria del file di report
		try {
			String immagine = img.getOriginalFileInfo().directory;
			immagine += img.getOriginalFileInfo().fileName;
			GregorianCalendar gc = new GregorianCalendar();
			String ora,min,sec;
			int anno = gc.get(Calendar.YEAR);
			int mese = gc.get(Calendar.MONTH) + 1;
			int giorno = gc.get(Calendar.DATE);
			if(gc.get(Calendar.HOUR_OF_DAY) < 10)
				ora = ""+"0"+gc.get(Calendar.HOUR_OF_DAY);
			else
				ora = ""+gc.get(Calendar.HOUR_OF_DAY);
			if(gc.get(Calendar.MINUTE) < 10)
				min = ""+"0"+gc.get(Calendar.MINUTE);
			else
				min = ""+gc.get(Calendar.MINUTE);
			if(gc.get(Calendar.SECOND) < 10)
				sec = ""+"0"+gc.get(Calendar.SECOND);
			else
				sec = ""+gc.get(Calendar.SECOND);
			//percorso file immagine
			String file = img.getOriginalFileInfo().directory;
			file += img.getOriginalFileInfo().fileName+"-report.html";
			//creazione file report.html
			FileWriter report = new FileWriter(file);
			report.append("<html>");
			report.append("<head>");
			report.append("<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\">");
			report.append("</head>");
			report.append("<body>");
			report.append("<h1>Disallineamento Report</h1>");
			report.append("Data Generazione Report: "+"<strong>" + giorno +"\\"+mese+"\\"+
					anno	+" "+ora+":"+min+":"+sec+"</strong><BR>");
			report.append("Immagine: "+"<strong>"+immagine+"</strong><BR>");
			report.append("<hr><h2>Filtro</h2>");
			report.append("<p>Il filtro effettua una traslazione in orizzontale di una linea di pixel, per permettere il \"riallineamento\" di alcuni dettagli altrimenti non riconoscibili."+
					"<ul><li><strong>Range:</strong> rappresenta di quanti pixel viene traslata la riga.</li>" + 
					"<li><strong>Line:</strong> indica quale riga subisce la traslazione.</li></ul>"+
					"<strong>Un valore Range positivo indica una traslazione verso destra.Un valore Range negativo indica una traslazione verso sinistra.</strong></p>");
			report.append("<hr><h2>Valori Applicati</h2></hr>");
			report.append("<ul>");
			for(int i = 0;i<lista.getItemCount();i++)
				report.append("<li>Range: "+(lista.getItem(i).split("          "))[0]+" Line: "+
						(lista.getItem(i).split("          "))[1]+"</li>");
			report.append("</ul>");
			report.close();
			//apriamo il report creato in una finestra del browser
			BrowserLauncher BL = new BrowserLauncher();
			BL.run("file:///"+file);
		} catch (IOException e) {
			IJ.error("File output non trovato");
		}
	}
	//ascoltatore di eventi mouse...cliccando due volte sul primo pixel e due volte sul secondo
	//calcola l'entita di range e la linea da traslare..sostituito dal metodo per trascinamento
	public void mouseClicked(MouseEvent e) {
	}
	public void mouseEntered(java.awt.event.MouseEvent arg0) {
		
	}
	public void mouseExited(java.awt.event.MouseEvent arg0) {
		
	}
	//con questi due metodi è possibile ricavare l'entità dello spostamento trascinando il cursore
	public void mousePressed(MouseEvent e) {
		if(enableMouse)
			if(IJ.getToolName().equals("line")) { //se il tool in uso è proprio quello line 
				int y;							  //allora effettua l'operazione del plugin
				y = e.getY();
				line = canvas.offScreenY(y);
				firstPx = e.getX();
				relase = true;
			}
			else { 
				enableMouse = false;  			  //altrimenti torna allo stato di mouse listener OFF 
				onListener.setText("Mouse OFF"); //e permetti di usare il tool selezionato dall'utente
				onListener.setBackground(Color.red);
				relase = false; 
				}
	}
	public void mouseReleased(MouseEvent e) {
		if(relase && enableMouse && IJ.getToolName().equals("line")) {
			seconPx = e.getX();
			jump = canvas.offScreenX(seconPx) - canvas.offScreenX(firstPx);
			textR.setText(""+jump);
			textL.setText(""+line);
			scrollR.setValue(jump);
			scrollL.setValue(line);
			seconPx = 0;
			firstPx = 0;
			relase = false;
			addOperation();
			//elimina la linea gialla che si disegna quando si usa il mouse
			img.killRoi();
		}
	}
	//funzione che avvia la GUI
    private void initComponents() {
    	JFrame wind = new JFrame();
    	wind.setVisible(true);
        delOp = new javax.swing.JButton();
        about = new javax.swing.JButton();
        addOp = new javax.swing.JButton();
        jScrollPane2 = new javax.swing.JScrollPane();
        report = new javax.swing.JButton();
        textR = new javax.swing.JTextField();
        onListener = new javax.swing.JButton();
        scrollR = new javax.swing.JScrollBar(Scrollbar.HORIZONTAL,0,1,-ip.getWidth(),ip.getWidth()+1);
        scrollR.addAdjustmentListener(new AdjustmentListener () {
        	public void adjustmentValueChanged(AdjustmentEvent e) {
        		jump = scrollR.getValue();
        		textR.setText(""+jump);
        		return;
        	}
        });
        label2 = new javax.swing.JLabel();
        textL = new javax.swing.JTextField();
        scrollL = new javax.swing.JScrollBar(Scrollbar.HORIZONTAL,0,1,0,ip.getHeight()+1);
        scrollL.addAdjustmentListener(new AdjustmentListener() {
			public void adjustmentValueChanged(AdjustmentEvent e) {
				line = scrollL.getValue();
				textL.setText(""+line);
				return;
			}	
		});
        label1 = new javax.swing.JLabel();
        lista = new java.awt.List();


        delOp.setText("DeleteOperation");
        delOp.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				try {
				String stringa = lista.getSelectedItem();
				lista.remove(stringa);
				String[] st = stringa.split("          ");
				pluginDis((-1*Integer.parseInt(st[0])),Integer.parseInt(st[1]));
				}
				catch(Exception e) {}
			}
		});
        about.setText("About");
        about.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				showAbout();			
			}	
		});
        addOp.setText("AddOperation");
        addOp.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				addOperation();
			}
		});


        jScrollPane2.setViewportView(lista);

        report.setText("Report");
        report.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				creaReportFile();
				return;
			}
		});

        onListener.setText("Mouse OFF");
        onListener.setBackground(Color.red);
        onListener.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if(!enableMouse) {
					IJ.setTool(Toolbar.LINE);
					enableMouse = true;
					onListener.setBackground(Color.green);
					onListener.setText("Mouse ON");
				}
				else if(enableMouse) {
					IJ.setTool(Toolbar.HAND);
					enableMouse = false;
					onListener.setBackground(Color.red);
					onListener.setText("Mouse OFF");
				}
			}
		});

        scrollR.setOrientation(javax.swing.JScrollBar.HORIZONTAL);

        label2.setText("Line");

        scrollL.setOrientation(javax.swing.JScrollBar.HORIZONTAL);

        label1.setText("Range");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(wind.getContentPane());
        wind.getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(scrollL, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 237, Short.MAX_VALUE)
                    .addComponent(scrollR, javax.swing.GroupLayout.PREFERRED_SIZE, 237, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 203, Short.MAX_VALUE)
                        .addGap(34, 34, 34)))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addGroup(layout.createSequentialGroup()
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(about, javax.swing.GroupLayout.DEFAULT_SIZE, 129, Short.MAX_VALUE))
                            .addGroup(layout.createSequentialGroup()
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(report, javax.swing.GroupLayout.DEFAULT_SIZE, 129, Short.MAX_VALUE))
                            .addGroup(layout.createSequentialGroup()
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(onListener, javax.swing.GroupLayout.DEFAULT_SIZE, 129, Short.MAX_VALUE))
                            .addGroup(layout.createSequentialGroup()
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(delOp, javax.swing.GroupLayout.DEFAULT_SIZE, 129, Short.MAX_VALUE))
                            .addComponent(addOp, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 129, Short.MAX_VALUE))
                        .addGap(18, 18, 18))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(textL, javax.swing.GroupLayout.DEFAULT_SIZE, 67, Short.MAX_VALUE)
                            .addComponent(textR, javax.swing.GroupLayout.DEFAULT_SIZE, 67, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(label2, javax.swing.GroupLayout.DEFAULT_SIZE, 66, Short.MAX_VALUE)
                            .addComponent(label1, javax.swing.GroupLayout.DEFAULT_SIZE, 66, Short.MAX_VALUE))
                        .addContainerGap())))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(38, 38, 38)
                        .addComponent(scrollR, javax.swing.GroupLayout.DEFAULT_SIZE, 20, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(scrollL, javax.swing.GroupLayout.DEFAULT_SIZE, 20, Short.MAX_VALUE))
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(textR)
                            .addComponent(label1, javax.swing.GroupLayout.DEFAULT_SIZE, 17, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(textL)
                            .addComponent(label2, javax.swing.GroupLayout.DEFAULT_SIZE, 17, Short.MAX_VALUE))))
                .addGap(55, 55, 55)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(addOp, javax.swing.GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(delOp, javax.swing.GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(onListener, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(report, javax.swing.GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(about, javax.swing.GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE))
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 139, Short.MAX_VALUE))
                .addGap(22, 22, 22))
        );

        wind.pack();
    }

}
