package algorithmen;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.nio.file.*;
import java.util.Arrays;

import graph.*;
/**
 * Dieser Algorithmus findet die kürzesten Pfade in einem gewichteten Graphen.
 * Algorithmus: Dijkstra
 *
 * @version 7.1 from 12.02.2025
 * @author Thomas Schaller
 */

public class GraphAlgo_DijkstraMitVorgaenger extends GraphAlgo {

    // Anfang Attribute
    public  String getBezeichnung() {
        return "Kürzester Pfad (Dijkstra mit Vorgänger)";
    }


    public void init() {
        List<Knoten> alle = g.getAlleKnoten();
        for(Knoten k : alle) {
            k.set("Vorgänger","-");
            k.set("Entfernung",Double.POSITIVE_INFINITY);
            k.setSortierkriterium("Entfernung");
        }
       gp.getGraphOptions().knotenKurztext = new String[]{"Entfernung","Vorgänger"};
       gp.getGraphOptions().knotenLangtext = new String[]{"Infotext","Entfernung","Vorgänger","Markiert","Besucht"};
    }
    
    public void fuehreAlgorithmusAus() throws InterruptedException  {
        if (g.getAnzahlKnoten()==0) {
            return;
        } 


        
        info("Erzeuge leere toDo-Liste und füge Startknoten hinzu");
        List<Knoten> toDo = new ArrayList<Knoten>();
        getStartKnoten().setBesucht(true);
        getStartKnoten().set("Entfernung", 0);
        toDo.add(getStartKnoten());

        while(toDo.size()>0) {
            info("Sortiere toDo-Liste nach der Entfernung");
            Collections.sort(toDo);
            info("Nimm ersten Knoten aus der toDo-Liste (momentan "+toDo.size()+" Elemente) heraus");
            Knoten k = toDo.remove(0);
            infoIndentMore();
            k.setMarkiert(true);
            info("Markiere den Knoten");
            info("Er hat Entfernung "+k.getString("Entfernung"));
            info("Für jeden Nachbarknoten");
            infoIndentMore();
            for(Knoten n : g.getNachbarknoten(k)) {
                if(!n.isMarkiert()){
                    if(!n.getInfotext().isEmpty()) {
                      info("- "+n.getInfotext()+" ist noch nicht markiert");   
                    } else {
                      info("- Knoten Nr. "+g.getNummer(n)+" ist noch nicht markiert");   
                    }
                    Kante ka = g.getKante(k, n);
                    if(!n.isBesucht() || n.getDouble("Entfernung") > k.getDouble("Entfernung") + ka.getGewicht()){
                        if(n.isBesucht()) {
                            List<Kante> eingehend = g.getEingehendeKanten(n, ka2 -> !ka2.isGeloescht() && ka2.isMarkiert());
                            Kante alterWeg = eingehend.get(0);
                            // Kante alterWeg = g.beschraenkeKantenAuf(g.getEingehendeKanten(n), Graph.MARKIERT, Graph.NICHTGELOESCHT).get(0);
                            // alterWeg.setGeloescht(true); 
                            // alterWeg.setMarkiert(false);
                            alterWeg.setGeloescht(true); 
                            alterWeg.setMarkiert(false);

                            info(" loesche bisherigen Weg dorthin");
                        }
                        
                        n.set("Entfernung", k.getInt("Entfernung")+ka.getGewicht());
                        if(k.getInfotext().equals("")) {
                          n.set("Vorgänger",g.getNummer(k));
                        } else {
                          n.set("Vorgänger",k.getInfotext());
                        }
                        if(!toDo.contains(n)) toDo.add(n);
                        ka.setMarkiert(true);
                        n.setBesucht(true);
                        info("  setze Entfernung "+n.getString("Entfernung")+" und füge ggf. ToDo-Liste hinzu.");
                        info("  toDo-Liste hat jetzt "+toDo.size()+" Elemente");
                    } else {
                        info("  keine neue beste Entfernung");
                        ka.setGeloescht(true);
                    }
                } 
            }
            infoIndentLess();
            infoIndentLess();
            step();
        }
        info("ToDo-Liste fertig abgearbeitet");

    } // end
    // Ende Methoden

}

