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

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

/**
 * Mozliwy zestaw dzieci danego wezla (Node).
 *
 * Odpowiada elementowi children w forest.xml.
 *
 * Posiada nazwe produkcji, liste wierzcholkow-dzieci oraz numer
 * elementu children w danym elemencie node (numerujac od 0).
 *
 * @author Piotr Achinger <piotr.achinger at gmail.com>
 */
public class NodeChildren implements Serializable {

    /**
     * Wartosc atrybutu rule elementu children w XML.
     */
    private String rule;

    /**
     * Lista wierzcholkow-dzieci
     */
    private List<Node> children;

    /**
     * Numer elementu children w obrebie elementu node, numerujac od 0.
     */
    private int index;

    /**
     * Lista numerow dzieci oznaczonych jako head
     */
    private List<Integer> heads;

    public NodeChildren(String rule, int index) {
        this.rule = rule;
        this.children = new LinkedList<Node>();
        this.index = index;
        this.heads = new LinkedList<Integer>();
    }

    /**
     * Dodanie kolejnego dziecka.
     *
     * Musza byc dodawane w kolejnosci takiej jak elementy child w forest.xml
     */
    public void addChild(Node child, boolean isHead) {
        this.children.add(child);
        if (isHead)
            this.heads.add(new Integer(children.size() - 1));
    }

    /**
     * Porownanie potrzebne przy MUZG-owaniu
     *
     * @author Karolina Soltys
     */
    public boolean isEquivalentTo(NodeChildren nodeChildren) {
        if (nodeChildren == null || !rule.equals(nodeChildren.getRule()) ||
                children.size() != nodeChildren.getChildren().size()) {
            return false;
        }
        for (int i = 0 ; i < children.size() ; i++) {
            if (!children.get(i).isEquivalentTo(nodeChildren.getChildren().get(i))) {
                return false;
            }
        }
        return true;
    }

    /**
     * Liczba poddrzew.
     *
     * Rowna iloczynowi wartosci atrybutow subtrees wszystkich dzieci.
     */
    public long getSubtrees() {
        long ret = 1;
        for (Node child : children) {
            ret *= child.getSubtrees();
        }
        return ret;
    }

    /**
     * Czy wariant moze byc jest zgodny analiza morfosyntaktyczna NKJP.
     *
     * 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 hasNKJPCompliantNodes() {
        for (Node node : this.getChildren()) {
            if (!node.hasNKJPCompliantVariant()) {
                return false;
            }
        }
        return true;
    }

    public boolean isHead(int n) {
        return heads.contains(new Integer(n));
    }

    /* === G & S === */
    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

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

    public String getRule() {
        return rule;
    }

    public List<Integer> getHeads() {
        return heads;
    }

    @Override
    public String toString() {
        String ret = "\tChildren[rule=" + rule + "; ";

        for (Node ch : children) {
            ret += ch.getId() + ",";
        }

        return ret + "]\n";
    }
}
