/**-------------------------------------------------------*
 * Plugin Clone_Detection2 per ImageJ                      *
 * Programmatore: Viagrande Luigi Claudio (luigiviagrande@gmail.com) and Roberta Carrubba (robertacarrubba@gmail.com)*
 * -------------------------------------------------------**/
import ij.*;
import ij.measure.Calibration;
import ij.process.*;
import ij.plugin.filter.PlugInFilter;
import ij.IJ;
import ij.gui.*;
import ij.io.*;
import java.io.*;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

//sistemare il target nel report quando non assegnamo un target
public class CloneDetection2_ implements PlugInFilter, MouseListener {
	boolean enableMouse = false;
	ImagePlus img,imgSwap;
	ImageCanvas canvas;
	ImageProcessor ip,ipSwap;
	int indice = 0;
	int type_ricerca=0;
	double scalex=0;
	double scaley=0;
	double iscalex=0;
	double iscaley=0;
	int soglia=0;
	int rotazione=0;
	int passi=0;
	int jump = 0;
	int firstPx = 0;
	int firstPy = 0;
	int secondPx = 0;
	int secondPy = 0;
	int width=0;
	int heigth=0;
	int clickcount = 1;
	int threshold,angolo,rotazioni=0;
	double scaleX,scaleY,iscaleX,iscaleY=0;
	double IncrX,IncrY=0;
	int xSource,ySource,wSource,hSource=0;
	int xTarget,yTarget,wTarget,hTarget=0;
	int image_search=0;
	boolean target=false;
	
	Scrollbar rangeS = null;
	Scrollbar lineS = null;
	TextField rangeT = null;
	TextField lineT = null;
	TextField Angle = null;
	TextField Steps = null;
	TextField iScaleX,iScaleY,ScaleX,ScaleY,Xinput,Yinput,Winput,Hinput=null;
	Button addValue = null;
	Button deleteOp = null;
	Button report = null;
	Button about = null;
	Button onListener = null;
	Button Source=null;
	Button Target=null;
	Button ClearSource,ClearTarget,ClearResult,ClearAll;
	List lista,listaTarget,listaResult = null;
	List source,targets,result,thresh,angle,gradi,xscale,yscale,ixscale,iyscale,counterClock=null;
	Rectangle myRoi,sourceRoi,targetRoi=null;
	ImageProcessor SourceIp,SourceIpTemp,TargetIp,SwapIp=null;
	int targetOffsetX,targetOffsetY=0;
	Checkbox clockWise;
	JPanel labelProva = new JPanel();
	List[] reportList=new List[8];
	String string,string2,string4,string5,string3=null;
	
	
	public int setup(String arg, ImagePlus img) {
		if(arg.equals("about")) {
			showAbout();
			return DONE;
		}
		this.img = img;
		imgSwap=img;
		return DOES_ALL+SUPPORTS_MASKING;
	}
	public void run(ImageProcessor ip) {
		this.ip = ip; //init world variable imageProcessor ip
		ipSwap=ip;
		//implements mouse listeners on image
		ImageWindow win = img.getWindow();
		canvas = win.getCanvas();
		canvas.addMouseListener(this);
		startInterface();
		
	}
	
	void showAbout() {
		IJ.showMessage("About Brute_...",
				"Plugin by: Viagrande Luigi Claudio (luigiviagrande@gmail.com)" +" e Roberta Carrubba (robertacarrubba@gmail.com)"+
				"\nEffettua un Clone Detection sull'immagine desiderata."
				);
	}
	//Funzione principale, adibita alla ricerca di cloni nell'immagine
	void Search_Clone(int soglia, int rot, int step,double Scalex,double Scaley,double iScalex,double iScaley) 
	{
		
		indice++;
		int angoli=0;
		/*
		listaResult.removeAll();
		listaResult.add("Result");
		*/
		listaResult.add("Ricerca "+indice);
		int width = ip.getWidth();
		int height = ip.getHeight();
		
		int[] arrayCopy=new int[3];
		int[] arrayReal=new int[3];
		int amount=SourceIp.getWidth()*SourceIp.getHeight();
		amount/=3;
		amount*=2;
		int matches=0;
		int ruota=0;
		SourceIp.setInterpolationMethod(0);
		SwapIp=SourceIp;
		
		threshold=soglia;
		angolo=rot;
		if(step<0)
			step*=-1;
		rotazioni=step;
		scaleX=Scalex;
		scaleY=Scaley;
		iscaleX=iScalex;
		iscaleY=iScaley;
		xSource=sourceRoi.x;
		ySource=sourceRoi.y;
		wSource=sourceRoi.width;
		hSource=sourceRoi.height;
		
		
		source.add("X: "+xSource);
		source.add("Y: "+ySource);
		source.add("W: "+wSource);
		source.add("H: "+hSource);
		
		
		if(targetRoi!=null)
		{
			xTarget=targetRoi.x;
			yTarget=targetRoi.y;
			wTarget=targetRoi.width;
			hTarget=targetRoi.height;
			targets.add("X: "+xTarget);
			targets.add("Y: "+yTarget);
			targets.add("W: "+wTarget);
			targets.add("H: "+hTarget);
		}
		else
		{
			targets.add("N/A");
			targets.add("N/A");
			targets.add("N/A");
			targets.add("N/A");
		}
		
		//controlla se la rotazione della sorgente deve avvenire in senso orario o antiorario
		if(clockWise.getState())
		{
			ruota=step*(-1);
			counterClock.add("CounterClockWise: yes");
		}
		else
		{
			ruota=step;
			counterClock.add("CounterClockWise: no");
		}
		if(TargetIp==null)
		{
			
			target=false;
			for(int r=0;r<rot+1;r+=step)
			{
			
			if(r!=0)
			{
			SourceIp.rotate(ruota);
			angoli+=ruota;
			}
			if(step==0)
				r=rot+1;
		for(int i=0;i<width;i++)
		{
			for(int l=0;l<height;l++)
			{
				matches=0;
				for(int j=0;j<sourceRoi.width;j++)
				{
					for(int k=0;k<sourceRoi.height;k++)
					{
						image_search=1;
						SourceIp.getPixel(j,k,arrayCopy);
						ip.getPixel(i+j,l+k,arrayReal);
						if(Math.abs(arrayReal[0]-arrayCopy[0])<soglia)
							if(Math.abs(arrayReal[1]-arrayCopy[1])<soglia)
								if(Math.abs(arrayReal[2]-arrayCopy[2])<soglia)
									matches++;
					}
					
				}
				if(matches>amount)
				{
					if(image_search!=1){ip.setColor(Color.RED);}else{ip.setColor(Color.white);}
					ip.setLineWidth(2);
					
					ip.drawRect(i,l,sourceRoi.width,sourceRoi.height);
					String stringa = "x: " + i + " y: " + l +" w: " + sourceRoi.width + " h: " + sourceRoi.height;
					listaResult.add(stringa);
					result.add(stringa);
					
					image_search=2;
				}
				
				}	
			}
		}
		}
		else
		{
			target=true;
			for(int r=0;r<rot+1;r+=step)
			{
				if(r!=0)
				{
				SourceIp.rotate(ruota);
				angoli+=ruota;
				}
				if(step==0)
					r=rot+1;
			for(int i=0;i<targetRoi.width;i++)
			{
				for(int l=0;l<targetRoi.height;l++)
				{
					
					matches=0;
					for(int j=0;j<sourceRoi.width;j++)
					{
						for(int k=0;k<sourceRoi.height;k++)
						{
							SourceIp.getPixel(j,k,arrayCopy);
							TargetIp.getPixel(i+j,l+k,arrayReal);
							if(Math.abs(arrayReal[0]-arrayCopy[0])<soglia)
								if(Math.abs(arrayReal[1]-arrayCopy[1])<soglia)
									if(Math.abs(arrayReal[2]-arrayCopy[2])<soglia)
										matches++;
						}
						
					}
					if(matches>amount)
					{
						
						String stringa = "x: " + (i+targetOffsetX) + " y: " + (l+targetOffsetY) +" w: " + sourceRoi.width + " h: " + sourceRoi.height;
						listaResult.add(stringa);
						result.add(stringa);
						ip.setLineWidth(2);
						ip.setColor(Color.RED);
						ip.drawRect(i+targetOffsetX,l+targetOffsetY,sourceRoi.width,sourceRoi.height);
					}
					
					}
				}
			}
			TargetIp.reset();
		}
			
		//Flipping Horizontal
				SourceIp.flipHorizontal();
				type_ricerca=1;
		        ImagePlus alter3 = new ImagePlus("Flipping", ip) ;
		        ImagePlus alter4 = new ImagePlus("Flipping2", SourceIp) ;
			    CloneSearch(width,height,soglia,amount,type_ricerca);
			    SourceIp.flipHorizontal();
			    
				
				
			
		//Scaling			    
			     SourceIpTemp=SourceIp.duplicate();
			     type_ricerca=2;
		             for(double ys=0;ys<=Scaley;ys+=iscaleY){
		                for(double xs=0;xs<=Scalex;xs+=iscaleX){
		                   if(Scalex!=0 && Scaley!=0){    	 
			                 SourceIp.scale(xs,ys);
			                 ImagePlus alter = new ImagePlus("scale", ip) ;  
		                     ImagePlus alter2 = new ImagePlus("scalling", SourceIp) ;
		                     CloneSearch(width,height,soglia,amount,type_ricerca);  
		                     SourceIp=SourceIpTemp.duplicate();
		              }
			        }
			    } 
			   
	    listaResult.add("Ricerca Completata");
			    
		result.add("0");
		SourceIp.reset();
		SourceIp.rotate(angoli*(-1));
		string="Threshold:"+threshold;
		thresh.add(string);
		string2="Angle: "+angolo;
		angle.add(string2);
		string3="Steps: "+rotazioni;
		gradi.add(string3);
		
		string4="Scale x: "+scaleX;
		xscale.add(string4);
		
		string5="Scale y: "+scaleY;
		yscale.add(string5);
		
		string4="Incremento x: "+scaleX;
		ixscale.add(string4);
		
		string5="Incremento y: "+scaleY;
		iyscale.add(string5);
		
		img.updateAndDraw();
		
		
	}
	
	
	
	
	
	void CloneSearch(int width,int height,int soglia,int amount,int type_ricerca){
		int[] arrayCopy=new int[3];
	    int[] arrayReal=new int[3];
	    
	
		
		    if(targetRoi!=null)
		{
			xTarget=targetRoi.x;
			yTarget=targetRoi.y;
			wTarget=targetRoi.width;
			hTarget=targetRoi.height;
			targets.add("X: "+xTarget);
			targets.add("Y: "+yTarget);
			targets.add("W: "+wTarget);
			targets.add("H: "+hTarget);
		}
		else
		{
			targets.add("N/A");
			targets.add("N/A");
			targets.add("N/A");
			targets.add("N/A");
		}
	    
		int matches=0;
		if(TargetIp==null)
		{
		for(int i=0;i<width;i++)
		{
			for(int l=0;l<height;l++)
			{
			matches=0;
				for(int x=0;x<sourceRoi.width;x++)
		          {
					
					
					for(int y=0;y<sourceRoi.height;y++)
		            	{	
						SourceIp.getPixel(x,y,arrayCopy);
						 ip.getPixel(i+x,l+y,arrayReal);
						
						 
						if(Math.abs(arrayReal[0]-arrayCopy[0])<soglia)
							if(Math.abs(arrayReal[1]-arrayCopy[1])<soglia)
								if(Math.abs(arrayReal[2]-arrayCopy[2])<soglia)
								      matches++;
								
					}	
				}
				
				
				//matches==indice se la roi e la porzione immagine hanno uguale dimesione
				//matches>amount pixel uguali ta Roi e immagine
				if(matches>amount)
				{
					ip.setLineWidth(2);
					if(type_ricerca==1)	ip.setColor(Color.GREEN);
					if(type_ricerca==2)  ip.setColor(Color.blue);
					ip.drawRect(i,l,sourceRoi.width,sourceRoi.height);
					String stringa ="x: " + i + " y: " + l +" w: " + sourceRoi.width + " h: " + sourceRoi.height;
					listaResult.add(stringa);
					result.add(stringa);
				}
			
            }		
		}}
		else
		{	
			target=true;

			listaResult.add("mah");
			for(int i=0;i<targetRoi.width;i++)
			{
				for(int l=0;l<targetRoi.height;l++)
				{
					
					matches=0;
					for(int j=0;j<sourceRoi.width;j++)
					{
						for(int k=0;k<sourceRoi.height;k++)
						{
							SourceIp.getPixel(j,k,arrayCopy);
							TargetIp.getPixel(i+j,l+k,arrayReal);
							if(Math.abs(arrayReal[0]-arrayCopy[0])<soglia)
								if(Math.abs(arrayReal[1]-arrayCopy[1])<soglia)
									if(Math.abs(arrayReal[2]-arrayCopy[2])<soglia)
										matches++;
						}
						
					}
					if(matches>amount)
					{
						
						String stringa = "x: " + (i+targetOffsetX) + " y: " + (l+targetOffsetY) +" w: " + sourceRoi.width + " h: " + sourceRoi.height;
						listaResult.add(stringa);
						result.add(stringa);
						ip.setLineWidth(2);
					if(type_ricerca==1)	ip.setColor(Color.GREEN);
					if(type_ricerca==2)  ip.setColor(Color.blue);
						ip.drawRect(i+targetOffsetX,l+targetOffsetY,sourceRoi.width,sourceRoi.height);
					}
					
					}
				}
			TargetIp.reset();
		}
		type_ricerca=0;
	}
	//metodo che implementa la GUI con i suoi bottoni e i metodi azione ad essi legati
	void startInterface() 
	{
		
		source=new List(5,false);
		targets=new List(5,false);
		result=new List(5,false);
		thresh=new List(5,false);
		angle=new List(5,false);
		gradi=new List(5,false);
		xscale=new List(5,false);
		yscale=new List(5,false);
		ixscale=new List(5,false);
		iyscale=new List(5,false);
		
		counterClock=new List(5,false);
		JFrame wind = new JFrame("CloneDetect2");
		wind.setLocation(100, 100);
		wind.setSize(600, 400);
		wind.setLayout(new GridLayout(1,1));
		
		
	
		JPanel buttonP = new JPanel();
		buttonP.setLayout(new GridLayout(9,1));
		buttonP.setVisible(true);

		JPanel labelP = new JPanel();
		labelP.setLayout(new GridLayout(1,2));
		labelP.setVisible(true);
		
		JPanel labelList = new JPanel();
		labelList.setLayout(new GridLayout(3,1));
		labelList.setVisible(true);
		
		
		
		JPanel inputArea = new JPanel();
		inputArea.setLayout(new GridLayout(6,4));
		inputArea.setVisible(true);
		
		JPanel labelRight = new JPanel();
		labelRight.setLayout(new GridLayout(2,1));
		labelRight.setVisible(true);
		
		JPanel labelLeft = new JPanel();
		labelLeft.setLayout(new GridLayout(1,1));
		labelLeft.setVisible(true);
		

		JLabel label=new JLabel("X: ");
		JLabel label2=new JLabel("Y: ");
		JLabel label3=new JLabel("W: ");
		JLabel label4=new JLabel("H: ");
		JLabel label5=new JLabel("Threshold: ");
		JLabel label6=new JLabel("Rotation: ");
		JLabel label7=new JLabel("Steps: ");
		JLabel label9=new JLabel("Scale x: ");
		JLabel labe20=new JLabel("Scale y: ");
		JLabel label8=new JLabel("CounterClock ");
		JLabel labe21=new JLabel("Amount X: ");
		JLabel labe22=new JLabel("Amount Y: ");
		
		
		ScaleX = new TextField("0");
		ScaleX.setSize(5, 1);
		
		ScaleY = new TextField("0");
		ScaleY.setSize(5, 1);
		
		iScaleX = new TextField("0");
		iScaleX.setSize(5, 1);
		
		iScaleY = new TextField("0");
		iScaleY.setSize(5, 1);
		
		rangeT = new TextField();
		rangeT.setSize(5, 1);
		
		Angle = new TextField("0");	
		Angle.setSize(5, 1);
		
		Steps = new TextField("0");
		Steps.setSize(5, 1);
		
		Xinput= new TextField("X");
		Xinput.setSize(5, 1);
		
		Yinput= new TextField("Y");
		Yinput.setSize(5, 1);
		
		Winput= new TextField("W");
		Winput.setSize(5, 1);
		
		Hinput= new TextField("H");
		Hinput.setSize(5, 1);
		
		clockWise=new Checkbox("",false);
		
		inputArea.add(label);
		inputArea.add(Xinput);
		inputArea.add(label2);
		inputArea.add(Yinput);
		inputArea.add(label3);
		inputArea.add(Winput);
		inputArea.add(label4);
		inputArea.add(Hinput);
		inputArea.add(label5);
		inputArea.add(rangeT);
		inputArea.add(label6);
		inputArea.add(Angle);
		inputArea.add(label7);
		inputArea.add(Steps);
		inputArea.add(label8);
		inputArea.add(clockWise);
		
		inputArea.add(label9);
		inputArea.add(ScaleX);
		
		inputArea.add(labe20);
		inputArea.add(ScaleY);
		
		inputArea.add(labe21);
		inputArea.add(iScaleX);
		
		inputArea.add(labe22);
		inputArea.add(iScaleY);
		
		addValue = new Button("Search_Clone");
		addValue.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent e) 
			{
				boolean ok=true;
				try
				{
					
				soglia=Integer.parseInt(rangeT.getText());
				}
				catch (NumberFormatException ex) 
				{
		            ok=false;
		            int soglia2=(ip.getAutoThreshold()/2);
		            IJ.error("Errore", "Non hai specificato una soglia valida"+"\n"+"La soglia consigliata è "+soglia2);
		        }
				if(sourceRoi==null)
				{
					ok=false;
					IJ.error("Errore", "Non hai specificato una sorgente valida");
				}
				
				try
				{
				rotazione=Integer.parseInt(Angle.getText());
				passi=Integer.parseInt(Steps.getText());
				

				}
				catch (NumberFormatException ex) 
				{
		            ok=false;
		            IJ.error("Errore", "I valori di rotazione inseriti non sono validi");
		        }
				
				
				try{
					scalex=Double.parseDouble(ScaleX.getText());
				    scaley=Double.parseDouble(ScaleY.getText());	
				    iscalex=Double.parseDouble(iScaleX.getText());
				    iscaley=Double.parseDouble(iScaleY.getText());
				    
				  
				}
				
				catch (Exception ex) {
					ok=false;
					IJ.error("Errore", "I valori di scalatura inseriti non sono validi");
					  }
				if((iscalex==0||iscaley==0)&&(scalex!=0 || scaley!=0))
				{
					ok=false;
					IJ.error("Errore", "Non hai specificato i valori Amount x e Amount y");
				}
				
				if(ok)
				{
				Search_Clone(soglia,rotazione,passi,scalex,scaley,iscalex,iscaley);
				}
			}
		});
	
		report = new Button("Report HTML");
		report.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent arg0) 
			{
				creaReportFile();
				return;
			}
		});
		
		Source = new Button("Source");
		Source.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent arg0) 
			{
				makeSource();
				return;
			}
		});
		
		ClearResult = new Button("Clear_Result");
		ClearResult.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent arg0) 
			{
				int reply = JOptionPane.showConfirmDialog(null, "Sei sicuro?", "Cancella i risultati", JOptionPane.YES_NO_OPTION);
			    if (reply == JOptionPane.YES_OPTION)
			    {
				clearResult();
			    }
				return;
			}
		});
		
		ClearSource = new Button("Clear_Source");
		ClearSource.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent arg0) 
			{
				clearSource();
				return;
			}
		});
		
		ClearTarget = new Button("Clear_Target");
		ClearTarget.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent arg0) 
			{
				clearTarget();
				return;
			}
		});
		
		ClearAll = new Button("Clear_All");
		ClearAll.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent arg0) 
			{
				int reply = JOptionPane.showConfirmDialog(null, "Sei sicuro?", "Cancella tutto", JOptionPane.YES_NO_OPTION);
			    if (reply == JOptionPane.YES_OPTION)
			    {
			      
			      clearSource();
				  clearTarget();
				  clearResult();
			    }
				
				
				return;
			}
		});
		
		Target = new Button("Target");
		Target.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent arg0) 
			{
				makeTarget();
				return;
			}
		});
		
		about = new Button("About");
		about.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent arg0) 
			{
				IJ.resetThreshold();
				showAbout();			
			}	
		});
		
		
		
		buttonP.add(addValue);
		buttonP.add(Source);
		buttonP.add(Target);
		buttonP.add(ClearSource);
		buttonP.add(ClearTarget);
		buttonP.add(ClearResult);
		buttonP.add(ClearAll);
		buttonP.add(report);
		buttonP.add(about);
	
		
		lista = new List(5,false);
		listaTarget = new List(5,false);
		listaResult = new List(5,false);
		listaResult.setBackground(Color.lightGray);
		listaTarget.setBackground(Color.lightGray);
		lista.setBackground(Color.lightGray);
		lista.setFocusable(false);
		listaResult.setFocusable(false);
		listaTarget.setFocusable(false);
		labelRight.add(inputArea);
		labelRight.add(buttonP);
		labelList.add(lista);
		labelList.add(listaTarget);
		labelList.add(listaResult);
		labelLeft.add(labelList);
		labelP.add(labelLeft);
		labelP.add(labelRight);
		
		
		lista.add("Source");
		listaTarget.add("Target");
		listaResult.add("Result");
		
		
		wind.add(labelP);
		wind.setVisible(true);
		
	}
	//metodo che crea il report HTML
	public void creaReportFile() 
	{
		reportList[0]=source;
		reportList[1]=targets;
		reportList[2]=result;
		reportList[3]=thresh;
		reportList[4]=angle;
		reportList[5]=gradi;
		reportList[6]=xscale;
		reportList[7]=yscale;
		reportList[8]=ixscale;
		reportList[9]=iyscale;
		//apri la finestra di dialogo per scegliere dove salvare il report
		SaveDialog s = new SaveDialog("Salva report","report",".html");
		//tramite la finestra sopra ottengo il percorso dove voglio salvere il report
		//N.B. il report ancora non è stato creato
		String file = s.getDirectory(); //mi ricavo il percorso del 
		file += s.getFileName();        //file immagine per scopi futuri
		//scrittura vera e propria del file di report
		try {
			String immagine = img.getOriginalFileInfo().directory;
			immagine += img.getOriginalFileInfo().fileName;
			GregorianCalendar gc = new GregorianCalendar();
			int anno = gc.get(Calendar.YEAR);
			int mese = gc.get(Calendar.MONTH) + 1;
			int giorno = gc.get(Calendar.DATE);
			int ora = gc.get(Calendar.HOUR_OF_DAY);
			int min = gc.get(Calendar.MINUTE);
			int sec = gc.get(Calendar.SECOND);
			
			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>Clone Detection 2 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 ricerca Brute Force di possibili segmenti di immagini clonati all'interno della stessa. Controlla se la differenza tra i valori assoluti dei valori dei pixel sorgente con quelli della zona analizzata corrisponde a meno di una certa soglia. "+
					"<ul><li><strong>Source:</strong> Rappresenta rispettivamente la posizione x del pixel in alto a sinistra che descrive la regione d'interesse che si andra' a confrontare, la sua posizione y, la lunghezza e l'altezza della nostra regione.</li></ul>" + 
					"<ul><li><strong>Threshold:</strong> Indica il valore di soglia specificata per la ricerca.</li></ul>"+
					"<ul><li><strong>Target:</strong> Se presente indica una specifica sezione dell'immagine sulla quale si e' effettuata la ricerca.</li></ul>"+
					"<ul><li><strong>Result:</strong> Indica i possibili cloni rinvenuti nell'immagine.</li></ul></p>"+
					"<ul><li><strong>Angle:</strong> Rappresenta il grado massimo di rotazione della zona da confrontare (Source).</li></ul>"+
					"<ul><li><strong>Steps:</strong> Indica di quanti gradi la zona da confrontare, (source), ruotera' ad ogni ricerca prima di giungere al valore di Angle.</li></ul></p>"+
					"<ul><li><strong>CounterClockWise:</strong> Indica se la rotazione della sorgente avviene in senso orario o meno.</li></ul></p>"+
					"<ul><li><strong>Scale X:</strong> Indica il valore massimo di scala lungo l'asse x.</li></ul></p>"+
					"<ul><li><strong>Scale Y:</strong> Indica il valore massimo di scala lungo l'asse y .</li></ul></p>"+
					"<ul><li><strong>Amount x:</strong> Indica di quanto la scalatura sull'asse x deve aumentare ad ogni iterazione prima di giungere al valore massimo di scale sull'asse x.</li></ul></p>"+
		            "<ul><li><strong>Amount y:</strong> Indica di quanto la scalatura sull'asse y deve aumentare ad ogni iterazione prima di giungere al valore massimo di scale sull'asse y.</li></ul></p>");

			report.append("<hr><h2>Valori Applicati e risultati</h2></hr>");
			int j=thresh.getItemCount();
			int risultato=0;
			for(int k=1;k<=j;k++)
			{
				report.append("<hr><h2>Ricerca "+k+"</h2></hr>");
				report.append("<ul>");
			
					report.append("Source:"+"<br>");
					for(int l = (k-1)*4;l<k*4;l++)
					{
						report.append("<li>"+source.getItem(l)+"</li>");
						
				
					}
					report.append("<br>");
					report.append("Target:"+"<br>");
					for(int m = (k-1)*4;m<k*4;m++)
					{
						if(targets.getItem(m).compareTo("N/A")==0)
						{
							report.append("<li>"+targets.getItem(m)+"</li>");
							break;
						}
						report.append("<li>"+targets.getItem(m)+"</li>");
				
					}
					
					
					report.append("<br>");
					report.append("Results:"+"<br>");
					for(int n = risultato;n<result.getItemCount();n++)
					{
						
						if(result.getItem(n).compareTo("0")==0)
								{
							if(risultato==n)
								report.append("<li>"+"N/A"+"</li>");
									risultato=n+1;
									
									break;
								}
						
						report.append("<li>"+result.getItem(n)+"</li>");
				
					}
					
					
			
					
					report.append("<br>");
					report.append("<li>"+thresh.getItem(k-1)+"</li>");
					report.append("<br>");
					
					report.append("<br>");
					report.append("<li>"+angle.getItem(k-1)+"</li>");
					report.append("<br>");
					
					report.append("<br>");
					report.append("<li>"+gradi.getItem(k-1)+"</li>");
					report.append("<br>");
				
					
					report.append("<br>");
					report.append("<li>"+counterClock.getItem(k-1)+"</li>");
					report.append("<br>");
					
			      report.append("<br>");
					report.append("<li>"+xscale.getItem(k-1)+"</li>");
					report.append("<br>");
					
						report.append("<br>");
					report.append("<li>"+yscale.getItem(k-1)+"</li>");
					report.append("<br>");
				report.append("</ul>");	
			}
			
			
			report.close();
		} 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) {
		
	}
	//catturo l'evento click del mouse
	public void mousePressed(MouseEvent e) 
	{
		
			
			int y,x;
			y = e.getY();
			x=e.getX();
			firstPx=x;
			firstPy=y;
		
	}
	//catturo l'evento pulsante del mouse rilasciato e genero l'area di interesse evidenziata
	public void mouseReleased(MouseEvent e) 
	{
		int y,x,roiX,roiY;
		y = e.getY();
		x=e.getX();
		secondPx=x;
		secondPy=y;
		
		width=Math.abs(secondPx-firstPx);
		heigth=Math.abs(secondPy-firstPy);
		if(firstPx<secondPx)
			roiX=firstPx;
		else
			roiX=secondPx;
		if(firstPy<secondPy)
			roiY=firstPy;
		else
			roiY=secondPy;
		ip.setRoi(roiX,roiY,width,heigth);
		myRoi=ip.getRoi();
				
		
		targetOffsetX=roiX;
		targetOffsetY=roiY;
		
		
	}
	//genero la sorgente con l'area di interesse evidenziata
	public void makeSource() 
	{
		
	
		if(isNumber())
		{
			myRoi=new Rectangle();
			myRoi.x=Integer.parseInt(Xinput.getText());
			myRoi.y=Integer.parseInt(Yinput.getText());
			myRoi.width=Integer.parseInt(Winput.getText());
			myRoi.height=Integer.parseInt(Hinput.getText());
			lista.removeAll();
			lista.add("Source");
			String stringa = "x: " + myRoi.x;
			lista.add(stringa);
			stringa = "y: " + myRoi.y;
			lista.add(stringa);
			stringa = "w: " + myRoi.width;
			lista.add(stringa);
			stringa = "h: " + myRoi.height;
			lista.add(stringa);
			sourceRoi=myRoi;
			ip.setRoi(sourceRoi);
			SourceIp = ip.crop();
			
		}
		else
		if(myRoi!=null)
		{
			lista.removeAll();
			lista.add("Source");
			String stringa = "x: " + myRoi.x;
			lista.add(stringa);
			stringa = "y: " + myRoi.y;
			lista.add(stringa);
			stringa = "w: " + myRoi.width;
			lista.add(stringa);
			stringa = "h: " + myRoi.height;
			lista.add(stringa);
			sourceRoi=myRoi;
			SourceIp = ip.crop();
			
		}
		
		else
			IJ.error("Errore", "Non hai definito una regione di interesse");
	
	}
	
	//genero il target con l'area di interesse evidenziata
	public void makeTarget() 
	{
		if(isNumber())
		{
			myRoi=new Rectangle();
			myRoi.x=Integer.parseInt(Xinput.getText());
			myRoi.y=Integer.parseInt(Yinput.getText());
			myRoi.width=Integer.parseInt(Winput.getText());
			myRoi.height=Integer.parseInt(Hinput.getText());
			listaTarget.removeAll();
			listaTarget.add("Target");
			String stringa = "x: " + myRoi.x;
			listaTarget.add(stringa);
			stringa = "y: " + myRoi.y;
			listaTarget.add(stringa);
			stringa = "w: " + myRoi.width;
			listaTarget.add(stringa);
			stringa = "h: " + myRoi.height;
			listaTarget.add(stringa);
			targetRoi=myRoi;
			ip.setRoi(targetRoi);
			TargetIp = ip.crop();
			
		}
		else
		if(myRoi!=null)
		{
			listaTarget.removeAll();
			listaTarget.add("Target");
			String stringa = "x: " + myRoi.x;
			listaTarget.add(stringa);
			stringa = "y: " + myRoi.y;
			listaTarget.add(stringa);
			stringa = "w: " + myRoi.width;
			listaTarget.add(stringa);
			stringa = "h: " + myRoi.height;
			listaTarget.add(stringa);
			targetRoi=myRoi;
			TargetIp = ip.crop();
			
		}
	
		else 
			IJ.error("Errore", "Non hai definito una regione di interesse");
	
	}
	
	//controllo i valori inseriti manualmente qualora non fossero numerici
	public boolean isNumber()
	{
		
		try 
		{

            Integer.parseInt(Xinput.getText());
            Integer.parseInt(Yinput.getText());
            Integer.parseInt(Winput.getText());
            Integer.parseInt(Hinput.getText());
            
        } 
		catch (NumberFormatException ex) 
		{
            return false;
        }
		return true;
	}
	//gestisco gli eventi di eliminazione della sorgente, target e risultati
	public void clearResult()
	{
		listaResult.removeAll();
		listaResult.add("Result");
		ip.reset();
		img.updateAndDraw();
		source.removeAll();
		targets.removeAll();
		result.removeAll();
		thresh.removeAll();
		angle.removeAll();
		gradi.removeAll();
		xscale.removeAll();
		yscale.removeAll();
		ixscale.removeAll();
		iyscale.removeAll();
		counterClock.removeAll();
		indice=0;
	}
	
	public void clearSource()
	{
		lista.removeAll();
		lista.add("Source");
		SourceIp=null;
		sourceRoi=null;
	}
	
	public void clearTarget()
	{
		listaTarget.removeAll();
		listaTarget.add("Target");
		TargetIp=null;
		targetRoi=null;
	}
}