package reseau;

import client.Application;
import client.ApplicationHelper;
import client.model.LienUserGroupRole;
import client.model.benchmark.Benchmarks;
import client.model.benchmark.Solution;
import client.model.group.Groupe;
import client.model.problem.*;
import client.model.user.Utilisateur;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

final class XMLReader {

    private static final Logger logger = Logger.getLogger(XMLReader.class.getCanonicalName());

    private static final SAXBuilder DEFAULT_SAX_READER = new SAXBuilder(true);

    static {
        DEFAULT_SAX_READER.setFeature(
                "http://apache.org/xml/features/validation/schema", true);
    }

    //FIXME Fill no files
    public static Probleme ReaderProblemaMessage(String XML) {

        Document document = null;
        try {
            document = DEFAULT_SAX_READER.build(new StringReader(XML));

            return buildProblem(document.getRootElement());
        } catch (JDOMException e) {
            logger.log(Level.SEVERE, "Fail at parsing given XML", e);
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Fail at reading given XML", e);
        }
        return null;
    }

    public static Resultat ReaderResultMessage(String XML) {
        Document document = null;
        try {
            document = DEFAULT_SAX_READER.build(new StringReader(XML));

            return buildResult(document.getRootElement());
        } catch (JDOMException e) {
            logger.log(Level.SEVERE, "Fail at parsing given XML", e);
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Fail at reading given XML", e);
        }
        return null;
    }

    public static Benchmarks ReaderBenchmarkMessage(String XML) {
        Document document = null;
        try {
            document = DEFAULT_SAX_READER.build(new StringReader(XML));

            return buildBenchmarks(document.getRootElement());
        } catch (JDOMException e) {
            logger.log(Level.SEVERE, "Fail at parsing given XML", e);
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Fail at reading given XML", e);
        }
        return null;
    }

    public static Groupe ReaderGroupMessage(String XML) {
        Document document = null;
        try {
            document = DEFAULT_SAX_READER.build(new StringReader(XML));

            return buildGroup(document.getRootElement());
        } catch (JDOMException e) {
            logger.log(Level.SEVERE, "Fail at parsing given XML", e);
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Fail at reading given XML", e);
        }
        return null;
    }

    public static Utilisateur ReaderUserMessage(String XML) {
        Document document = null;
        try {
            document = DEFAULT_SAX_READER.build(new StringReader(XML));

            return buildUser(document.getRootElement());
        } catch (JDOMException e) {
            logger.log(Level.SEVERE, "Fail at parsing given XML", e);
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Fail at reading given XML", e);
        }
        return null;
    }

    static Groupe buildGroup(Element racine) {
        Groupe g = new Groupe();

        int idGroup = Integer.parseInt(racine.getAttributeValue("id"));
        g.setIdGroupe(idGroup);
        g.setNomGroupe(racine.getAttributeValue("name"));

        // On crée une List contenant tous les noeuds "etudiant" de l'Element
        List listProblem = racine.getChildren();

        // On crée un Iterator sur notre liste
        Iterator i = listProblem.iterator();

        ArrayList<LienUserGroupRole> arrayTemp = new ArrayList<LienUserGroupRole>();

        while (i.hasNext()) {

            Element courant = (Element) i.next();

            if (courant.getName().equals("users")) {
                List listContrainte = courant.getChildren();

                if (listContrainte.size() > 0) {

                    Iterator j = listContrainte.iterator();

                    while (j.hasNext()) {
                        Element courant2 = (Element) j.next();

                        if (courant2.getName().equals("user")) {
                            int idUser = Integer.parseInt(courant2.getAttributeValue("id"));

                            int idRole = ApplicationHelper.IdRoleOfUserInGroup(idUser, idGroup);
                            arrayTemp.add(new LienUserGroupRole(idUser, idGroup, idRole));
                        }
                    }
                }
            } else if (courant.getName().equals("problems")) {
                List listContrainte = courant.getChildren();

                if (listContrainte.size() > 0) {

                    Iterator j = listContrainte.iterator();

                    while (j.hasNext()) {
                        Element courant2 = (Element) j.next();

                        if (courant2.getName().equals("problem")) {
                            int idProblem = Integer.parseInt(courant2
                                    .getAttributeValue("id"));

                            g.addIdProbleme(idProblem);
                        }
                    }
                }
            }

            // On ajoute le problème au groupe
            Application.getInstance().addGroup(g.getIdGroupe(), g);
        }

        // On met le nouveau arrayLink
        Application.getInstance().setArrayLinkOfUserGroupRole(arrayTemp);
        System.out.println("Reader Group : " + Application.getInstance().toStringArrayLinkUserGroupRole());

        return g;
    }

    static Utilisateur buildUser(Element racine) {
        Utilisateur user = new Utilisateur();

        int idUser = Integer.parseInt(racine.getAttributeValue("id"));
        user.setIdPersonne(idUser);

        // On crée une List contenant tous les noeuds "etudiant" de l'Element
        List listProblem = racine.getChildren();

        // On crée un Iterator sur notre liste
        Iterator i = listProblem.iterator();

        // On supprime l'utilisateur enregistré
        Application.getInstance().removeUser(idUser);

        // On supprime les users du groupe afin d'actualiser le tableau
        for (int counter = 0; counter < Application.getInstance()
                .getArrayLinkOfUserGroupRole().size(); counter++) {
            LienUserGroupRole l = Application.getInstance()
                    .getArrayLinkOfUserGroupRole().get(counter);
            ApplicationHelper.RemoveUserFromGroup(idUser, l.getIdGroup());
        }

        while (i.hasNext()) {

            Element courant = (Element) i.next();

            List listContrainte = courant.getChildren();

            if (listContrainte.size() > 0) {

                Iterator j = listContrainte.iterator();

                while (j.hasNext()) {
                    Element courant2 = (Element) j.next();

                    int idGroup = Integer.parseInt(courant2
                            .getAttributeValue("id"));

                    int idRole = Integer.parseInt(courant2
                            .getAttributeValue("associated-role-id"));

                    ApplicationHelper.AddLienUserGroupRole(idUser, idGroup, idRole);
                    logger.fine("size of : " + Application.getInstance().getArrayLinkOfUserGroupRole().size());
                }
            } else {
                if (courant.getName().equals("login")) {
                    user.setLogin(courant.getValue());
                } else if (courant.getName().equals("password")) {
                    user.setPassword(courant.getValue());
                }
            }
        }
        // On ajoute l'utilisateur dans l'arrayUser
        Application.getInstance().addUser(idUser, user);
        System.out.println("Reader User : " + Application.getInstance().toStringArrayLinkUserGroupRole());

        return user;
    }

    static Resultat buildResult(Element racine) {
        Resultat r = new Resultat();

        int idProbleme = 0;
        int idMethode = 0;

        if (racine.getName().equals("resultats"))
            racine = (Element) racine.getChild("resultat-simple");

        List listProblem = racine.getChildren();

        // On crée un Iterator sur notre liste
        Iterator i = listProblem.iterator();

        while (i.hasNext()) {

            Element courant = (Element) i.next();

            r.setIdResultat(Integer.parseInt(racine.getAttribute("id")
                    .getValue()));

            // On supprime le resultat si enregistré
            Application.getInstance().removeResultat(r.getIdResultat());

            if (courant.getName().equals("nom_resultat")) {
                r.setNomResultat(courant.getValue());
            } else if (courant.getName().equals("probleme")) {
                idProbleme = Integer.parseInt(courant
                        .getAttributeValue("id"));
                r.setNomProbleme(courant.getValue());
                r.setIdProblem(idProbleme);
            } else if (courant.getName().equals("methode")) {
                idMethode = Integer.parseInt(courant
                        .getAttributeValue("id"));
                r.setNomMethode(courant.getValue());
                r.setIdMethod(idMethode);
            } else if (courant.getName().equals("run_date")) {
                r.setDate(courant.getValue());
            } else if (courant.getName().equals("point_depart")) {
                r.setPointDeDepart("(");
                List listSolution = courant.getChildren();

                if (listSolution.size() > 0) {

                    Iterator point = listSolution.iterator();

                    while (point.hasNext()) {

                        Element e = (Element) point.next();
                        if (r.getPointDeDepart().length() != 1) {
                            r.setPointDeDepart(r.getPointDeDepart()
                                    + ", " + e.getValue());
                        } else {
                            r.setPointDeDepart(r.getPointDeDepart()
                                    + e.getValue());
                        }
                    }
                    r.setPointDeDepart(r.getPointDeDepart() + ")");
                    System.out.println("point de depart : "
                            + r.getPointDeDepart());
                }
            } else if (courant.getName().equals("parametres")) {
                List listParametres = courant.getChildren();

                if (listParametres.size() > 0) {

                    Iterator params = listParametres.iterator();

                    while (params.hasNext()) {
                        Element e = (Element) params.next();

                        if (e.getName().equals("epsilon")) {
                            r.setEpsilon(Double.parseDouble(e
                                    .getValue()));
                        } else if (e.getName().equals("pas")) {
                            r.setPas(Double.parseDouble(e.getValue()));
                        } else {
                            System.out
                                    .println("Error parsing XML @ parameters");
                        }
                    }
                }

            } else if (courant.getName().equals(
                    "point_valeur_optimisation")) {
                r.setPointValOptim("(");
                List listSolution2 = courant.getChildren();

                if (listSolution2.size() > 0) {

                    Iterator point2 = listSolution2.iterator();

                    while (point2.hasNext()) {
                        Element e = (Element) point2.next();

                        if (e.getName().equals("patience")) {
                            r.setMaxIteration(Double.parseDouble(e
                                    .getValue()));

                        } else if (e.getName().equals("point")) {
                            if (r.getPointValOptim().length() != 1) {

                                r.setPointValOptim(r.getPointValOptim()
                                        + ", " + e.getValue());
                            } else {
                                r.setPointValOptim(r.getPointValOptim()
                                        + e.getValue());
                            }
                        }
                    }
                    r.setPointValOptim(r.getPointValOptim() + ")");
                }

            } else if (courant.getName().equals("valeur")) {
                r.setValeurResultat(Double.parseDouble(courant
                        .getValue()));

            } else if (courant.getName()
                    .equals("complexite_iteration")) {
                r.setComplexite(courant.getValue());

            } else if (courant.getName().equals("erreur_absolue")) {
                r.setErrAbsolue(Double.parseDouble(courant
                        .getValue()));
            } else {
                Exception e = new Exception(
                        "XML parsing error : no nodes corresponding");
            }
        }

        System.out.print("Resultat : " + r.toString());

        // On ajoute le résultat dans l'arrayResultat
        Application.getInstance().addResultat(r.getIdResultat(), r);

        // On ajoute dans l'arrayLink
        ApplicationHelper.AddLienProblemeMethodeResultat(idProbleme, idMethode,
                r.getIdResultat());

        return r;
    }

    static Probleme buildProblem(Element racine) {
        Probleme p = new Probleme();

        p.setIdProbleme(Integer.parseInt(racine.getAttribute("id").getValue()));

        // On supprime le problème si enregistré
        Application.getInstance().removeProbleme(p.getIdProbleme());

        // On crée une List contenant tous les noeuds "etudiant" de l'Element
        List listProblem = racine.getChildren();

        // On crée un Iterator sur notre liste
        Iterator i = listProblem.iterator();

        while (i.hasNext()) {

            Element courant = (Element) i.next();

            if (courant.getName().equals("nom_probleme")) {
                p.setNomProbleme(courant.getValue());

            } else if (courant.getName().equals("fonction")) {
                p.setDimensionFonction(Integer.parseInt(courant.getChild(
                        "dimension").getValue()));
                p.setLibelleFonction(courant.getChild(
                        "representation-textuelle").getValue());
                //TODO Dire à Andréa de rajouter ces infos dans le XML
                //p.setNomFonction(courant.getChild("appel-fonction").getValue());
                //p.setAppelFonction(courant.getChild("chemin").getValue());

            } else if (courant.getName().equals("solution")) {
                p.setSolutionExacte("(");
                List listSolution = courant.getChildren();

                if (listSolution.size() > 0) {

                    Iterator j = listSolution.iterator();

                    while (j.hasNext()) {
                        Element e = (Element) j.next();
                        if (p.getSolutionExacte().length() != 1) {
                            p.setSolutionExacte(p.getSolutionExacte() + ", "
                                    + e.getValue());
                        } else {
                            p.setSolutionExacte(p.getSolutionExacte()
                                    + e.getValue());
                        }
                    }
                    p.setSolutionExacte(p.getSolutionExacte() + ")");
                }

            } else if (courant.getName().equals("contraintes")) {

                List listContrainte = courant.getChildren();

                if (listContrainte.size() > 0) {

                    Iterator j = listContrainte.iterator();

                    while (j.hasNext()) {
                        Element courant2 = (Element) j.next();

                        Contrainte contrainte = new Contrainte();

                        List listParametre = courant2.getChildren();

                        if (listParametre.size() > 0) {

                            Iterator k = listParametre.iterator();

                            while (k.hasNext()) {
                                Element courant3 = (Element) k.next();

                                System.out.println("courant3 : " + courant3.getName());

                                if (courant3.getName().equals(
                                        "representation-textuelle")) {
                                    contrainte.addParameters(new Parameters(
                                            courant3.getName(), courant3
                                            .getValue()));
                                } else if (courant3.getName().equals(
                                        "appel-fonction")) {
                                    contrainte.addParameters(new Parameters(
                                            courant3.getName(), courant3
                                            .getValue()));
                                } else if (courant3.getName().equals("chemin")) {
                                    contrainte.addParameters(new Parameters(
                                            courant3.getName(), courant3
                                            .getValue()));
                                } else {
                                    Exception e = new Exception(
                                            "Error Parsing XML in the fourth node");
                                }
                            }
                        }
                        p.addContraintes(contrainte);
                    }
                } else {
                    Exception e = new Exception(
                            "Error Parsing XML in the third node");
                }

            } else if (courant.getName().equals("derivees")) {
                List listContrainte = courant.getChildren();

                if (listContrainte.size() > 0) {
                    Derive derive = null;

                    Iterator j = listContrainte.iterator();

                    while (j.hasNext()) {
                        Element courant2 = (Element) j.next();

                        derive = new Derive();

                        if (courant2.getName().equals("derivee")) {
                            derive.setIdDerive(Integer.parseInt(courant2
                                    .getAttributeValue("ordre")));
                        }

                        List listParametre = courant2.getChildren();

                        if (listParametre.size() > 0) {

                            Iterator k = listParametre.iterator();

                            while (k.hasNext()) {
                                Element courant3 = (Element) k.next();

                                if (courant3.getName().equals(
                                        "representation-textuelle")) {
                                    derive.addParameters(new Parameters(
                                            courant3.getName(), courant3
                                            .getValue()));
                                } else if (courant3.getName().equals(
                                        "appel-fonction")) {
                                    derive.addParameters(new Parameters(
                                            courant3.getName(), courant3
                                            .getValue()));
                                } else if (courant3.getName().equals("chemin")) {
                                    derive.addParameters(new Parameters(
                                            courant3.getName(), courant3
                                            .getValue()));
                                } else {
                                    Exception e = new Exception(
                                            "Error Parsing XML in the fourth node");
                                }
                            }
                        }
                    }
                    p.addDerive(derive);
                } else {
                    Exception e = new Exception(
                            "Error Parsing XML in the third node");
                }
            }
        }
        // On ajoute le problème dans l'arrayProbleme
        Application.getInstance().addProbleme(p.getIdProbleme(), p);
        System.out.println("Problème : " + p.toString());

        return p;
    }

    static Benchmarks buildBenchmarks(Element racine) {
        Benchmarks b = new Benchmarks();

        // On crée une List contenant tous les noeuds "etudiant" de l'Element
        List listProblem = racine.getChildren();

        // On crée un Iterator sur notre liste
        Iterator i = listProblem.iterator();

        while (i.hasNext()) {

            Element courant = (Element) i.next();

            if (courant.getName().equals("resultat-benchmark")) {
                b.setIdBenchmark(Integer.parseInt(courant
                        .getAttributeValue("id")));
            }

            List listNoeuds = courant.getChildren();

            if (listNoeuds.size() > 0) {

                Iterator j = listNoeuds.iterator();

                while (j.hasNext()) {
                    Element courant2 = (Element) j.next();

                    if (courant2.getName().equals("solution")) {
                        Solution s = new Solution();

                        // On crée une List contenant tous les noeuds "etudiant"
                        // de l'Element
                        List listSolution = courant2.getChildren();

                        // On crée un Iterator sur notre liste
                        Iterator h = listSolution.iterator();

                        while (h.hasNext()) {
                            Element courant3 = (Element) h.next();

                            if (courant3.getName().equals("point-optimisation")) {
                                List listPoint = courant3.getChildren();

                                // On crée un Iterator sur notre liste
                                Iterator p = listPoint.iterator();

                                s.setPoint("(");

                                while (p.hasNext()) {

                                    Element courant4 = (Element) p.next();

                                    if (s.getPoint().length() != 1) {
                                        s.setPoint(s.getPoint() + ", "
                                                + courant4.getValue());
                                    } else {
                                        s.setPoint(s.getPoint()
                                                + courant4.getValue());
                                    }
                                }
                                s.setPoint(s.getPoint() + ")");

                            } else if (courant3.getName().equals(
                                    "valeur-optimation")) {
                                s.setValOptim(Double.parseDouble(courant3
                                        .getValue()));
                            }
                        }

                        // On ajoute la solution au benchmark
                        b.setSolution(s);

                    } else if (courant2.getName().equals("resultat")) {
                        Resultat r = new Resultat();

                        r.setIdResultat(Integer.parseInt(courant2
                                .getAttributeValue("id")));

                        List listResultat = courant2.getChildren();

                        // On crée un Iterator sur notre liste
                        Iterator h = listResultat.iterator();

                        while (h.hasNext()) {

                            Element courant3 = (Element) h.next();

                            // On supprime le resultat si enregistré
                            Application.getInstance().removeResultat(
                                    r.getIdResultat());

                            if (courant3.getName().equals("nom_resultat")) {
                                r.setNomResultat(courant3.getValue());
                            } else if (courant3.getName().equals("probleme")) {
                                r.setNomProbleme(courant3.getValue());
                            } else if (courant3.getName().equals("methode")) {
                                r.setNomMethode(courant3.getValue());
                            } else if (courant3.getName().equals("run_date")) {
                                r.setDate(courant3.getValue());
                            } else if (courant3.getName()
                                    .equals("point_depart")) {
                                r.setPointDeDepart("(");
                                List listSolution = courant3.getChildren();

                                if (listSolution.size() > 0) {

                                    Iterator point = listSolution.iterator();

                                    while (point.hasNext()) {

                                        Element e = (Element) point.next();
                                        if (r.getPointDeDepart().length() != 1) {
                                            r.setPointDeDepart(r
                                                    .getPointDeDepart()
                                                    + ", " + e.getValue());
                                        } else {
                                            r.setPointDeDepart(r
                                                    .getPointDeDepart()
                                                    + e.getValue());
                                        }
                                    }
                                    r.setPointDeDepart(r.getPointDeDepart()
                                            + ")");
                                }
                            } else if (courant3.getName().equals("parametres")) {
                                List listParametres = courant3.getChildren();

                                if (listParametres.size() > 0) {

                                    Iterator params = listParametres.iterator();

                                    while (params.hasNext()) {
                                        Element e = (Element) params.next();

                                        if (e.getName().equals("epsilon")) {
                                            r.setEpsilon(Double.parseDouble(e
                                                    .getValue()));
                                        } else if (e.getName().equals("pas")) {
                                            r.setPas(Double.parseDouble(e
                                                    .getValue()));
                                        } else {
                                            System.out
                                                    .println("Error parsing XML @ parameters");
                                        }
                                    }
                                }

                            } else if (courant3.getName().equals(
                                    "point_valeur_optimisation")) {
                                r.setPointValOptim("(");
                                List listSolution2 = courant3.getChildren();

                                if (listSolution2.size() > 0) {

                                    Iterator point2 = listSolution2.iterator();

                                    while (point2.hasNext()) {
                                        Element e = (Element) point2.next();

                                        if (e.getName().equals("patience")) {
                                            r.setMaxIteration(Double
                                                    .parseDouble(e.getValue()));

                                        } else if (e.getName().equals("point")) {
                                            if (r.getPointValOptim().length() != 1) {

                                                r.setPointValOptim(r
                                                        .getPointValOptim()
                                                        + ", " + e.getValue());
                                            } else {
                                                r.setPointValOptim(r
                                                        .getPointValOptim()
                                                        + e.getValue());
                                            }
                                        }
                                    }
                                    r.setPointValOptim(r.getPointValOptim()
                                            + ")");
                                }

                            } else if (courant3.getName().equals("valeur")) {
                                r.setValeurResultat(Double.parseDouble(courant3
                                        .getValue()));

                            } else if (courant3.getName().equals(
                                    "complexite_iteration")) {
                                r.setComplexite(courant3.getValue());

                            } else if (courant3.getName().equals(
                                    "erreur_absolue")) {
                                r.setErrAbsolue(Double.parseDouble(courant3
                                        .getValue()));
                            } else {
                                Exception e = new Exception(
                                        "XML parsing error : no nodes corresponding");
                            }
                        }

                        // On ajoute le résultat au benchmark
                        b.addResultat(r);
                    }
                }
            }
        }

        System.out.println("Benchmark : " + b.toString());

        return b;
    }
}
