package dendrarium.trees;

import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 *
 * @author pta
 */
public class NonterminalNode extends Node {

    private String category;


    /* --- POWIAZANIA RODZINNE --- */
    /**
     * Lista mozliwych zestawow dzieci -- odpowiadaja elementom children
     */
    private List<NodeChildren> children = new LinkedList<NodeChildren>();

    /* --- DANE PRZYDATNE PRZY OBROBCE LASU --- */
    /**
     * Wariant aktualnie wybrany przez dendrologa.
     *
     * Wartosc null oznacza brak decyzji lub terminal.
     */
    private NodeChildren chosenChildren = null;

    public enum ChoiceType implements Serializable {

        NONE("Węzeł do rozstrzygnięcia"),
        TERMINAL("Terminal"),
        MANY_CHILDREN_ONE_SUGGESTED("Automatyczny wybór jedynego sugerowanego spośród wielu wariantów"),
        ONE_SUGGESTED_CHILD("Automatyczny wybór jedynego wariantu; wariant był sugerowany"),
        ONE_NOT_SUGGESTED_CHILD("Automatyczny wybór jedynego wariantu; wariant nie był sugerowany"),
        USER_SUGGESTED("Wybór sugerowanego wariantu dokonany przez Użytkownika"),
        USER_NOT_SUGGESTED("Wybór nie sugerowanego wariantu dokonany przez Użytkownika");

        private String description;

        public String getDescription() {
            return description;
        }

        private ChoiceType(String description) {
            this.description = description;
        }
    }

    /**
     * Typ dokonanego wyboru (przydatny np. przy kolorowaniu wierzcholkow)
     */
    private ChoiceType choiceType = null;

    public NonterminalNode(int id,
            int from, int to, long subtrees,
            String category) {
        super(id, from, to, subtrees);
        this.category = category;
    }

    /**
     * Dodanie kolejnego mozliwego zestawu dzieci.
     *
     * Musza byc dodawane w kolejnosci takiej jak elementy children w forest.xml
     */
    public void addChildren(NodeChildren children) {
        this.children.add(children);
    }

    /**
     * NUMER wybranego zestawu dzieci
     */
    public Integer getChosenChildrenNo() {
        if (chosenChildren != null) {
            return children.indexOf(chosenChildren);
        } else {
            return null;
        }
    }

    public boolean isEquivalentTo(Node otherNode) {
        if (!(otherNode instanceof NonterminalNode)) {
            return false;
        } else {
            NonterminalNode other = (NonterminalNode) otherNode;

            return category.equals(other.category) && to == other.to && from == other.from; // TODO: spytac MW o zasieg
        }
    }

    /**
     * Mozliwy zestaw dzieci o danym numerze.
     *
     * Numerujemy od 0 w takiej kolejnosci w jakiej wystepuja elementy
     * children w forest.xml.
     */
    public Node getChild(int index) {
        return children.toArray(new NodeChildren[0])[0].getChildren().toArray(new Node[0])[index];
    }

    public boolean isLeaf() {
        return (chosenChildren == null);
    }

    /**
     * Czy wezel jest terminalem zgodnym z analiza morfosyntaktyczna NKJP
     * lub posiada wybor zestawu dzieci zgodny z ta analiza.
     *
     * Formalnie:
     *    f(node) = true jesli node jest terminalem
     *    f(node) = true jesli f(children) = true dla PEWNEGO wariantu children
     *                         danego wezla
     *    f(children) = true jesli f(node) = true dla KAZDEGO wezla danego
     *                             wariantu
     */
    public boolean hasNKJPCompliantVariant() {
        for (NodeChildren variant : this.getChildren()) {
            if (variant.hasNKJPCompliantNodes()) {
                return true;
            }
        }
        return false;
    }

    public String getSymbol() {
        return category;
    }

    public String getLabel() {
        return category + "(" + getAttrString() + ")";
    }

    /* === G & S === */
    public ChoiceType getChoiceType() {
        return choiceType;
    }

    public void setChoiceType(ChoiceType choiceType) {
        this.choiceType = choiceType;
    }

    public List<NodeChildren> getChildren() {
        return children;
    }

    public void setChosenChildren(NodeChildren chosenChildren) {
        this.chosenChildren = chosenChildren;
    }

    public NodeChildren getChosenChildren() {
        return chosenChildren;
    }

    public String getCategory() {
        return category;
    }
}
