/*
 * TerminalGraphNode.java
 *
 * Autor: Piotr Achinger <piotr.achinger at gmail.com>
 */
package dendrarium.trees.terminals;

import dendrarium.trees.Node;
import dendrarium.trees.TerminalNode;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

/**
 * Wierzcholek w grafie terminali.
 * 
 * W forest.xml wystepuje tylko jako wartosc atrybutu from lub to jakiegos
 * wezla. Terminal jest krawedzia pomiedzy wierzcholkami odpowiadajacymi
 * jego from oraz to.
 * 
 * Glowna rola wierzcholka to znajdowanie najkrotszej sciezki do 
 * innego wierzcholka. W tym celu pamieta on i aktualizuje kierunki
 * wychodzacych najkrotszych sciezek.
 *
 * @author Piotr Achinger <piotr.achinger at gmail.com>
 */
class TerminalGraphNode {

    /**
     * Krawedz -- para (dokad, terminal).
     */
    class Transition {

        TerminalGraphNode to;

        TerminalNode terminal;

        public Transition(TerminalGraphNode to, TerminalNode node) {
            this.to = to;
            this.terminal = node;
        }
    }

    /* identyfikator pozycji w zdaniu (wartosc from= lub to=) */
    int id;

    /* od linear extension - numerek taki, ze jesli pozycja x jest na pewno
     * przed pozycja y, to x.le < y.le
     */
    int le = -1;

    /* przejscia z tej pozycji:  pary (dokad, etykieta krawedzi (terminal)  */
    Set<Transition> transitions = new HashSet();

    Map<Integer, Transition> shortestPathDirection = new HashMap();

    Map<Integer, Integer> shortestPathLength = new HashMap();

    TerminalGraphNode(int id) {
        this.id = id;
    }

    void addTransition(TerminalGraphNode dest, TerminalNode terminal) {
        Transition newTransition = new Transition(dest, terminal);
        transitions.add(newTransition);
        updateShortestPath(dest.id, 1, newTransition);

        for (Integer to : dest.shortestPathLength.keySet()) {
            int length = dest.shortestPathLength.get(to);

            updateShortestPath(to, length + 1, newTransition);
        }

//        System.out.println("TRANSITION " + id + "->" + dest.id + " VIA " + node.getLabel());
    }

    void updateShortestPaths() {
        Set<Integer> tos = new HashSet();
        for (Transition transition : transitions) {
            if (tos.contains(transition.to.id)) {
                continue;
            }
            tos.add(transition.to.id);
            transition.to.updateShortestPaths();
            for (Integer to : transition.to.shortestPathLength.keySet()) {
                int length = transition.to.shortestPathLength.get(to);

                updateShortestPath(to, length + 1, transition);
            }
        }
    }

    void generateLinearExtension() {
        int max = 0;

        for (Transition transition : transitions) {
            if (transition.to.le == -1) {
                transition.to.generateLinearExtension();
            }

            if (transition.to.le > max) {
                max = transition.to.le;
            }
        }

        this.le = max + 1;
    }

    public LinkedList<TerminalNode> shortestPathTo(int dest) {
        if (dest == this.id) {
            return new LinkedList<TerminalNode>();
        } else {
            Transition transition = shortestPathDirection.get(dest);
            LinkedList<TerminalNode> list = transition.to.shortestPathTo(dest);
            list.addFirst(transition.terminal);
            return list;
        }
    }

    private void updateShortestPath(int to, int length, Transition via) {
        if (!shortestPathDirection.containsKey(to) || shortestPathLength.get(to) > length) {
            shortestPathDirection.put(to, via);
            shortestPathLength.put(to, length);
        }
    }
}
