/** Auteur : Samuele Giraudo.
 *  Creation : 01/09/10
 *  Modifications : 03/09/10 04/09/10 01/11/10 */

import java.io.FileWriter;
import java.io.FileReader;
import java.util.StringTokenizer;
import java.util.List;
import java.util.LinkedList;
import java.util.Iterator;
import java.lang.Math;

public class GrapheMatAdj implements Graphe {

    // ATTRIBUTS.
    private boolean[][] mat;


    // CONSTRUCTEURS.

    public GrapheMatAdj(int nombre_sommets) {
        assert nombre_sommets >= 0;

        this.mat = new boolean[nombre_sommets][nombre_sommets];
        for (int i = 0 ; i < nombre_sommets ; ++i) {
            for (int j = 0 ; j < nombre_sommets ; ++j)
                this.mat[i][j] = false;
        }
    }

    public GrapheMatAdj(String nom_fichier_dot) {
        assert nom_fichier_dot != null;

        try{
            int nombre_sommets = 0;
            List<Arc> liste_arcs = new LinkedList<Arc>();
            FileReader fichier_dot = new FileReader(nom_fichier_dot);
            char[] tab = new char[32768];
            fichier_dot.read(tab);
            String contenu = new String(tab);
            StringTokenizer tk = new StringTokenizer(contenu, " \b\t\r\n{}\"abcdefghijklmnopqrstuvwxyz->=[]", false);
            while (tk.hasMoreTokens()) {
                try {
                    boolean termine = false;
                    double[] valeurs = new double[2];
                    int nb_val = 0;
                    while (!termine && nb_val <= 2) {
                        String t = tk.nextToken();
                        if (t.charAt(0) == ';')
                            termine = true;
                        else if (t.charAt(t.length() - 1) == ';') {
                            valeurs[nb_val] = Double.parseDouble(t.substring(0, t.length() - 1));
                            termine = true;
                        }
                        else
                            valeurs[nb_val] = Double.parseDouble(t.substring(0, t.length()));
                        ++nb_val;
                    }
                    if (nb_val == 1)
                        nombre_sommets = Math.max(nombre_sommets, (int) valeurs[0] + 1);
                    else if (nb_val == 2) {
                        Sommet s1 = new Sommet((int) valeurs[0]);
                        Sommet s2 = new Sommet((int) valeurs[1]);
                        liste_arcs.add(new Arc(Arc.ORIENTE, s1, s2, 0));
                        nombre_sommets = Math.max(nombre_sommets, s1.cle() + 1);
                        nombre_sommets = Math.max(nombre_sommets, s2.cle() + 1);
                    }
                }
                catch (NumberFormatException nfe) {
                    break;
                }
            }
            this.mat = new boolean[nombre_sommets][nombre_sommets];
            for (int i = 0 ; i < nombre_sommets ; ++i) {
                for (int j = 0 ; j < nombre_sommets ; ++j)
                    this.mat[i][j] = false;
            }
            Iterator it = liste_arcs.iterator();
            while (it.hasNext())
                this.ajouterArc((Arc) it.next());
        }
        catch (Exception ex){
            System.out.println(ex.toString());
        }
    }


    // METHODES.

    public int nombreSommets() {
        return this.mat.length;
    }

    public int nombreArcs() {
        int nb = 0;
        for (int i = 0 ; i < this.nombreSommets() ; ++i)
            for (int j = 0 ; j < this.nombreSommets() ; ++j)
                if (this.mat[i][j])
                    ++nb;
        return nb;
    }

    public boolean existeArc(Arc a) {
        assert a != null;
        assert a.masqueEspece() == Arc.ORIENTE;
        assert a.depart().cle() < this.nombreSommets();
        assert a.arrivee().cle() < this.nombreSommets();

        return this.mat[a.depart().cle()][a.arrivee().cle()];

    }

    public void ajouterArc(Arc a) {
        assert a != null;
        assert a.masqueEspece() == Arc.ORIENTE;
        assert a.depart().cle() < this.nombreSommets();
        assert a.arrivee().cle() < this.nombreSommets();

        this.mat[a.depart().cle()][a.arrivee().cle()] = true;
    }

    public void supprimerArc(Arc a) {
        assert a != null;
        assert a.masqueEspece() == Arc.ORIENTE;
        assert a.depart().cle() < this.nombreSommets();
        assert a.arrivee().cle() < this.nombreSommets();

        this.mat[a.depart().cle()][a.arrivee().cle()] = false;
    }

    public String toString() {
        String res = new String();
        res = "digraph G {\n";
        for (int i = 0 ; i < this.nombreSommets() ; ++i)
            res += "    " + i + ";\n";
        for (int i = 0 ; i < this.nombreSommets() ; ++i) {
            for (int j = 0 ; j < this.nombreSommets() ; ++j) {
                if (this.mat[i][j])
                    res += "    " + String.valueOf(i) + " -> " + String.valueOf(j) + ";\n";
            }
        }
        res += "}\n";
        return res;
    }

    public void afficher() {
        System.out.println(this.toString());
    }

    public void versImage(String nom_fichier) {
        assert nom_fichier != null;
        assert !nom_fichier.equals("");

        try {
            FileWriter fichier_dot = new FileWriter(nom_fichier + ".dot");
            fichier_dot.write(this.toString());
            fichier_dot.flush();
            Process p = Runtime.getRuntime().exec("dot " + nom_fichier + ".dot -Tpng -o " + nom_fichier + ".png");
            p.waitFor();
        }
        catch(Exception ex) {
            System.out.println("Erreur d'execution de dot");
        }
    }

}
