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

import geonoteInterface.BarreEtat;
import geonoteInterface.FenetreCalibrageCoord;
import geonoteInterface.Interface;
import geonoteOutils.TraceurCarte;

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;

/**
 * @author lefevre
 * affiche et gere une carte et ses fonctionnalités (herite de la classe Images)
 */
public class Carte extends Images {
	private double echelleLat = 1;
	private double echelleLong = 1;
	
	//	variables permettant le calcul des coordonnees geo
	private int latitude1 = -1;
	private int latitude2 = -1;
	private int latitudeOrigine = 0;
	
	private ArrayList listeArrets = null;
	private int longitude1 = -1;
	private int longitude2 = -1;
	private int longitudeOrigine = 0;
	private boolean pointeurIN = false;
	private boolean modeDefCoord = false; //mode de definition des coord geo
	private int x1 = -1;
	private int x2 = -1;
	private int xCourant; //pour l'affichage des coord suivant le pointeur
	private int y1 = -1;
	private int y2 = -1;
	private int yCourant;
	private FenetreCalibrageCoord fcc = null;
	
	private MonImageIcon vue = null;
	private boolean reglageTransparence = false;
	private Color couleurArrets = Color.WHITE;
	private String cheminMeta = "";	//conserve le chemin du fichier de metadonnees de la carte en cours
	
	/**
	 * constructeur
	 * @param path
	 * @param ech
	 * @param unit
	 * @param regletDisp
	 * @param zoomDisp
	 * @param modeEd
	 * @param i
	 * @param list
	 * @param latO
	 * @param longO
	 * @param echLat
	 * @param echLong
	 */
	public Carte(String path, double ech, String unit, boolean regletDisp, boolean zoomDisp, boolean modeEd, Interface i, ArrayList list, int latO, int longO, double echLat, double echLong, String couleurArrets) {
		super(path, ech, unit, regletDisp, zoomDisp, modeEd, i);
		cheminMeta = path;
		listeArrets = new ArrayList();
		latitudeOrigine = latO;
		longitudeOrigine = longO;
		echelleLat = echLat;
		echelleLong = echLong;
		String[] rvb = couleurArrets.split(" ");
		this.couleurArrets = new Color(Integer.parseInt(rvb[0]), Integer.parseInt(rvb[1]), Integer.parseInt(rvb[2]));
		if (list != null) listeArrets.addAll(list);
		if (modeEdition) curseurDefaut = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
	}
		
	/**
	 * indique si l'id est deja present ds la liste des arrets
	 * @param id
	 * @return
	 */
	private boolean present(int id) {
		boolean présent = false;
		int i = 0;
		while (i<listeArrets.size() && !présent) {
			Arret courant = (Arret) listeArrets.get(i);
			int idC = courant.getId();
			if (id == idC) {
				présent = true;
			}
			i++;
		}
		return présent;
	}
	
	private int rechercheIdLibreMin() {
		int id = 1;
		boolean trouvé = false;
		while (!trouvé) {
			if (present(id) == false) {
				trouvé = true;
			} else {
				id++;
			}
		}
		return id;
	}
	
	/**
	 * Construit un arret et l'ajoute à la liste de la carte 
	 * @param x
	 * @param y
	 */
	public void ajoutArret(int x, int y) {
		if (modeEdition) {
			Arret rech = recherche(x,y);
			if (rech == null) {
				int id = rechercheIdLibreMin();
				Arret arretCourant = new Arret(id, x, y);
				diplomate.ajouteArretCarte(id,x,y);
				listeArrets.add(arretCourant);
			} else {
				ArrayList retour = diplomate.ajouteDonneeCarte(rech.getId());
				if (!retour.isEmpty()) {
					rech.ajouteLien((String) retour.get(0), (String) retour.get(1));
				}
				//				System.out.println("collision !");
			}
		}
	}
	
	public void ajouteCoord(int x, int y, int latitudeTemp, int longitudeTemp) {
		if (x1==-1 && y1==-1) { //premier point
			x1 = x;
			y1 = y;
			latitude1 = latitudeTemp;
			longitude1 = longitudeTemp;
		} else { //deuxieme point
			if (x2==-1 && y2==-1) {
				x2 = x;
				y2 = y;
				latitude2 = latitudeTemp;
				longitude2 = longitudeTemp;
				//CALCULS :
				if ((x2-x1) != 0) {
					echelleLat = (longitude2 - longitude1)/(x2-x1);
				} else {
					echelleLat = 0;
				}
				if ((y2-y1) != 0) {
					echelleLong = (latitude2 - latitude1)/(y2-y1);
				} else {
					echelleLong = 0;
				}
				longitudeOrigine = (int) (longitude1 - (x1*echelleLong));
				latitudeOrigine = (int) (latitude1 - (x1*echelleLat));
				diplomate.ajouteCoordonnees(latitudeOrigine, longitudeOrigine, echelleLat, echelleLong);
				diplomate.rapportTrace("carte","ajout coordonnees");
				modeDefCoord = false;
			}
		}
	}
	
	//	redefinition d'une methode du listener pour integrer l'ajout d'arrets
	public void mouseClicked(MouseEvent arg0) {
		if (SwingUtilities.isLeftMouseButton(arg0)) {
			if (modeEdition && modeDefCoord && ((x1==-1 && y1==-1) || (x2==-1 && y2==-1))) {
				if (fcc == null || !fcc.isVisible()) {
					if ((x1==-1 && y1==-1)) fcc = new FenetreCalibrageCoord(this, "Premier point", arg0.getX(), arg0.getY());
					else fcc = new FenetreCalibrageCoord(this, "Deuxième point", arg0.getX(), arg0.getY());
				}
			} else {
				if (diplomate.isModeSuppArret()) {
					suppArret((int) (arg0.getX()/zoom),(int) (arg0.getY()/zoom));
					diplomate.rapportTrace("carte","suppression arret");
				} else {
					ajoutArret((int) (arg0.getX()/zoom),(int) (arg0.getY()/zoom));
					diplomate.rapportTrace("carte","ajout arret");
				}
			}
			repaint();
		} else {
			if (SwingUtilities.isRightMouseButton(arg0) && diplomate.getAAA()) {
				ouvertureArret((int) (arg0.getX()/zoom),(int) (arg0.getY()/zoom));
				repaint();
			}
		}
	}
	
	public void mousePressed(MouseEvent arg0) {
		super.mousePressed(arg0);
		xCourant = (int) (arg0.getX()/zoom);
		yCourant = (int) (arg0.getY()/zoom);
		if (SwingUtilities.isRightMouseButton(arg0)) {
			reglageTransparence = true;
			String temp = Float.toString(image.getTransparency()*100);
			String transparence = temp.substring(0, temp.indexOf("."))+"%"; //formattage
			BarreEtat.afficheDroite("Transparence : "+transparence);
			repaint();
		}
	}
	
	public void mouseDragged(MouseEvent arg0) {
		super.mouseDragged(arg0);
		xCourant = (int) (arg0.getX()/zoom);
		yCourant = (int) (arg0.getY()/zoom);
	}
	
	public void mouseEntered(MouseEvent arg0) {
		pointeurIN = true;
	}
	public void mouseExited(MouseEvent arg0) {
		pointeurIN = false;
		repaint();
	}
	
	public void mouseMoved(MouseEvent arg0) {
		xCourant = (int) (arg0.getX()/zoom);
		yCourant = (int) (arg0.getY()/zoom);
		Arret rech = recherche(xCourant, yCourant);
		if (rech != null && diplomate.getAAA()) {//		verif de la presence d'un arret sous le pointeur
			if (diplomate.isModeSuppLien() || diplomate.isModeSuppArret()) setCursor(diplomate.suppCurseur);
			else setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
			repaint();
		} else {
			setCursor(curseurDefaut);
			repaint();
		}
		xCourant = (int) (arg0.getX()/zoom);//pour eviter les sauts
		yCourant = (int) (arg0.getY()/zoom);
	}
	
	public void mouseReleased(MouseEvent arg0) {
		if (regletDispo){
			if ((modeEdition) && SwingUtilities.isRightMouseButton(arg0) && reglet.getLongueur()>0) {
				diplomate.ajouteEchelle(reglet.getLongueur(), "carte");
				diplomate.rapportTrace("carte","ajout echelle");
			}
			regletActif=false;
			BarreEtat.resetDroite();
			setCursor(curseurDefaut);
			diplomate.rapportTrace("reglet","fin");
			repaint();
		}
		deplacement = false;
		xCourant = (int) (arg0.getX()/zoom);//pour eviter les sauts
		yCourant = (int) (arg0.getY()/zoom);
		if (reglageTransparence) {
			reglageTransparence = false;
			BarreEtat.resetDroite();
		}
	}
	
	/**
	 * pour masquer la vue principale qd une vue secondaire est selectionnée ds l'histo
	 */
	public void masquerCarte() {
		image.setTransparency(0.0f);
	}
	
	public void mouseWheelMoved(MouseWheelEvent arg0) {
		if (reglageTransparence) {
			image.setTransparency((float) (image.getTransparency()-arg0.getWheelRotation()*0.05));
			String temp = Float.toString(image.getTransparency()*100);
			String transparence = temp.substring(0, temp.indexOf("."))+"%"; //formattage
			BarreEtat.afficheDroite("Transparence : "+transparence);
			repaint();
		} else {
			super.mouseWheelMoved(arg0); //zoom sur la carte
		}
		xCourant = (int) (arg0.getX()/zoom);//pour eviter les sauts
		yCourant = (int) (arg0.getY()/zoom);
	}
	
	/**
	 * detecte la presence d'un arret aux coord passees et ouvre son menu 
	 */
	private void ouvertureArret(int x, int y) {
		final Arret arret = recherche(x,y);
		if (arret != null) {
			//ouverture des metadonnees de la carte pour connaitre les donnees accessibles
			TraceurCarte tr = new TraceurCarte();
			String extension = cheminMeta.substring(cheminMeta.lastIndexOf("."));
			String cheminXML = cheminMeta.replace(extension, ".xml");
			tr.charger(cheminXML);
			final JPopupMenu menu = new JPopupMenu("Données disponibles :");
			ArrayList liste = arret.exporteListeLiens();
			Iterator i = liste.iterator();
			if (liste.isEmpty()) {
				menu.add(new JMenuItem("VIDE"));
			} else {
				while (i.hasNext()) {
					ArrayList listeDonneesPourUnType = (ArrayList) i.next();
					Iterator it = listeDonneesPourUnType.iterator();
					final String type = (String) it.next();
					JMenu item = new JMenu(type);	//construction du sous menu en fonction du type
					while (it.hasNext()) {
						final String fich = (String) it.next();
						JMenuItem fichItem = new JMenuItem(fich);
						fichItem.addActionListener(new ActionListener() {
							public void actionPerformed(ActionEvent arg0) {
								if (diplomate != null) {
									if (!modeEdition) {	//en mode edition, on ne peut pas visionner les donnees
										diplomate.afficheNav(fich,"arret");
										diplomate.ajoutArretHisto(arret.getId(), fich);
										diplomate.rapportTrace("carte", "ouverture donnee georeferencee", fich);
									} else {
										if (diplomate.isModeSuppLien()) {
											arret.suppLien(fich, type);
											diplomate.suppLienEffectue(arret.getId(), fich);
											diplomate.rapportTrace("carte", "suppression lien", "arret "+arret.getId(), "lien : "+fich);
										}
									}
								}
								menu.setVisible(false);
							}
						});
						item.add(fichItem);
						System.out.println();
						if (!modeEdition) fichItem.setEnabled(tr.exporteEtat(fich).equals("accessible"));
					}
					menu.add(item);
				}
			}
			menu.show(this, (int) (x*zoom), (int) (y*zoom));
		}
	}
	
	/**
	 * redefinition de la methode d'affichage (complete pour afficher arrets en dessous du reglet !)
	 * @param g
	 * @param zoom
	 */
	public void paint(Graphics 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);
		g2.setStroke(new BasicStroke( (float) (1.0f/zoom) ));
		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;
		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 {
					//si la carte est plus petite que la zone d'affichage
					dimension = new Dimension(this.getParent().getSize());
					zoom = min;
				}
			}
		}
		g2.scale(zoom, zoom);
		if (vue != null) {
			vue.paint(g2);
		}
		image.paint(g2);
		if (this.getSize()!= dimension) {
			this.setPreferredSize(dimension);
			this.setSize(dimension);
		}
		
//		int decalHaut = 0;//(int) ((getHeight()-hautImage)/(2*zoom));
//		int decalLarg = 0;//(int) ((getWidth()-largImage)/(2*zoom));
//		g2.drawImage(image.getImage(), decalLarg, decalHaut, this); //FAIT RAMER !!! et en trop (deja dessinée)

		//affichage des arrets
		if ((!listeArrets.isEmpty()) && (diplomate.getAAA())) {
			for(int i=0 ; i<listeArrets.size(); i++) {
				Arret temp = (Arret) listeArrets.get(i);
				temp.draw(g2, zoom, couleurArrets/*, decalLarg, decalHaut*/);
			}
		}
		int xAff = (int) (xCourant+10/zoom);
		int yAff = (int) (yCourant+10/zoom);
		if (reglageTransparence) { //affichage du pourcentage de transparence (REALISE AVEC LA MOLETTE !!)
//			g2.setColor(Color.black);
//			g2.drawRect(xAff, yAff, (int) (45/zoom), (int) (18/zoom));
//			g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f));
//			g2.setColor(Color.white);
//			g2.fillRect(xAff, yAff, (int) (45/zoom), (int) (18/zoom));
//			g2.setColor(Color.black);
//			g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
//			String temp = Float.toString(image.getTransparency()*100);
//			String transparence = temp.substring(0, temp.indexOf("."))+"%"; //formattage
//			g2.drawString(transparence, (int) (xAff+(3/zoom)), (int) (yAff+(14/zoom)));
		}
		
		if ((regletDispo) && (regletActif)) {
			reglet.draw(g2,zoom, echelle, unité/*, decalLarg, decalHaut*/);
		}
		//affichage des coordonnées
		if (/*(!regletActif) &&*/ diplomate.getACA() && pointeurIN) {
			g2.setStroke(new BasicStroke( (float) (1.0f/zoom) ));
			g2.setColor(Color.white);
			g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f ));
			g2.fillRect(xAff, yAff, (int) (110/zoom), (int) (25/zoom));
			g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f ));
			g2.setColor(Color.black);
			g2.drawRect(xAff, yAff, (int) (110/zoom), (int) (25/zoom));
			if (modeEdition && modeDefCoord && ((x1==-1 && y1==-1) || (x2==-1 && y2==-1))) {
				g.setFont(new Font("Courrier", 0,(int) (15/zoom)));
				String texte = "";
				if (x1==-1 && y1==-1) {
					texte = "Premier point";
				} else if (x2==-1 && y2==-1) texte = "Deuxieme point";
				g2.drawString(texte, (int) (xAff+(3/zoom)), (int) (yAff+(18/zoom)));
			} else {
				int longitude = (int) (longitudeOrigine + xCourant*echelleLong);
				int latitude = (int) (latitudeOrigine + yCourant*echelleLat);
				int degres = latitude/3600;
				int minutes = (latitude-degres*3600)/60;
				int secondes = latitude-degres*3600-minutes*60;
				g.setFont(new Font("Courrier", 0,(int) (10/zoom)));
				g2.drawString("Latitude : "+Integer.toString(degres)+"°"+Integer.toString(minutes)+"'"+Integer.toString(secondes)+"\"", (int) (xAff+(3/zoom)), (int) (yAff+(23/zoom)));
				degres = longitude/3600;
				minutes = (longitude-degres*3600)/60;
				secondes = longitude-degres*3600-minutes*60;
				g2.drawString("Longitude : "+Integer.toString(degres)+"°"+Integer.toString(minutes)+"'"+Integer.toString(secondes)+"\"", (int) (xAff+(3/zoom)), (int) (yAff+(11/zoom)));
			}
		}
		g2.dispose();
	}
	
	/**
	 * fait passer l'image de la vue vers la carte
	 */
	public void VueVersCarte() {
		if (vue != null) {
			image = vue;
			chemin = vue.getChemin();
		}
	}
	
	public void chargerCouleurArrets(String coul) {
	    String[] rvb = coul.split(" ");
		couleurArrets = new Color(Integer.parseInt(rvb[0]), Integer.parseInt(rvb[1]), Integer.parseInt(rvb[2]));
	}
	
	/**
	 * charge une vue
	 * @param path
	 */
	public void chargerVue(String path) {
		vue = new MonImageIcon(path);
		repaint();
	}
	
	/**
	 * recherche dans la liste des arrets un arret ayant les coordonnees passees
	 * @return
	 */
	private Arret recherche(int x, int y) {
		Arret cible = null;
		boolean trouve = false;
		int i=0;
		while ((i< listeArrets.size()) && (!trouve)) {
			Arret temp = (Arret) listeArrets.get(i);
			if ( (x >= temp.getX()-temp.getDiametre()/(2*zoom))
					&& (x <= temp.getX()+temp.getDiametre()/(2*zoom))
					&& (y >= temp.getY()-temp.getDiametre()/(2*zoom))
					&& (y <= temp.getY()+temp.getDiametre()/(2*zoom))
			) {
				cible = temp;
				trouve = true;
			}
			i++;
		}
		return cible;
	}
	
	/**
	 * supprime un arret
	 * @param x
	 * @param y
	 */
	private void suppArret(int x, int y) {
		if (modeEdition) {
			Arret rech = recherche(x,y);
			if (rech != null) {
				listeArrets.remove(rech);
				diplomate.suppArretEffectue(rech.getId());
				diplomate.rapportTrace("carte", "suppression arret", "arret "+rech.getId());
			}
		}
	}
	
	public void activerModeDefCoord() {
		this.modeDefCoord = true;
	}
	
	public void desactiverModeDefCoord() {
		modeDefCoord = false;
	}
	
	public String exporteCheminCarte() {
		return chemin;
	}
	
	public String exporteCheminVue() {
		if (vue == null) return null;
		else return vue.getChemin();
	}
}
