/*
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.HashMap;
import java.util.Map;
import fr.cnrs.liris.drim.grt.modele.Terme;

/**
 *
 * @author sgesche
 */
public class DistanceStatisticoSemantique {
    private Map<Terme, double[]> vecteurs;
    
    public final static int DISTANCE_MANHATTAN = 0;
    public final static int DISTANCE_EUCLIDIENNE = 1;
    
    public DistanceStatisticoSemantique() {
        vecteurs = new HashMap<>();
    }
    
    public void addTerme(Terme t, double[] vecteur) {
        vecteurs.put(t, vecteur);
    }
    
    public double getSimilarite(Terme t0, Terme t1, int DISTANCE_QQCH) throws IllegalArgumentException {
        if(!vecteurs.containsKey(t0)) {
            return t0.equals(t1)?1.0:0.0;
            //throw new IllegalArgumentException("Le terme "+t0.toString()+" n'est pas connu de l'analyseur spectral.");
        }
        if(!vecteurs.containsKey(t1)) {
            return t0.equals(t1)?1.0:0.0;
            //throw new IllegalArgumentException("Le terme "+t1.toString()+" n'est pas connu de l'analyseur spectral.");
        }
        double resultat;
        switch(DISTANCE_QQCH) {
            case DISTANCE_EUCLIDIENNE:
                resultat = getDistanceEuclidienne(vecteurs.get(t0), vecteurs.get(t1));
                break;
            default: // DISTANCE_MANHATTAN
                resultat = getDistanceManhattan(vecteurs.get(t0), vecteurs.get(t1));
                break;
        }
        return 1.0 - resultat / Math.sqrt(2);
    }
    
    public Terme[] getTermesSimilaires(Terme t, double seuil, int DISTANCE_QQCH) throws IllegalArgumentException {
        ArrayList<Terme> resultat = new ArrayList<>();
        
        for(Terme aEvaluer: vecteurs.keySet()) {
            if(getSimilarite(t, aEvaluer, DISTANCE_QQCH) >= seuil) {
                resultat.add(aEvaluer);
            }
        }
        
        Terme[] res = new Terme[resultat.size()];
        resultat.toArray(res);
        return res;
    }
    
    private double getDistanceManhattan(double[] vecteurA, double[] vecteurB) {
        double qt = 0.0;
        for(int i=0; i<vecteurA.length; i++) {
            qt += Math.abs(vecteurA[i] - vecteurB[i]);
        }
        return qt;
    }
    
    private double getDistanceEuclidienne(double[] vecteurA, double[] vecteurB) {
        double qt = 0.0;
        for(int i=0; i<vecteurA.length; i++) {
            qt += (vecteurA[i] - vecteurB[i]) * (vecteurA[i] - vecteurB[i]);
        }
        return Math.sqrt(qt);
    }
    
    public Terme[] listeTermes() {
        Terme[] resultat = new Terme[vecteurs.keySet().size()];
        vecteurs.keySet().toArray(resultat);
        return resultat;
    }
}
