package Modèle;
//
/**
 * 	Generated by StarUML(tm) Java Add-In
 *
 *	@ Project : OptimEisti
 * 	@ File Name : DonneesXML.java
 * 	@ Date : 25/04/2011
 * 	@ Author : Casey Alexandre, Collasse Emilie, Fong cynthia, Gauquelin Benoit
 *
*/

import java.io.File;
import java.io.IOException;
import java.util.Vector;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

public class DonneesXML {
	protected Document arbreUtilisateur;
	protected Document arbrePb;
	protected boolean isValid;
	static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
	static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
	static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";

	public DonneesXML() {
		chargerDonnees();
		if(validXML("Data/Utilisateurs.xml","Data/Utilisateurs.xsd"))
			System.out.println("Le XML des utilisateurs a été validé par le schéma XSD");
		if(validXML("Data/Problemes.xml","Data/Problemes.xsd"))
			System.out.println("Le XML des problèmes a été validé par le schéma XSD");
	}
/**
 * Fonction permettant de récuperer des données XML dans la base de données
 */

	public void chargerDonnees() {
		try {
			DocumentBuilderFactory fabrique1 = DocumentBuilderFactory.newInstance();
			DocumentBuilderFactory fabrique2 = DocumentBuilderFactory.newInstance();
			DocumentBuilder db1 = fabrique1.newDocumentBuilder();
			DocumentBuilder db2 = fabrique2.newDocumentBuilder();
			File f1 = new File("Data/Utilisateurs.xml");
			if (!f1.exists()) {
				// Le fichier des sessions n'existe pas. On crée un arbre
				// toutesLesSessions avec aucune session
				// On crée en mémoire vive un document qui est donc un arbre
				// vide
				arbreUtilisateur = db1.newDocument();

				// On crée un élément en précisant le nom de la balise
				Element e = arbreUtilisateur.createElement("Utilisateurs");
				// On l'accroche au document. Il devient donc la racine de
				// l'arbre xml
				arbreUtilisateur.appendChild(e);
			}
			else {
				// On charge en mémoire vive l'arbre de l'ensemble des sessions
				arbreUtilisateur = db1.parse(f1);
			}
			File f2 = new File("Data/Problemes.xml");
			if (!f2.exists()) {
				// Le fichier des sessions n'existe pas. On crée un arbre
				// toutesLesSessions avec aucune session
				// On crée en mémoire vive un document qui est donc un arbre
				// vide
				arbrePb = db2.newDocument();

				// On crée un élément en précisant le nom de la balise
				Element e = arbrePb.createElement("Problemes");
				// On l'accroche au document. Il devient donc la racine de
				// l'arbre xml
				arbrePb.appendChild(e);
			}
			else {
				// On charge en mémoire vive l'arbre de l'ensemble des sessions
				arbrePb = db2.parse(f2);
			}
		} catch (Exception e) {
			System.out.println("Erreur de création ou de chargement des arbres xml : " + e);
		}
	}
/**
 * Affiche l'arbre XLM des Utilisateurs
 */
	public void afficherXMLUtilisateur() {
		try {
			Element e = arbreUtilisateur.getDocumentElement();
			NodeList nl = e.getChildNodes();
			afficherNoeud(nl);
		} catch (Exception e) {
			System.out.println("Erreur de lecture de l'arbre XML Utilisateur" + e);
		}
	}

	/**
	 * Affiche l'arbre XML des problèmes
	 */
	public void afficherXMLProblemes() {
		try {
			Element e = arbrePb.getDocumentElement();
			NodeList nl = e.getChildNodes();
			afficherNoeud(nl);
		} catch (Exception e) {
			System.out.println("Erreur de lecture de l'arbre XML Utilisateur" + e);
		}
	}

	/**
	 * Affiche le noeud demandé
	 * @param nl: nom du noeud a afficher
	 */
	public void afficherNoeud(NodeList nl) {
		try {
			int i, j;
			for (i = 0; i < nl.getLength(); i++) {
				Node n = nl.item(i);
				switch (n.getNodeType()) {
					case Node.TEXT_NODE:
						if (!n.getNodeValue().contains("\n"))
							System.out.println(n.getNodeValue());
					break;
					case Node.ELEMENT_NODE:
						System.out.println(n.getNodeName());
						if (n.getAttributes().getLength() != 0)
							System.out.println("Liste des attributs");
						for (j = 0; j < n.getAttributes().getLength(); j++) {
							Node nf = n.getAttributes().item(j);
							System.out.println(nf.getNodeName() + " : " + nf.getNodeValue());
						}
					break;
					case Node.COMMENT_NODE:
						System.out.println("<!-- " + n.getNodeValue() + " -->");
					break;
				}
				if (n.getChildNodes().getLength() != 0)
					afficherNoeud(n.getChildNodes());
			}
		} catch (Exception e) {
			System.out.println("Erreur de lecture de l'arbre XML Utilisateur" + e);
		}
	}

	/**
	 * Récupère le problème demander
	 * @param d : Nom du problème
	 * @return : ??????????
	 */
	public Vector<Probleme> getPb(Document d) {
		Vector<Probleme> vPb = new Vector<Probleme>();
		Element e = d.getDocumentElement();
		NodeList nl = e.getChildNodes();
		Probleme p;
		for (int i = 0; i < nl.getLength(); i++) {
			if (nl.item(i).getNodeName().equals("Probleme")) {
				p = new Probleme(nl.item(i).getAttributes().item(0).getNodeValue());
				NodeList comp = nl.item(i).getChildNodes();
				for (int j = 0; j < comp.getLength(); j++) {
					if (comp.item(j).getNodeName().equals("Variable")) {
						Variable v = new Variable(comp.item(j).getNodeValue(), null);
						p.ajoutVar(v);
					}
					if (comp.item(j).getNodeName().equals("FctObj")) {
						FonctionObjectif f;
						NamedNodeMap attFct = comp.item(j).getAttributes();
						if (comp.item(j).getAttributes().item(0).getNodeName().equals("objectif")) {
							f = new FonctionObjectif(attFct.item(0).getNodeValue(), attFct.item(1).getNodeValue());
						}
						else {
							f = new FonctionObjectif(attFct.item(1).getNodeValue(), attFct.item(0).getNodeValue());
						}
						p.setFctObj(f);
					}
					if (comp.item(j).getNodeName().equals("Contrainte")) {
						Contrainte c = new Contrainte(comp.item(j).getAttributes().item(0).getNodeValue());
						p.ajoutContr(c);
					}
					if (comp.item(j).getNodeName().equals("Resultat")) {
						Resultat r;
						Vector<Variable> vectVar = new Vector<Variable>();
						NodeList rList = comp.item(j).getChildNodes();
						Double meilleurOpt = 0.0;
						for (int k = 0; k < rList.getLength(); k++) {
							if (rList.item(k).getNodeName().equals("Variable2")) {
								Variable v = new Variable(rList.item(k).getTextContent().substring(0, rList.item(k).getTextContent().indexOf('=')), Double.parseDouble(rList.item(k).getTextContent().substring(rList.item(k).getTextContent().indexOf('=') + 1, rList.item(k).getTextContent().length())));
								vectVar.add(v);
							}
							if (rList.item(k).getNodeName().equals("FctObj2")) {
								meilleurOpt = Double.parseDouble(rList.item(k).getAttributes().item(0).getNodeValue());
							}
						}
						r = new Resultat(meilleurOpt, vectVar);
						p.enregistrerSolution(r);
					}
				}
				vPb.add(p);
			}
		}
		return vPb;
	}
/**
 *  Récupère les groupes
 * @return : retourne le vecteur des groupes mis a jour
 */
	public Vector<Groupe> getGroupes() {
		Vector<Groupe> vectGroupe = new Vector<Groupe>();
		Element e = arbreUtilisateur.getDocumentElement();
		NodeList nl = e.getChildNodes();
		Utilisateur u;
		for (int i = 0; i < nl.getLength(); i++) {
			if (nl.item(i).getNodeName().equals("Administrateurs")) {
				Groupe admin = new Groupe("Administrateurs", "Tous les droits");
				NodeList nladm = nl.item(i).getChildNodes();
				for (int j = 0; j < nladm.getLength(); j++) {
					if (nladm.item(j).getNodeName().equals("Utilisateur")) {
						NamedNodeMap utilAtt = nladm.item(j).getAttributes();
						String login = "";
						String mdp = "";
						String nom = "";
						String prenom = "";
						for (int k = 0; k < 4; k++) {
							if (utilAtt.item(k).getNodeName().equals("login"))
								login = utilAtt.item(k).getNodeValue();
							if (utilAtt.item(k).getNodeName().equals("motDePasse"))
								mdp = utilAtt.item(k).getNodeValue();
							if (utilAtt.item(k).getNodeName().equals("nom"))
								nom = utilAtt.item(k).getNodeValue();
							if (utilAtt.item(k).getNodeName().equals("prenom"))
								prenom = utilAtt.item(k).getNodeValue();
						}
						u = new Utilisateur(login, mdp, nom, prenom, true);
						admin.ajoutUtilisateur(u);
					}
				}
				vectGroupe.add(admin);
			}
			if (nl.item(i).getNodeName().equals("Groupe")) {
				Groupe gr = new Groupe(nl.item(i).getAttributes().getNamedItem("nom").getNodeValue(), nl.item(i).getAttributes().getNamedItem("droits").getNodeValue());
				NodeList nlgr = nl.item(i).getChildNodes();
				for (int j = 0; j < nlgr.getLength(); j++) {
					if (nlgr.item(j).getNodeName().equals("Utilisateur")) {
						NamedNodeMap utilAtt = nlgr.item(j).getAttributes();
						String login = "";
						String mdp = "";
						String nom = "";
						String prenom = "";
						for (int k = 0; k < 4; k++) {
							if (utilAtt.item(k).getNodeName().equals("login"))
								login = utilAtt.item(k).getNodeValue();
							if (utilAtt.item(k).getNodeName().equals("motDePasse"))
								mdp = utilAtt.item(k).getNodeValue();
							if (utilAtt.item(k).getNodeName().equals("nom"))
								nom = utilAtt.item(k).getNodeValue();
							if (utilAtt.item(k).getNodeName().equals("prenom"))
								prenom = utilAtt.item(k).getNodeValue();
						}
						u = new Utilisateur(login, mdp, nom, prenom, false);
						gr.ajoutUtilisateur(u);
					}
				}
				vectGroupe.add(gr);
			}
		}
		return vectGroupe;
	}
/**
 * Fonction qui sauvegarde les données de qui ont été modifiées pendant une session, dans le fichhier XML
 * @param vectGroupe : vecteur de groupe permettant d'identifier ce dont on doit sauvegarder
 */
	public void sauvegarderModifUtil(Vector<Groupe> vectGroupe) {
		miseAJourUtil(vectGroupe);
		try {

			// allocation et préparation de l'objet qui va permettre de créer le
			// fichier xml
			TransformerFactory tf = TransformerFactory.newInstance();
			Transformer transformer = tf.newTransformer();

			// On précise que la sauvegarde doit être un fichier xml
			transformer.setOutputProperty(OutputKeys.METHOD, "xml");

			// On demande pour la présentation du fichier xml de mettre des
			// indentations pour chaque nouveau noeud
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");

			// On précise l'encodage du fichier xml à générer
			transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");

			// Pour mettre la ligne de déclaration <?xml ... ?>
			transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");

			// Création et ouverture du fichier xml de sauvegarde
			File f = new File("Data/Utilisateurs.xml");
			if (f.exists()) {
				f.delete();
			}
			// l'objet transformer ne travaille pas avec un fichier mais avec un
			// flot de type StreamResult
			StreamResult nvFichier = new StreamResult(f);

			// On fait la sauvegarde
			transformer.transform(new DOMSource(arbreUtilisateur), nvFichier);
		} catch (Exception e) {
			System.out.println("Erreur de sauvegarde d'un objet Document " + e + "  : Fin du message d'erreur");
		}
	}
/**
 * Fonction qui permet de créer l'arbre XML pour les Utilisateur
 * @param vectGroupe : vecteur du groupe pour la creation de l'arbre
 */
	public void miseAJourUtil(Vector<Groupe> vectGroupe) {
		arbreUtilisateur.removeChild(arbreUtilisateur.getDocumentElement());
		Element Utilisateurs = arbreUtilisateur.createElement("Utilisateurs");
		Element adm = arbreUtilisateur.createElement("Administrateurs");
		for (int l = 0; l < vectGroupe.get(0).getUtilisateurs().size(); l++) {
			Element uti = arbreUtilisateur.createElement("Utilisateur");
			uti.setAttribute("login", vectGroupe.get(0).getUtilisateurs().get(l).getLogin());
			uti.setAttribute("motDePasse", vectGroupe.get(0).getUtilisateurs().get(l).getMotDePasse());
			uti.setAttribute("nom", vectGroupe.get(0).getUtilisateurs().get(l).getNom());
			uti.setAttribute("prenom", vectGroupe.get(0).getUtilisateurs().get(l).getPrenom());
			adm.appendChild(uti);
		}
		Utilisateurs.appendChild(adm);
		for (int i = 1; i < vectGroupe.size(); i++) {
			Element gr = arbreUtilisateur.createElement("Groupe");
			gr.setAttribute("nom", vectGroupe.get(i).getNom());
			gr.setAttribute("droits", vectGroupe.get(i).getDroits());
			for (int j = 0; j < vectGroupe.get(i).getUtilisateurs().size(); j++) {
				Element uti = arbreUtilisateur.createElement("Utilisateur");
				uti.setAttribute("login", vectGroupe.get(i).getUtilisateurs().get(j).getLogin());
				uti.setAttribute("motDePasse", vectGroupe.get(i).getUtilisateurs().get(j).getMotDePasse());
				uti.setAttribute("nom", vectGroupe.get(i).getUtilisateurs().get(j).getNom());
				uti.setAttribute("prenom", vectGroupe.get(i).getUtilisateurs().get(j).getPrenom());
				gr.appendChild(uti);
			}
			Utilisateurs.appendChild(gr);
		}
		arbreUtilisateur.appendChild(Utilisateurs);
	}
/**
 * Sauvegarde les modofication effectuées sur les problèmes et enregistre dans le fichier XML
 * @param vectPb : vecteur de problèmers a sauvegarder
 */
	public void sauvegarderModifPb(Vector<Probleme> vectPb) {
		miseAJourPb(vectPb);
		try {

			// allocation et préparation de l'objet qui va permettre de créer le
			// fichier xml
			TransformerFactory tf = TransformerFactory.newInstance();
			Transformer transformer = tf.newTransformer();

			// On précise que la sauvegarde doit être un fichier xml
			transformer.setOutputProperty(OutputKeys.METHOD, "xml");

			// On demande pour la présentation du fichier xml de mettre des
			// indentations pour chaque nouveau noeud
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");

			// On précise l'encodage du fichier xml à générer
			transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");

			// Pour mettre la ligne de déclaration <?xml ... ?>
			transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");

			// Création et ouverture du fichier xml de sauvegarde
			File f = new File("Data/Problemes.xml");
			if (f.exists()) {
				f.delete();
			}
			// l'objet transformer ne travaille pas avec un fichier mais avec un
			// flot de type StreamResult
			StreamResult nvFichier = new StreamResult(f);

			// On fait la sauvegarde
			transformer.transform(new DOMSource(arbrePb), nvFichier);
		} catch (Exception e) {
			System.out.println("Erreur de sauvegarde d'un objet Document " + e + "  : Fin du message d'erreur");
		}
	}
	
	
/**
 * Crée l'arbre XML pour les problèmes
 * @param vectPb: vecteur de problèmes pour créer l'arbre
 */
	public void miseAJourPb(Vector<Probleme> vectPb) {
		arbrePb.removeChild(arbrePb.getDocumentElement());
		Element ListeProblemes = arbrePb.createElement("ListeProblemes");
		for (int i = 0; i < vectPb.size(); i++) {
			Element probleme = arbrePb.createElement("Probleme");
			probleme.setAttribute("nom", vectPb.get(i).getNom());
			for (int l = 0; l < vectPb.get(i).getVariables().size(); l++) {
				Element var = arbrePb.createElement("Variable");
				Text varT = arbrePb.createTextNode(vectPb.get(i).getVariables().get(l).getNom()+"");
				var.appendChild(varT);
				probleme.appendChild(var);
			}
			Element fct = arbrePb.createElement("FctObj");
			fct.setAttribute("objectif", vectPb.get(i).getFctObj().getObjectif());
			fct.setAttribute("fct", vectPb.get(i).getFctObj().getFonction());
			probleme.appendChild(fct);
			for (int j = 0; j < vectPb.get(i).getContraintes().size(); j++) {
				Element contrainte = arbrePb.createElement("Contrainte");
				contrainte.setAttribute("c", vectPb.get(i).getContraintes().get(j).getContrainte());
				probleme.appendChild(contrainte);
			}
			if (vectPb.get(i).getResultat() != null) {
				Element resultat = arbrePb.createElement("Resultat");
				for (int k = 0; k < vectPb.get(i).getResultat().getVariables().size(); k++) {
					Element var2 = arbrePb.createElement("Variable2");
					Text var2T = arbrePb.createTextNode(vectPb.get(i).getResultat().getVariables().get(k).getNom() + "=" + vectPb.get(i).getResultat().getVariables().get(k).getValeur());
					var2.appendChild(var2T);
					resultat.appendChild(var2);
				}
				Element obj = arbrePb.createElement("FctObj2");
				obj.setAttribute("optim", "" + vectPb.get(i).getResultat().getMeilleurRes());
				resultat.appendChild(obj);
				probleme.appendChild(resultat);
			}
			ListeProblemes.appendChild(probleme);
		}
		arbrePb.appendChild(ListeProblemes);
	}

	/**
	 * Fonction permettant d'importer des problèmes d'un fichier XML. Ce fichier sera vérifié et validé par un schéma XSD
	 * @param fichier Nom du fichier dans lequel se trouve le problème à importer
	 * @return : retourne le problème contenu dans le fichier
	 */
	public Vector<Probleme> importerPb(String fichier) {
		if(validXML(fichier,"Data/Problemes.xsd")){
			System.out.println("Le fichier a été vérifié par schéma XSD");
			try {
				DocumentBuilderFactory fabrique1 = DocumentBuilderFactory.newInstance();
				DocumentBuilder db1 = fabrique1.newDocumentBuilder();
				File f1 = new File(fichier);
				if (!f1.exists()) {
					System.out.println("Le fichier n'existe pas.");
					return null;
				}
				else {
					// On charge en mémoire vive l'arbre de l'ensemble des sessions
					Document arbreImportPb = db1.parse(f1);
					Vector<Probleme> vPb=new Vector<Probleme>();
					vPb=getPb(arbreImportPb);
					return vPb;
				}
			} catch (Exception e) {
				System.out.println("Erreur de création ou de chargement des arbres xml : " + e);
				return null;
			}
		}
		else{
			System.out.println("Ce fichier n'a pas été accepté par le schéma XSD");
			return null;
		}
	}
	/**
	 * Fonction renvoyant l'arbre XML
	 * @return : retourne l'arbre XML des problèmes
	 */
	public Document getArbrePb(){
		return arbrePb;
	}

	/**
	 * Fontion permettant de vérifier la validité de l'arbre
	 * @param xmlFile fichier XML a tester
	 * @param xsdFile XSD permettant de verifier
	 * @return retourne la validité de l'arbre
	 */
	public boolean validXML(String xmlFile, String xsdFile) {
		isValid = true; // Valide jusqu'à ce qu'une erreur se produise !
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		dbf.setIgnoringComments(true);
		dbf.setNamespaceAware(true);
		dbf.setValidating(true);
		dbf.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
		dbf.setAttribute(JAXP_SCHEMA_SOURCE, new File(xsdFile));
		try {
			// Parsage du fichier XML avec DOM
			DocumentBuilder db = dbf.newDocumentBuilder();
			db.setErrorHandler(new ErrorHandler() {
				public void fatalError(SAXParseException e) {
					System.out
							.println("Erreur de validation XSD - Erreur fatal :\n"+e);
					isValid = false;
				}

				public void error(SAXParseException e) {
					System.out.println("Erreur de validation XSD - Erreur :\n"+e);
					isValid = false;
				}

				public void warning(SAXParseException e) {
					System.out.println("Erreur de validation XSD - Warning :\n"+e);
					isValid = false;
				}
			});
			db.parse(xmlFile);
		} catch (ParserConfigurationException pcee) {
			System.out.println(pcee);
			return false;
		} catch (IOException ioe) {
			System.out.println(ioe);
			return false;
		} catch (SAXException saxe) {
			System.out.println(saxe);
			return false;
		}
		return isValid;
	}
}
