/*
 * Created on 13 avr. 2005
 */
package geonoteZones;

import geonoteInterface.Interface;
import geonoteTypesDonnees.Arret;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;

import javax.swing.BorderFactory;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextPane;
import javax.swing.JTree;
import javax.swing.ToolTipManager;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

/**
 * @author lefevre
 * partie gauche de la fenetre, contenant l'historique
 */
public class Historique extends JPanel {
	private JTree tree = null;
	private Interface diplomate = null;
	private JScrollPane conteneur = null;
	private boolean selectionListenerActif = true; //permet de "desactiver le TreeSelectionListener pdt l'ajout d'un nd au jtree
	private MyTreeCellRenderer renderer = null;
	private JScrollPane conteneurEcran = null;
	
	/**
	 * redefinition du renderer de l'arbre pour colorer les nds annotés
	 */
	private class MyTreeCellRenderer extends JTextArea implements TreeCellRenderer {
		public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
			DefaultMutableTreeNode dmt = (DefaultMutableTreeNode)value;
			Object o = dmt.getUserObject();
			String text = o.toString();
			setText(text);
			setBackground(Color.WHITE);
			setFont(new Font("Courrier",Font.BOLD,12)); 
			if (sel) {
				setBackground(Color.darkGray);
				setForeground(Color.white);
				//					setToolTipText("COUCOU");
			} else {
				setBackground(tree.getBackground());
            	setForeground(tree.getForeground());
			}
			if (!dmt.isLeaf()) {
				DefaultMutableTreeNode pere = (DefaultMutableTreeNode) dmt.getParent();
				if (pere == null) {
					setBackground(tree.getBackground());
					setForeground(new Color(255,0,0));
				}
				DefaultMutableTreeNode fils = (DefaultMutableTreeNode) dmt.getFirstChild();
				Object oFils = fils.getUserObject();
				String textFils = oFils.toString();
				if (textFils.contains("Annotation")) { 
					if (!sel) {
						setBackground(new Color(168,210,159));
						setForeground(tree.getForeground());
					} else {
						setBackground(Color.darkGray);
						setForeground(Color.white);
					}
				} else {
					int nbFils = dmt.getChildCount();
					boolean aColorer = false;
					while (nbFils>0 && !aColorer) {
						DefaultMutableTreeNode fiston = (DefaultMutableTreeNode) dmt.getChildAt(nbFils-1);
						if (!fiston.isLeaf()) {
							DefaultMutableTreeNode petitFils = (DefaultMutableTreeNode) fiston.getFirstChild();
							if (petitFils != null) {
								Object oPetitFils = petitFils.getUserObject();
								String textPetitFils = (String) oPetitFils.toString();
								if (textPetitFils.contains("Annotation")) { 
									aColorer = true;
								}
							} 
						}
						nbFils--;
					}
					if (aColorer) {
						if (!sel) {
							setBackground(new Color(168,210,159));
							setForeground(tree.getForeground());
						} else {
							setBackground(Color.darkGray);
							setForeground(Color.white);
						}
					} 
				}
			} 
			return this;
		}
	}
	
	/**
	 * Constructeur
	 */
	public Historique(Interface i) {
		super();
		this.setLayout(new BorderLayout());
		diplomate = i;	
		setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
	}
	
	/**
	 * Permet l'affichage d'une annotation sur plusieurs lignes
	 * @param texte
	 * @param fich
	 */
	private void creerEcran(String texte, String fich) {
		if (conteneurEcran != null) remove(conteneurEcran);
		JTextPane ecranAnnotation = new JTextPane();
		ecranAnnotation.setBackground(new Color(168,210,159));
		ecranAnnotation.setText(texte);
		ecranAnnotation.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(fich),BorderFactory.createLineBorder(new Color(168,210,159), 5)));
		ecranAnnotation.setEditable(false);
		conteneurEcran = new JScrollPane(ecranAnnotation);
		conteneurEcran.setPreferredSize(new Dimension(getWidth(), 120));
		conteneur.revalidate();
		add(conteneurEcran, BorderLayout.SOUTH);
		validate();
	}
	
	/**
	 * supprime l'ecran des annotations
	 */
	private void suppEcran() {
		if (conteneurEcran != null) remove(conteneurEcran);
		validate();
	}
	
	/**
	 * Cree un nouvel arbre avec le nom de la racine en parametre 
	 */
	public void creerArbre(String racine) {
		if (conteneur!=null) {
			if (tree != null) {
				conteneur.remove(tree);
			}
			this.remove(conteneur);
		}
		DefaultMutableTreeNode rac = new DefaultMutableTreeNode(racine);
		tree = new JTree(rac);
		tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
		tree.setBorder(BorderFactory.createLineBorder(Color.white, 5));
		tree.setCellRenderer(new MyTreeCellRenderer());
		tree.setVisible(true);
		tree.addTreeSelectionListener( new TreeSelectionListener() {
			public void valueChanged(TreeSelectionEvent e){
				if (selectionListenerActif) {
					DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
					if (node!=null) {
						if (verifExtension(node.getUserObject().toString())) {
							if (node.getParent().toString().equals("Vue(s)")) { 
								String fich = ""; 
								if (node.getUserObject().toString().contains(" ")) fich = node.getUserObject().toString().substring(0, node.getUserObject().toString().indexOf(" "));  
								else fich = node.getUserObject().toString();
								diplomate.afficheNav(fich, "carte"); 
								diplomate.rapportTrace("historique", "affiche vue", fich);  
							} else {
								if (node.getParent().toString().contains("Arr")){ 
									String fich = ""; 
									if (node.getUserObject().toString().contains(" ")) fich = node.getUserObject().toString().substring(0, node.getUserObject().toString().indexOf(" "));  
									else fich = node.getUserObject().toString();
									diplomate.afficheNav(fich, "arret"); 
									diplomate.rapportTrace("historique", "affiche donnee georeferencee", fich);  
								} else {
									if (node.getParent().toString().equals("Documentation")) { 
										String fich = ""; 
										if (node.getUserObject().toString().contains(" ")) fich = node.getUserObject().toString().substring(0, node.getUserObject().toString().indexOf(" "));  
										else fich = node.getUserObject().toString();
										diplomate.afficheDocs(fich);
										diplomate.rapportTrace("historique", "affiche document", fich);  
									} else {
										if (node.getParent().toString().equals("Recherches")) { 
											String fich = ""; 
											if (node.getUserObject().toString().contains(" ")) fich = node.getUserObject().toString().substring(0, node.getUserObject().toString().indexOf(" "));  
											else fich = node.getUserObject().toString();
											diplomate.afficheDocs(fich);
											diplomate.rapportTrace("historique", "affiche recherche", fich);  
										} 
									}
								}
							}
							suppEcran();
						} else {
							//affichage des annotations sur plusieurs lignes ...
							if (node.toString().contains("Annotation")) { 
								String texte = node.toString();
								texte = texte.substring(texte.indexOf(" : ")+3, texte.length()); 
								String fich = ((DefaultMutableTreeNode) node.getParent()).getUserObject().toString();//.substring(0, ((DefaultMutableTreeNode) node.getParent()).getUserObject().toString().indexOf(" "));
								creerEcran(texte ,fich);								
							} else {
								suppEcran();
							}
						}
					}
				}
			}
		});
		tree.addMouseListener( new MouseListener() {
			public void mouseClicked(MouseEvent arg0) {
				if (arg0.getButton()==3) {
					ouvreMenu(arg0.getX(), arg0.getY());
				}
			}
			public void mousePressed(MouseEvent arg0) {
			}
			public void mouseReleased(MouseEvent arg0) {
			}
			public void mouseEntered(MouseEvent arg0) {
			}
			public void mouseExited(MouseEvent arg0) {
			}
		});
		ToolTipManager.sharedInstance().registerComponent(tree);
		conteneur = new JScrollPane(tree);
		conteneur.setBorder(null);
		this.add(conteneur, BorderLayout.CENTER);
		this.validate();
	}
	
	/**
	 * construit le menu des actions possibles sur le nd selectionné
	 * @param x
	 * @param y
	 */
	private void ouvreMenu(int x, int y) {
		TreePath path = tree.getClosestPathForLocation(x, y);
		final DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
		String noeud = node.toString();
		final JPopupMenu menu = new JPopupMenu();
		if (node.isLeaf()) {
			if (noeud.contains(".")) { //si le nom de l'objet contient un "." = possede une extension --> c'est une donnee 
				JMenuItem annoter = new JMenuItem("Annoter"); 
				annoter.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {
						menu.setVisible(false);
						annote(node);
					}			
				});
				menu.add(annoter);
				menu.show(this , x, y);
			} else {
				if (noeud.contains("Annotation")) { 
					JMenuItem modifier = new JMenuItem("Modifier"); 
					modifier.addActionListener(new ActionListener() {
						public void actionPerformed(ActionEvent arg0) {
							menu.setVisible(false);
							modifieAnnotation(node);
						}			
					});
					JMenuItem supprimer = new JMenuItem("Supprimer"); 
					supprimer.addActionListener(new ActionListener() {
						public void actionPerformed(ActionEvent arg0) {
							menu.setVisible(false);
							supprimeAnnotation(node);
						}
					});
					menu.add(modifier);
					menu.add(supprimer);
					menu.show(this , x, y);
				}
			}
		}
	}
	
	/**
	 * supprime l'annotation d'un elt avec confirmation
	 * @param elt
	 */
	private void supprimeAnnotation(DefaultMutableTreeNode elt) {
		selectionListenerActif=false;
		if (elt != null) {
			int res = JOptionPane.showConfirmDialog(diplomate,"Etes-vous sûr ?","Confirmation", JOptionPane.WARNING_MESSAGE);  
			if (res == JOptionPane.YES_OPTION) {
				diplomate.rapportTrace("historique", "suppression annotation", elt.toString());  
				DefaultMutableTreeNode pere = (DefaultMutableTreeNode) elt.getParent();
				pere.remove(elt);
				if (diplomate != null) diplomate.suppAnnotation(elt.toString());
				tree.setModel (new DefaultTreeModel((DefaultMutableTreeNode) tree.getModel().getRoot()));
				tree.expandPath(new TreePath(((DefaultMutableTreeNode) pere.getParent()).getPath()));
			}
		}
		selectionListenerActif=true;
	}
	
	/**
	 * modifie l'annotation d'un elt
	 * @param elt
	 */
	private void modifieAnnotation(DefaultMutableTreeNode elt) {
		selectionListenerActif=false;
		if (elt != null) {
			String saisie = JOptionPane.showInputDialog(diplomate,"Votre texte :","Annotation", JOptionPane.INFORMATION_MESSAGE);  
			if (saisie != null && !saisie.matches("")) { 
				diplomate.rapportTrace("historique", "modification annotation", elt.toString(), "nouvelle annottion : "+saisie);   
				DefaultMutableTreeNode pere = (DefaultMutableTreeNode) elt.getParent();
				pere.remove(elt);
				elt = new DefaultMutableTreeNode("Annotation : "+saisie); 
				pere.add(elt);
				if (diplomate != null) diplomate.modifAnnotation(elt.toString(), saisie);
				tree.setModel (new DefaultTreeModel((DefaultMutableTreeNode) tree.getModel().getRoot()));
				tree.expandPath(new TreePath(pere.getPath()));
			}
		}
		selectionListenerActif=true;
	}
	
	/**
	 * ajoute une annotation à un elt
	 * @param elt
	 */
	private void annote(DefaultMutableTreeNode elt) {
		selectionListenerActif=false;
		if (elt != null) {
			String saisie = JOptionPane.showInputDialog(diplomate,"Votre texte :","Annotation", JOptionPane.INFORMATION_MESSAGE);  
			if (saisie != null && !saisie.matches("")) { 
				diplomate.rapportTrace("historique", "annotation", saisie);  
				DefaultMutableTreeNode annotation = new DefaultMutableTreeNode("Annotation : "+saisie); 
				elt.add(annotation);
				tree.expandPath(new TreePath(elt.getPath()));
				System.out.println( elt.getParent().toString());
				diplomate.annoter(elt.toString(), elt.getParent().toString(), saisie);
			}
		}
		selectionListenerActif=true;
	}
	
	/**
	 * ajoute l'annotation à l'elt correspondant au chemin (normalement lors d'un chargement uniquement)
	 * @param chemin
	 * @param annotation
	 */
	public void ajouteAnnotation(String pere, String chemin, String annotation) {
		selectionListenerActif=false;
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
		DefaultMutableTreeNode eltPere = rechercher(root, pere);
		if (eltPere != null) {
			DefaultMutableTreeNode elt = rechercher(eltPere, chemin);
			if (elt != null) {
				DefaultMutableTreeNode eltAnnotation = new DefaultMutableTreeNode("Annotation : "+annotation); 
				elt.add(eltAnnotation);
			} else {
				System.out.println("Erreur : nd non trouvé"); 
			}
		}
		selectionListenerActif=true;
	}
	
	/**
	 * Verifie qu'un chemin indique un type de fichier supporté
	 */
	private boolean verifExtension(String chemin) {
		return (	chemin.contains(".jpg") || chemin.contains(".JPG") ||  
					chemin.contains(".jpeg") || chemin.contains(".JPEG") ||  
					chemin.contains(".gif") || chemin.contains(".GIF") ||  
					chemin.contains(".png") || chemin.contains(".PNG") ||  
					chemin.contains(".rtf") || chemin.contains(".RTF")  
				);
	}
	
	/**
	 * Ajoute un nd "vue" a l'arbre de l'historique
	 */
	public void ajouterVue(String nomCarte) {
		if (tree != null) {
			selectionListenerActif=false;
			DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
			DefaultMutableTreeNode vues = rechercherN1(root, "Vue(s)"); 
			if (vues == null) {
				vues = new DefaultMutableTreeNode("Vue(s)"); 
				root.add(vues);
			}
			String aChercher;
			if (nomCarte.contains(" ")) { 
				aChercher = nomCarte.substring(0, nomCarte.indexOf(" ")); //pour supprimer la date ! 
			} else {
				aChercher = nomCarte;
			}
			DefaultMutableTreeNode nouvo = rechercherN1(vues, aChercher);
			if (nouvo == null) {
				nouvo = new DefaultMutableTreeNode(nomCarte);
				vues.add(nouvo);
			}
			tree.setModel (new DefaultTreeModel(root));
			tree.expandPath(new TreePath(vues.getPath()));
			selectionListenerActif=true;
		}
	}
	
	/**
	 * recherche seulement ds les fils de la racine
	 */
	private DefaultMutableTreeNode rechercherN1(DefaultMutableTreeNode racine, String cherché) {
		DefaultMutableTreeNode cible = null; //elt recherché
		DefaultMutableTreeNode temp = null;
		boolean trouvé = false;//pour arreter le parcours
		Enumeration enum;
		enum = racine.children();
		while (enum.hasMoreElements()  && !trouvé) {
			temp = (DefaultMutableTreeNode) enum.nextElement();
			if(temp.toString().contains(cherché)){
				cible = temp;
				trouvé = true;
			}
		}
		return cible;
	}
	
	/**
	 * Recherche un nd ds l'arbre et rend null si pas trouvé (RECURSIF)
	 */
	private DefaultMutableTreeNode rechercher(DefaultMutableTreeNode racine, String cherché) {
		DefaultMutableTreeNode cible = null; //elt recherché
		if(racine.toString().equals(cherché)){
			cible = racine;
		} else {
			DefaultMutableTreeNode temp = null;
			boolean trouvé = false;//pour arreter le parcours
			Enumeration enum;
			enum = racine.children();
			while (enum.hasMoreElements()  && !trouvé) {
				temp = (DefaultMutableTreeNode) enum.nextElement();
				cible = rechercher(temp, cherché);
				if (cible != null) {
					trouvé = true;
				}
			}
		}
		return cible;
	}
	
	/**
	 * Ajoute un nd "Docs" 
	 */
	public void ajouterDocs(String donnée) {
		selectionListenerActif = false;
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
		DefaultMutableTreeNode docs = rechercherN1(root, "Documentation"); 
		if (docs == null) { 
			docs = new DefaultMutableTreeNode("Documentation"); 
			root.add(docs);
		}
		String nomFichier = ""; 
		if (donnée.contains(" ")) nomFichier = donnée.substring(0, donnée.indexOf(" ")); //si datée  
		else nomFichier = donnée;
		DefaultMutableTreeNode nouvo = rechercherN1(docs, nomFichier);
		if (nouvo == null) {
			nouvo = new DefaultMutableTreeNode(donnée);
			docs.add(nouvo);
		}
		tree.setModel (new DefaultTreeModel(root));
		tree.expandPath(new TreePath(docs.getPath()));
		selectionListenerActif = true;
	}
	
	/**
	 * ajoute une liste de docs (lors d'un chargement)
	 * @param liste
	 */
	public void ajouterDocs(ArrayList liste) {
		 for(int i=0 ; i<liste.size() ; i++) {
		 	ajouterDocs(liste.get(i).toString());
		 }
	}
	
	/**
	 * ajoute un nd "recherche" contenant les acces aux resultats des recherches 
	 * @param fich
	 */
	public void ajoutRecherche(String fich) {
		selectionListenerActif = false;
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
		DefaultMutableTreeNode rech = rechercherN1(root, "Recherches"); 
		if (rech == null) { 
			rech = new DefaultMutableTreeNode("Recherches"); 
			root.add(rech);
		}
		String nomFichier = ""; 
		if (fich.contains(" ")) nomFichier = fich.substring(0, fich.indexOf(" ")); //si datée  
		else nomFichier = fich;
		DefaultMutableTreeNode nouvo = rechercherN1(rech, nomFichier);
		if (nouvo == null) {
			nouvo = new DefaultMutableTreeNode(fich);
			rech.add(nouvo);
		}
		tree.setModel (new DefaultTreeModel(root));
		tree.expandPath(new TreePath(rech.getPath()));
		selectionListenerActif = true;
	}
	
	/**
	 * rend la liste des nds arrets deja presents ds l'histo
	 */
	private ArrayList rechercheArrets() {
		ArrayList liste = new ArrayList();
		Enumeration enum = ((DefaultMutableTreeNode) tree.getModel().getRoot()).children();
		DefaultMutableTreeNode temp =null;
		while (enum.hasMoreElements()) {
			temp = (DefaultMutableTreeNode) enum.nextElement();
			if (temp.toString().contains("Arr")) { 
				liste.add(temp);
			}
		}
		return liste;
	}
	
	/**
	 * ajoute un nd "arret X" avec les acces aux donnees contenus par l'arret
	 * @param id
	 * @param donnee
	 */
	public void ajoutArret(int id, String donnee) {
		selectionListenerActif = false;
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
		DefaultMutableTreeNode arret = rechercherN1(root, "Arrêt "+id); 
		if (arret == null) { 
			arret = new DefaultMutableTreeNode("Arrêt "+id); 
			ArrayList liste = rechercheArrets();
			Iterator i = liste.iterator();
			int compteur = 2;
			boolean lieuTrouvé = false;
			while (i.hasNext() && !lieuTrouvé) {
				String courant = ((DefaultMutableTreeNode) i.next()).toString();
				int idCourant = Integer.parseInt(courant.substring(courant.indexOf(" ")+1)); 
				if (idCourant<id) {
					compteur++;
				} else {
					lieuTrouvé = true;
				}
			}
			root.insert(arret,compteur);	//ajout du nouvel arret à la bonne place
		}
		String nomFichier = ""; 
		if (donnee.contains(" ")) nomFichier = donnee.substring(0, donnee.indexOf(" "));  
		else nomFichier = donnee;
		DefaultMutableTreeNode nouvo = rechercherN1(arret, nomFichier);
		if (nouvo == null) {
			nouvo = new DefaultMutableTreeNode(donnee);
			arret.add(nouvo);
		}
		tree.setModel (new DefaultTreeModel(root));
		tree.expandPath(new TreePath(arret.getPath()));
		selectionListenerActif = true;
	}
	
	/**
	 * efface ttes les donnees
	 */
	public void reset() {
		if (conteneur!= null) {
			remove(conteneur);
		}
		if (conteneurEcran != null) {
		    remove(conteneurEcran);
		}
		tree = null;
	}
	
	/**
	 * Ajoute un nd "Date"
	 */
	public void ajouterDateSession(String j, String m, String a, String h, String min, String s) {
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
		DefaultMutableTreeNode carte = new DefaultMutableTreeNode("Date de création (session)"); 
		String chaineDate = "le "+j+"/"+m+"/"+a+" (à "+h+"h"+min+"m"+s+")";        
		DefaultMutableTreeNode nouvo = new DefaultMutableTreeNode(chaineDate);
		carte.add(nouvo);
		root.add(carte);
		tree.setModel (new DefaultTreeModel(root));
	}
	
	/**
	 * a partir de la liste des arrets de la session, ajoute les arrets a l'histo (chargement)
	 * @param liste
	 */
	public void chargeArrets(ArrayList liste) {
		selectionListenerActif = false;
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
		DefaultMutableTreeNode temp;
//System.out.println("chargement des arrets");
		Iterator i = liste.iterator();
		while (i.hasNext()) {
			Arret courant = (Arret) i.next();
			//construction du noeud
			temp = new DefaultMutableTreeNode("Arrêt "+courant.getId()); 
			ArrayList listLiens = courant.exporteListeLiens();
			DefaultMutableTreeNode lien;
			Iterator j = listLiens.iterator();
			while (j.hasNext()) {
				lien = new DefaultMutableTreeNode(j.next().toString());
				temp.add(lien);
			}
			//ajout du noeud a la bonne place
			ArrayList listeArrets = rechercheArrets();
			Iterator k = listeArrets.iterator();
			int compteur = 2;
			boolean lieuTrouvé = false;
			while (k.hasNext() && !lieuTrouvé) {
				String temp2 = ((DefaultMutableTreeNode) k.next()).toString();
				int idCourant = Integer.parseInt(temp2.substring(temp2.indexOf(" ")+1)); 
				if (idCourant<courant.getId()) {
					compteur++;
				} else {
					lieuTrouvé = true;
				}
			}
			root.insert(temp,compteur);	//ajout du nouvel arret à la bonne place
		}
		tree.setModel (new DefaultTreeModel(root));
		selectionListenerActif = true;
	}
}
