/*
 * Created on 17 mai 2005
 */
package geonoteTypesDonnees;

import geonoteInterface.Interface;
import geonoteOutils.Reglet;

import java.awt.AlphaComposite;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;

import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;

/**
 * @author lefevre
 * affiche et gere une image et ses fonctionnalités
 */
public class Images extends JComponent implements MouseListener,MouseMotionListener,MouseWheelListener {

	protected String chemin = null;
	protected /*ImageIcon*/MonImageIcon image = null;

	protected double zoom = 1;	//facteur de zoom
	protected double echelle = 1; //echelle de la carte/donnee
	protected Reglet reglet = null;
	protected boolean regletDispo = true; //pour activer la fonction reglet a la creation
	protected boolean zoomActif = true; //pour activer la fonction zoom a la creation
	protected Interface diplomate = null;
	protected String unité = "m";	//unité de mesure
	protected Cursor curseurDefaut = Cursor.getDefaultCursor();
	
	protected boolean regletActif = false; //pour activer/desactiver l'affichage du reglet suivant les actions de l'util
	protected boolean modeEdition = false;
	protected boolean deplacement = false;
	
	/**
	 * @author lefevre
	 * JPanel permettant l'affichage d'une ImageIcon avec un facteur de transparence
	 */
	protected class MonImageIcon extends JPanel {
		private String chemin = "";
		private float transparency = 1.0f;	//100% d'opacité par defaut (0% de transparence ;)
		private ImageIcon ii = null;
		public MonImageIcon(String path) {
			chemin = path;
			ii = new ImageIcon (path);
		}
		public String getChemin() {
			return chemin;
		}
		public double getIconHeight() {
			return ii.getIconHeight();
		}
		public double getIconWidth() {
			return ii.getIconWidth();
		}
		public Image getImage() {
			return ii.getImage();
		}
		public ImageIcon getIi() {
			return ii;
		}
		public void setTransparency(float aTransparency) {
			transparency = aTransparency;
			if (transparency<0.0f) transparency = 0.0f;
			if (transparency>1.0f) transparency = 1.0f;
		}
		public float getTransparency() {
			return transparency;
		}
		public void paint(Graphics2D g) {
			g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, transparency));
			g.drawImage(ii.getImage(), new AffineTransform(), null);
		}
	}
	
	/**
	 * Constructeur
	 * @param path
	 */
	public Images(String path, double ech, String unit, boolean regletDisp, boolean zoomDisp, boolean modeEd, Interface i) {
		image = new MonImageIcon(path);
		chemin = path;
		echelle = ech;
		unité = unit;
		regletDispo = regletDisp;
		zoomActif = zoomDisp;
		modeEdition = modeEd;
		diplomate = i;
		reglet = new Reglet(modeEdition);
		zoom = 1;
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
		this.addMouseWheelListener(this);
		if (modeEdition) curseurDefaut = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
	}

	public String getChemin() {
		return chemin;
	}

	public void setUnité(String u) {
		unité = u;
	}

	public void setEchelle(double e) {
		echelle = e;
	}
	
	/**
	 * redefinition de la methode d'affichage
	 * @param g
	 * @param zoom
	 */
	public void paint(Graphics g) {
//		super.paint(g);
		Graphics2D g2 = (Graphics2D) g;
		/* Demande de rendu rapide */
		g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
		g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED);
		g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
		g2.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
		/* Lissage du texte et des dessins */
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
		double rapportH = (double) this.getParent().getHeight()/image.getIconHeight();
		double rapportL = (double) this.getParent().getWidth()/image.getIconWidth();
		double min = Math.min(rapportH, rapportL);
		if (zoom == 1) zoom = min;
		int largImage = (int) (image.getIconWidth()*zoom);
		int hautImage = (int) (image.getIconHeight()*zoom);
		Dimension dimension = null;
		//dimensionnement du composant pour permettre la mise a jour des scrollbars
		if (largImage>this.getParent().getWidth() && hautImage>this.getParent().getHeight()) {
			dimension = new Dimension(largImage,hautImage);
		} else {
			if (largImage>this.getParent().getWidth()) {
				dimension = new Dimension(largImage, this.getParent().getHeight());
			} else {
				if (hautImage>this.getParent().getHeight()) {
					dimension = new Dimension(this.getParent().getWidth(), hautImage);
				} else {
					dimension = new Dimension(this.getParent().getSize());
					zoom = min;
				}
			}
		}
		g2.scale(zoom, zoom);
		image.paint(g2);
		if (this.getSize()!= dimension) {
			this.setPreferredSize(dimension);
			this.setSize(dimension);
		}
		
//		int decalHaut = 0;//(int) ((getHeight()-hautImage)/(2*zoom)); //INUTILE MAINTENANT
//		int decalLarg = 0;//(int) ((getWidth()-largImage)/(2*zoom));
//		g2.drawImage(image.getImage(), decalLarg, decalHaut, this); //FAIT RAMER !!! et en trop (deja dessinée)
		
		//affichage du reglet
		if ((regletDispo) && (regletActif)) {
			reglet.draw(g2,zoom, echelle, unité/*, decalLarg, decalHaut*/);
		}
		g2.dispose();
	}

	/**
	 * @return the image.
	 */
	public ImageIcon getImage() {
		return image.getIi();
	}
	
	public void mouseClicked(MouseEvent arg0) {
	}

	public void mouseReleased(MouseEvent arg0) {
		if (regletDispo){
			if ((modeEdition) && SwingUtilities.isRightMouseButton(arg0) && reglet.getLongueur()>0) {
				//ajout de l'echelle en edition
				diplomate.ajouteEchelle(reglet.getLongueur(), "image");
			}
			regletActif=false;
			diplomate.rapportTrace("reglet","fin");
			repaint();
		}
		deplacement = false;
		setCursor(curseurDefaut);
		diplomate.rapportTrace("image", "deplacement", "fin");
	}
	
	public void mouseEntered(MouseEvent arg0) {
	}
	
	public void mouseExited(MouseEvent arg0) {
	}
	
	//variables necessaires au deplacement de l'image
	private int ancienX;
	private int ancienY;
	private int ancienVX;
	private int ancienVY;
	
	public void mousePressed(MouseEvent arg0) {
		if (SwingUtilities.isRightMouseButton(arg0)) {
			if (regletDispo && modeEdition) {
				regletActif=true;
				reglet.setModeEcriture(true);
				setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
				reglet.setDepart((int)(arg0.getX()/zoom),(int)(arg0.getY()/zoom));
				reglet.setArrivée((int)(arg0.getX()/zoom),(int)(arg0.getY()/zoom));
				diplomate.rapportTrace("reglet","depart", "edition");
			} else {
				//mode deplacement
				JScrollPane scroll = (JScrollPane) ((JViewport) getParent()).getParent();
				ancienX = arg0.getX();
				ancienY = arg0.getY();
				ancienVX = scroll.getHorizontalScrollBar().getValue();
				ancienVY = scroll.getVerticalScrollBar().getValue();
				deplacement = true;
				diplomate.rapportTrace("image","deplacement");
			}
		} else {
			if (SwingUtilities.isLeftMouseButton(arg0)) {
				if (regletDispo) {
					regletActif=true;
					reglet.setModeEcriture(false);
					setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
					reglet.setDepart((int)(arg0.getX()/zoom),(int)(arg0.getY()/zoom));
					reglet.setArrivée((int)(arg0.getX()/zoom),(int)(arg0.getY()/zoom));
					diplomate.rapportTrace("reglet","depart");
				}
			}
		}
	}
	
	public void mouseDragged(MouseEvent arg0) {
		if (deplacement) {
			setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
			JScrollPane scroll = (JScrollPane) ((JViewport) getParent()).getParent(); //recup du contenant
			//calcul du deplacement du pointeur
			int diffX = (int) ((arg0.getX() - ancienX)*0.8);
			int diffY = (int) ((arg0.getY() - ancienY)*0.8);

			//repositionnement de l'espace visible
			scroll.getVerticalScrollBar().setValue(ancienVY+diffY);
			scroll.getHorizontalScrollBar().setValue(ancienVX+diffX);

			//mise a jour des variables
			ancienX = arg0.getX();
			ancienY = arg0.getY();
			ancienVX = scroll.getHorizontalScrollBar().getValue();
			ancienVY = scroll.getVerticalScrollBar().getValue();
		}
		if (regletDispo){	//pour rafraichir la position du reglet (evite les sauts du reglet)
			reglet.setArrivée((int)(arg0.getX()/zoom),(int)(arg0.getY()/zoom));
			repaint();
		}
	}
	
	public void mouseMoved(MouseEvent arg0) {
	}
	
	public void mouseWheelMoved(MouseWheelEvent arg0) {
		if (zoomActif) {
			JScrollPane scroll = (JScrollPane) ((JViewport) getParent()).getParent(); //recup du contenant
			//position du pointeur par rapport a l'espace visible
			int larg = arg0.getX()-scroll.getHorizontalScrollBar().getValue();
			int haut = arg0.getY()-scroll.getVerticalScrollBar().getValue();
			
			//coord du pointeur sur la carte (coord absolues/rapport de zoom)
			int x = (int) (arg0.getX()/zoom);
			int y = (int) (arg0.getY()/zoom);
			
			//modif du facteur de zoom
			double facteurTemp = zoom - arg0.getWheelRotation()*0.05;
			if ((facteurTemp>0.10)&&(facteurTemp<4)) {
				zoom = facteurTemp;	
			} else {
				//butées du zoom
				if (arg0.getWheelRotation()>0) {
					zoom = 0.10;
				} else {
					zoom = 4;
				}
			}	//fin modif
			
			//coord absolues (voulues) du pointeur avec le nouvo zoom !
			int absX = (int) (x*zoom);
			int absY = (int) (y*zoom);
			
			//repositionnement de l'espace visible
			scroll.getHorizontalScrollBar().setValue(absX-larg);
			scroll.getVerticalScrollBar().setValue(absY-haut);
		}
		if (regletDispo){ //pour rafraichir la position du reglet (evite les sauts du reglet)
			reglet.setArrivée((int)(arg0.getX()/zoom),(int)(arg0.getY()/zoom));
		}
		repaint();
	}

	public void setRegletDispo(boolean b) {
		regletDispo = b;
	}
	
	/**
	 * @return Returns the unité.
	 */
	public String getUnité() {
		return unité;
	}
}
