Subversion Repositories eFlore/Applications.del

Rev

Rev 2080 | Blame | Compare with Previous | Last modification | View Log | RSS feed

package org.tela_botanica.del.client.composants.votes.moyennevotes;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.tela_botanica.del.client.cache.CacheClient;
import org.tela_botanica.del.client.composants.votefleur.VoteFleurPresenteur;
import org.tela_botanica.del.client.composants.votefleur.VoteFleurVue;
import org.tela_botanica.del.client.modeles.Image;
import org.tela_botanica.del.client.modeles.Protocole;
import org.tela_botanica.del.client.modeles.VoteProtocole;
import org.tela_botanica.del.client.navigation.evenement.BusEvenementiel;
import org.tela_botanica.del.client.navigation.evenement.changementEtatUtilisateur.EvenementChangementEtatUtilisateur;
import org.tela_botanica.del.client.navigation.evenement.changementEtatUtilisateur.GestionnaireEvenementChangementEtatUtilisateur;
import org.tela_botanica.del.client.navigation.evenement.suppressioncommentaire.EvenementSuppressionCommentaire;
import org.tela_botanica.del.client.navigation.evenement.suppressioncommentaire.GestionnaireEvenementSuppressionCommentaire;
import org.tela_botanica.del.client.services.rest.VoteProtocoleService;
import org.tela_botanica.del.client.services.rest.async.AjoutVoteProtocoleCallback;
import org.tela_botanica.del.client.services.rest.async.VoteProtocoleCallback;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.dom.client.HasMouseMoveHandlers;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.HasText;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Panel;

public class MoyenneVotePresenteur {

        public interface Vue extends IsWidget {
                public HasClickHandlers getBoutonAnnuler();

                public HasClickHandlers getVotes();

                public int getValeurVote();

                public void afficherBoutonAnnuler();

                public void masquerBoutonAnnuler();

                public void afficherNbVotes();

                public void masquerNbVotes();

                //public void afficherNbPoints();

                //public void masquerNbPoints();

                public void reinitialiserVotes();

                public void rafraichir(int moyenneVote, int nbVotes, int nombrePoints, double moyenneArithmetique, double mediane, HashMap<Integer,Integer> occurrencesParNote, double moyennePonderee);

                public void ajouterAuParent(HasWidgets composite);

                public void afficherVotePrisEnCompte();

                public HasWidgets getZoneFleur();

                public HasText getZoneProtocole();

                public HasText getNbVotes();

                //public HasText getNbPoints();

                public HasClickHandlers getLienNbVotes();

                public void setNoteGenerale(int note);

                public void afficherVoteModifie();

                public HasMouseMoveHandlers getZoneVoter();
                public void masquerZoneVoter();
                
                public void afficherMessageVoteIdentifie(boolean doitEtreIdentifiePourVoter);

                public void setNoteGeneraleToolTip(double valeurVoteTotalPrecise);

                public void desactiverInteractionVote();

                public void activerInteractionVote();

                public void afficherVoteSupprime();

                public Panel getPanneauDetailVotes();

                public void afficherPanneauDetailVotes();

                public void masquerPanneauDetailVotes();

                public HasClickHandlers getLienPanneauFermer();
        }

        private Vue vue;
        private Protocole protocole;
        private Image image;

        private int valeurVoteDefaut = -1;
        private int valeurVoteUtilisateur = -1;
        private int valeurVoteTotal = 0;
        private double moyenneArithmetique = 0;
        private double mediane = 0;
        private int nombrePoints = 0;
        private double valeurVoteTotalPrecise = 0.0;
        private HashMap<Integer,Integer> occurrencesParNote;

        // TODO: on devrait passer un conteneur qui permet d'accéder à ces services
        private VoteProtocoleService voteProtocoleService;

        public MoyenneVotePresenteur(Image image, Protocole protocole, Vue vue,
                        VoteProtocoleService voteProtocoleService) {
                this.vue = vue;
                this.protocole = protocole;
                this.image = image;
                this.voteProtocoleService = voteProtocoleService;

                String nomProtocole = protocole.getNom();
                nomProtocole = nomProtocole.substring(0, 1).toUpperCase()
                                + nomProtocole.substring(1).toLowerCase();
                vue.getZoneProtocole().setText(nomProtocole);
        }

        public void go(HasWidgets composite) {
                vue.ajouterAuParent(composite);
                gererEvenements();
                rafraichirVue();
        }

        public void gererEvenements() {
                
                vue.afficherMessageVoteIdentifie(utilisateurPeutVoter());
                vue.getZoneVoter().addMouseMoveHandler(new MouseMoveHandler() {
                        
                        @Override
                        public void onMouseMove(MouseMoveEvent event) {
                                if(utilisateurPeutVoter()) {
                                        vue.masquerZoneVoter();
                                }       
                        }
                });
                
                vue.getVotes().addClickHandler(new ClickHandler() {
                        @Override
                        public void onClick(ClickEvent event) {
                                if(utilisateurPeutVoter()) {
                                        valeurVoteUtilisateur = vue.getValeurVote();
                                        enregistrerVote();
                                        vue.afficherBoutonAnnuler();
                                } else {
                                        Window.alert("Voter pour ce protocole nécéssite d'être identifié");
                                }

                        }
                });

                vue.getBoutonAnnuler().addClickHandler(new ClickHandler() {
                        @Override
                        public void onClick(ClickEvent event) {
                                valeurVoteUtilisateur = valeurVoteDefaut;
                                vue.masquerBoutonAnnuler();
                                supprimerVote();
                                vue.reinitialiserVotes();
                        }
                });

                // Affiche un chouette panneau qui montre le détail des votes
                vue.getLienNbVotes().addClickHandler(new ClickHandler() {
                        @Override
                        public void onClick(ClickEvent event) {
                                if (vue.getPanneauDetailVotes().isVisible()) {
                                        vue.masquerPanneauDetailVotes();
                                } else {
                                        vue.afficherPanneauDetailVotes();
                                }
                        }
                });

                vue.getLienPanneauFermer().addClickHandler(new ClickHandler() {
                        @Override
                        public void onClick(ClickEvent event) {
                                vue.masquerPanneauDetailVotes();
                        }
                });

                BusEvenementiel.getInstance().addHandler(EvenementChangementEtatUtilisateur.TYPE, new GestionnaireEvenementChangementEtatUtilisateur() {                
                        @Override
                        public void onModificationEtatUtilisateur(EvenementChangementEtatUtilisateur evenementChangementEtatUtilisateur) {
                                rafraichirVue();
                        }
                });
        }
        
        public boolean utilisateurPeutVoter() {
                return !protocole.doitEtreIdentifiePourVoter() || CacheClient.getInstance().getUtilisateur().estIdentifie();
        }

        public void setValeurVoteUtilisateur(int valeurVoteUtilisateur) {
                this.valeurVoteUtilisateur = valeurVoteUtilisateur;
        }

        public void enregistrerVote() {
                vue.desactiverInteractionVote();
                final VoteProtocole voteProtocole = new VoteProtocole();
                voteProtocole.setProtocole(this.protocole);
                voteProtocole.setVote(valeurVoteUtilisateur);
                String idContributeur = CacheClient.getInstance().getUtilisateur()
                                .getId();
                voteProtocole.setContributeur(idContributeur);
                
                //TODO: ceci devrait pouvoir être factorisé
                if (image.utilisateurAVotePourProtocole(this.protocole.getId() + "",
                                idContributeur)) {
                        voteProtocole.setId(image.getVotesProtocoles(this.protocole.getId()+"").get(idContributeur).getId());
                        VoteProtocoleCallback vpc = new VoteProtocoleCallback() {
                                @Override
                                public void surRetour(Void objetRetour) {
                                        image.ajouterVoteProtocole(voteProtocole);
                                        rafraichirVue();
                                        vue.afficherVoteModifie();
                                        vue.activerInteractionVote();
                                }
                        };
                        voteProtocoleService.modifierVote(image.getIdImage(),
                                        voteProtocole, vpc);
                } else {
                        AjoutVoteProtocoleCallback vpc = new AjoutVoteProtocoleCallback() {
                                @Override
                                public void surRetour(String idVote) {
                                        voteProtocole.setId(idVote);
                                        image.ajouterVoteProtocole(voteProtocole);
                                        rafraichirVue();
                                        vue.afficherVotePrisEnCompte();
                                        vue.activerInteractionVote();
                                }
                        };
                        voteProtocoleService.ajouterVote(image.getIdImage(), voteProtocole,
                                        vpc);
                }
        }
        
        public void supprimerVote() {
                vue.desactiverInteractionVote();
                final String idContributeur = CacheClient.getInstance().getUtilisateur()
                                .getId();
                final VoteProtocole voteProtocole = image.getVotesProtocoles(protocole.getId()).get(idContributeur);
                VoteProtocoleCallback vpc = new VoteProtocoleCallback() {
                        @Override
                        public void surRetour(Void objetRetour) {
                                // TODO: voir si l'on affiche un message en cas de succès ?
                                image.supprimerVoteProtocole(protocole.getId() + "", idContributeur);
                                rafraichirVue();
                                vue.afficherVoteSupprime();
                                vue.activerInteractionVote();
                        }

                };
                voteProtocoleService.supprimerVote(image.getIdImage(), voteProtocole, vpc);
        }

        public int getValeurVoteTotal() {
                return valeurVoteTotal;
        }

        public IsWidget getVue() {
                return vue;
        }

        private void rafraichirVue() {
                valeurVoteTotal = calculerMoyenneVotesArrondie();
                moyenneArithmetique = calculerMoyenneVotes();
                mediane = calculerMedianeVotes();
                valeurVoteTotalPrecise = calculerMoyennePondereeVotes();
                nombrePoints = calculerNombrePointsEchelleArbitraire();
                VoteProtocole voteProtocole = image.getVotesProtocoles(
                                protocole.getId()).get(
                                CacheClient.getInstance().getUtilisateur().getId());
                int voteUtilisateur = 0;
                if (voteProtocole != null) {
                        voteUtilisateur = voteProtocole.getVote();
                        vue.masquerZoneVoter();
                }
                
                if(image.utilisateurAVotePourProtocole(protocole.getId()+"", CacheClient.getInstance().getUtilisateur().getId())) {
                        vue.afficherBoutonAnnuler();
                }
                
                vue.afficherMessageVoteIdentifie(utilisateurPeutVoter());

                VoteFleurPresenteur presenteurFleur = new VoteFleurPresenteur(
                                new VoteFleurVue());
                presenteurFleur.setNote(valeurVoteTotal);
                vue.setNoteGenerale(valeurVoteTotal);
                vue.setNoteGeneraleToolTip(valeurVoteTotalPrecise);
                presenteurFleur.go(vue.getZoneFleur());
                vue.rafraichir(voteUtilisateur, image.getVotesProtocoles(protocole.getId()).size(), nombrePoints,
                                           moyenneArithmetique, mediane, occurrencesParNote, valeurVoteTotalPrecise);
        }

        public double calculerMedianeVotes() {
                double med = 0;
                // comparateur de votes (le bulldozer Java™ pour écraser une mouche)
                class Comparatisateur3000 implements Comparator<VoteProtocole> {
                        @Override
                        public int compare(VoteProtocole v1, VoteProtocole v2) {
                                if (v1.getVote() > v2.getVote()) {
                                        return 1;
                                } else if (v1.getVote() > v2.getVote()) {
                                        return -1;
                                } else {
                                        return 0;
                                }
                        }
                }
                // conversion en liste triable
                List<VoteProtocole> liste = new ArrayList<VoteProtocole>(image.getVotesProtocoles(protocole.getId()).values());
                Collections.sort(liste, new Comparatisateur3000());
                int longueur = liste.size();
                if (longueur > 0) {
                        if (longueur % 2 == 0) {
                                // moyenne des éléments centraux
                                med = (liste.get(longueur / 2 - 1).getVote() + liste.get(longueur / 2).getVote()) / 2;
                        } else {
                                // élément central
                                med = liste.get((int) (longueur / 2)).getVote(); 
                        }
                }
                return med;
        }

        // calcule la moyenne arithmétique
        public double calculerMoyenneVotes() {
                double valeurVote = 0;
                double nbVote = 0;
                for (Iterator<String> iterator = image
                                .getVotesProtocoles(protocole.getId()).keySet().iterator(); iterator
                                .hasNext();) {
                        VoteProtocole imageCelValidationData = image.getVotesProtocoles(
                                        protocole.getId()).get(iterator.next());
                        valeurVote += (double) imageCelValidationData.getVote() / 5;
                        nbVote++;
                }

                if (nbVote > 0) {
                        valeurVote /= nbVote;
                        valeurVote *= 5;
                }

                return valeurVote;
        }

        // Calcule une moyenne, où chaque note est pondérée par son nombre d'occurrences au carré.
        // voir http://www.tela-botanica.org/wikini/DevInformatiques/wakka.php?wiki=AppliDelCalculVotes
        public double calculerMoyennePondereeVotes() {

                double score = 0;
                double diviseur = 0;
                int nbOccurrences;
                // mise à jour des occurrences par note, utile pour le panneau de détails
                occurrencesParNote = new HashMap<Integer,Integer>();

                // rangement par note => occurrences
                for (String clef : image.getVotesProtocoles(protocole.getId()).keySet()) {
                        VoteProtocole imageCelValidationData = image.getVotesProtocoles(protocole.getId()).get(clef);
                        nbOccurrences = 1;
                        if (occurrencesParNote.containsKey(imageCelValidationData.getVote())) {
                                nbOccurrences = occurrencesParNote.get(imageCelValidationData.getVote()) + 1;
                        }
                        occurrencesParNote.put(imageCelValidationData.getVote(), nbOccurrences);
                }

                // calcul pondéré
                for (Integer clef : occurrencesParNote.keySet()) {
                        score += clef * occurrencesParNote.get(clef) * occurrencesParNote.get(clef);
                        diviseur += occurrencesParNote.get(clef) * occurrencesParNote.get(clef);
                }

                if (diviseur > 0) {
                        score /= diviseur;
                }

                return score;
        }

        // remplace chaque note par un nombre de points noté dans "echelle" afin de favoriser
        // les note fortes (5 et 4), pour le défi photo notamment
        public int calculerNombrePointsEchelleArbitraire() {
                int points = 0;
                //int[] echelle = {-1,0,1,4,20};
                int[] echelle = {1,10,100,1000,10000};

                for (String clef : image.getVotesProtocoles(protocole.getId()).keySet()) {
                        VoteProtocole imageCelValidationData = image.getVotesProtocoles(protocole.getId()).get(clef);
                        if (imageCelValidationData.getVote() > 0) {
                                points += echelle[imageCelValidationData.getVote() - 1];
                        }
                }

                return points;
        }

        public int calculerMoyenneVotesArrondie() {
                //double valeurVote = calculerMoyenneVotes();
                double valeurVote = calculerMoyennePondereeVotes();
                return (int) Math.round(valeurVote);
        }
}