/*
Copyright 2012-2014 Samuel Gesche

This file is part of the Greek Reuse Toolkit.

The Greek Reuse Toolkit is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

The Greek Reuse Toolkit is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with the Greek Reuse Toolkit.  If not, see <http://www.gnu.org/licenses/>.
*/

package fr.cnrs.liris.drim.grt.proc.similarite;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import fr.cnrs.liris.drim.grt.modele.Citation;
import fr.cnrs.liris.drim.grt.modele.Passage;
import fr.cnrs.liris.drim.grt.modele.Terme;
import fr.cnrs.liris.drim.grt.proc.Processus;

/**
 *
 * @author sgesche
 */
public class AuditAnalyseurSpectral implements Processus {
    private AnalyseurSpectral aAuditer;
    private String statut;
    private double avancement;
    private long momentDebut;
    private long momentFin;
    
    public AuditAnalyseurSpectral(AnalyseurSpectral aAuditer) {
        this.aAuditer = aAuditer;
    }
    
    public Map<Terme[], Double> getAllPairesSimilaires(int nbFrequents, int TRAITEMENT_QQCH, int TERMES_QQCH, double seuil, int DISTANCE_QQCH) {
        statut = "Audit en cours (paires)";
        momentDebut = System.currentTimeMillis();
        avancement = 0.0;
        aAuditer.calculeDistance(nbFrequents, TRAITEMENT_QQCH, TERMES_QQCH);
        avancement = 0.0;
        Terme[] termes = aAuditer.getDistance().listeTermes();
        avancement = 0.005;
        
        Map<Terme[], Double> resultat = new HashMap<>();
        for(int i=0; i<termes.length; i++) {
            avancement = 0.005 + 0.495 * (i*1.0/termes.length);
            Terme terme = termes[i];
            Terme[] termesSimilaires = aAuditer.getDistance().getTermesSimilaires(terme, seuil, DISTANCE_QQCH);
            for(Terme t: termesSimilaires) {
                resultat.put(new Terme[]{terme, t}, aAuditer.getDistance().getSimilarite(terme, t, DISTANCE_QQCH));
            }
        }
        avancement = 0.50;
        
        statut = "Audit terminé";
        return resultat;
    }
    
    public Map<Terme, Terme[]> getClusters(int nbFrequents, int TRAITEMENT_QQCH, int TERMES_QQCH, double seuil, int DISTANCE_QQCH) {
        statut = "Audit en cours (clusters)";
        momentDebut = System.currentTimeMillis();
        avancement = 0.0;
        aAuditer.calculeDistance(nbFrequents, TRAITEMENT_QQCH, TERMES_QQCH);
        avancement = 0.0;
        Terme[] termes = aAuditer.getDistance().listeTermes();
        avancement = 0.005;
        
        Map<Terme, Terme[]> resultat = new HashMap<>();
        for(int i=0; i<termes.length; i++) {
            avancement = 0.005 + 0.495 * (i*1.0/termes.length);
            Terme terme = termes[i];
            Terme[] termesSimilaires = aAuditer.getDistance().getTermesSimilaires(terme, seuil, DISTANCE_QQCH);
            resultat.put(terme, termesSimilaires);
        }
        avancement = 0.50;
        
        statut = "Audit terminé";
        return resultat;
    }
    
    public Map<Integer, Integer> getRepartitionClusters(int nbFrequents, int TRAITEMENT_QQCH, int TERMES_QQCH, double seuil, int DISTANCE_QQCH) {
        statut = "Audit en cours (répartition des clusters)";
        momentDebut = System.currentTimeMillis();
        avancement = 0.0;
        aAuditer.calculeDistance(nbFrequents, TRAITEMENT_QQCH, TERMES_QQCH);
        avancement = 0.0;
        Terme[] termes = aAuditer.getDistance().listeTermes();
        avancement = 0.005;
        
        Map<Integer, Integer> resultat = new HashMap<>();
        for(int i=0; i<termes.length; i++) {
            avancement = 0.005 + 0.495 * (i*1.0/termes.length);
            Terme terme = termes[i];
            Terme[] termesSimilaires = aAuditer.getDistance().getTermesSimilaires(terme, seuil, DISTANCE_QQCH);
            if(!resultat.containsKey(termesSimilaires.length)) {
                resultat.put(termesSimilaires.length, 1);
            } else {
                resultat.put(termesSimilaires.length, 1 + resultat.get(termesSimilaires.length));
            }
        }
        avancement = 0.50;
        
        /*Integer[] tailles = new Integer[clusters.keySet().size()];
        clusters.keySet().toArray(tailles);
        Arrays.sort(tailles);
        
        String resultat = "Nombre de clusters suivant leur taille\n\n";
        for(int i=0; i<tailles.length; i++) {
            if(clusters.containsKey(i)) {
                resultat += i + "\t" + clusters.get(i) + "\n";
            }
        }*/
        statut = "Audit terminé";
        return resultat;
    }
    
    public Map<Integer, Integer> getNombreDeLemmesSimilaires(Citation[] aAnalyser, int nbFrequents, int TRAITEMENT_QQCH, int TERMES_QQCH, double seuil, int DISTANCE_QQCH) {
        statut = "Audit en cours (nombre de lemmes similaires)";
        momentDebut = System.currentTimeMillis();
        avancement = 0.0;
        aAuditer.calculeDistance(nbFrequents, TRAITEMENT_QQCH, TERMES_QQCH);
        avancement = 0.0;
        
        Map<Integer, Integer> resultat = new HashMap<>();
        
        for(int i=0; i<aAnalyser.length; i++) {
            avancement = 0.0 + 0.500 * i / aAnalyser.length;
            Citation citation = aAnalyser[i];
            Passage[] cite = citation.getCite().getAllMots();
            Passage[] citeur = citation.getCiteur().getAllMots();
            
            ArrayList<String> termesCite = new ArrayList<>();
            ArrayList<String> termesCiteur = new ArrayList<>();
            
            for(Passage mot: cite) {
                termesCite.add(mot.getContenu().getExpression());
                //termesCite.addAll(new ArrayList(Arrays.asList(aAuditer.getTermesSimilaires(mot.getContenu(), seuil, DISTANCE_QQCH))));
            }
            for(Passage mot: citeur) {
                termesCiteur.add(mot.getContenu().getExpression());
                //termesCiteur.addAll(new ArrayList(Arrays.asList(aAuditer.getTermesSimilaires(mot.getContenu(), seuil, DISTANCE_QQCH))));
            }
            
            Set<String> termes = new HashSet<>();
            termes.addAll(termesCite);
            termes.addAll(termesCiteur);
            
            int nbSimilaires = 0;
            for(String terme: termes) {
                int nbCite = 0;
                int nbCiteur = 0;
                Set<String> candidats = new HashSet(Arrays.asList(aAuditer.getDistance().getTermesSimilaires(Terme.cree(terme), seuil, DISTANCE_QQCH)));
                for(String c: termesCite) {
                    Set<String> similaires = new HashSet(Arrays.asList(aAuditer.getDistance().getTermesSimilaires(Terme.cree(c), seuil, DISTANCE_QQCH)));
                    similaires.retainAll(candidats);
                    if(!similaires.isEmpty()) {
                        nbCite++;
                    }
                }
                for(String c: termesCiteur) {
                    Set<String> similaires = new HashSet(Arrays.asList(aAuditer.getDistance().getTermesSimilaires(Terme.cree(c), seuil, DISTANCE_QQCH)));
                    if(!similaires.isEmpty()) {
                        nbCiteur++;
                    }
                }
                nbSimilaires += Math.min(nbCite, nbCiteur);
            }
            
            if(!resultat.containsKey(nbSimilaires)) {
                resultat.put(nbSimilaires, 0);
            }
            resultat.put(nbSimilaires, resultat.get(nbSimilaires) + 1);
        }
        return resultat;
    }
    
    public Map<Integer, Integer> getNombreDeLemmesALaSuiteSimilaires(Citation[] aAnalyser, int nbFrequents, int TRAITEMENT_QQCH, int TERMES_QQCH, double seuil, int DISTANCE_QQCH) {
        statut = "Audit en cours (nombre de lemmes à la suite similaires)";
        momentDebut = System.currentTimeMillis();
        avancement = 0.0;
        aAuditer.calculeDistance(nbFrequents, TRAITEMENT_QQCH, TERMES_QQCH);
        avancement = 0.0;
        
        Map<Integer, Integer> resultat = new HashMap<>();
        
        for(int i=0; i<aAnalyser.length; i++) {
            avancement = 0.0 + 0.500 * i / aAnalyser.length;
            Citation citation = aAnalyser[i];
            Passage[] cite = citation.getCite().getAllMots();
            Passage[] citeur = citation.getCiteur().getAllMots();
            
            ArrayList<String> termesCite = new ArrayList<>();
            ArrayList<String> termesCiteur = new ArrayList<>();
            
            for(Passage mot: cite) {
                termesCite.add(mot.getContenu().getExpression());
                //termesCite.addAll(new ArrayList(Arrays.asList(aAuditer.getTermesSimilaires(mot.getContenu(), seuil, DISTANCE_QQCH))));
            }
            for(Passage mot: citeur) {
                termesCiteur.add(mot.getContenu().getExpression());
                //termesCiteur.addAll(new ArrayList(Arrays.asList(aAuditer.getTermesSimilaires(mot.getContenu(), seuil, DISTANCE_QQCH))));
            }
            
            Set<String> termes = new HashSet<>();
            termes.addAll(termesCite);
            termes.addAll(termesCiteur);
            
            int nbSimilaires = 0;
            for(String terme: termes) {
                int nbCite = 0;
                int nbCiteur = 0;
                Set<String> candidats = new HashSet(Arrays.asList(aAuditer.getDistance().getTermesSimilaires(Terme.cree(terme), seuil, DISTANCE_QQCH)));
                for(String c: termesCite) {
                    Set<String> similaires = new HashSet(Arrays.asList(aAuditer.getDistance().getTermesSimilaires(Terme.cree(c), seuil, DISTANCE_QQCH)));
                    similaires.retainAll(candidats);
                    if(!similaires.isEmpty()) {
                        nbCite++;
                    }
                }
                for(String c: termesCiteur) {
                    Set<String> similaires = new HashSet(Arrays.asList(aAuditer.getDistance().getTermesSimilaires(Terme.cree(c), seuil, DISTANCE_QQCH)));
                    if(!similaires.isEmpty()) {
                        nbCiteur++;
                    }
                }
                nbSimilaires += Math.min(nbCite, nbCiteur);
            }
            
            if(!resultat.containsKey(nbSimilaires)) {
                resultat.put(nbSimilaires, 0);
            }
            resultat.put(nbSimilaires, resultat.get(nbSimilaires) + 1);
        }
        return resultat;
    }

    @Override
    public double getAvancement() {
        return aAuditer.getAvancement() / 2 + avancement;
    }

    @Override
    public String getStatut() {
        return statut;
    }
    
    @Override
    public long getTempsExecution() {
        if(avancement == 1.0) {
            return momentFin - momentDebut;
        } else {
            return System.currentTimeMillis() - momentDebut;
        }
    }
}
