    001    package org.maltparser.core.syntaxgraph.node;
    002
    003    import java.util.NoSuchElementException;
    004    import java.util.Set;
    005    import java.util.SortedSet;
    006    import java.util.TreeSet;
    007
    008    import org.maltparser.core.exception.MaltChainedException;
    009    import org.maltparser.core.helper.SystemLogger;
    010    import org.maltparser.core.symbol.SymbolTable;
    011    import org.maltparser.core.syntaxgraph.LabelSet;
    012    import org.maltparser.core.syntaxgraph.SyntaxGraphException;
    013    import org.maltparser.core.syntaxgraph.edge.Edge;
    014
    015
    016    public class Token extends GraphNode implements TokenNode, DependencyNode, PhraseStructureNode {
    017            /**
    018             * the previous terminal node in the linear precedence
    019             */
    020            protected TokenNode predecessor = null;
    021            /**
    022             * the next terminal node in the linear precedence
    023             */
    024            protected TokenNode successor = null;
    025
    026            /**
    027             * a reference to a node where the node is part of a component. If the node is unconnected it will reference to it self.
    028             */
    029            protected DependencyNode component;
    030            protected int rank;
    031
    032            protected int index;
    033
    034            protected PhraseStructureNode parent;
    035            protected final SortedSet<DependencyNode> heads;
    036            protected final SortedSet<DependencyNode> leftDependents;
    037            protected final SortedSet<DependencyNode> rightDependents;
    038
    039
    040            public Token() throws MaltChainedException {
    041                    parent = null;
    042                    heads = new TreeSet<DependencyNode>();
    043                    leftDependents = new TreeSet<DependencyNode>();
    044                    rightDependents = new TreeSet<DependencyNode>();
    045                    clear();
    046            }
    047
    048            /**
    049             * Sets the predecessor terminal node in the linear order of the terminal nodes.
    050             *
    051             * @param predecessor the predecessor terminal node
    052             */
    053            public void setPredecessor(TokenNode predecessor) {
    054                    this.predecessor = predecessor;
    055            }
    056
    057            /**
    058             * Sets the predecessor terminal node in the linear order of the terminal nodes.
    059             *
    060             * @param successor the successor terminal node
    061             */
    062            public void setSuccessor(TokenNode successor) {
    063                    this.successor = successor;
    064            }
    065
    066            /**
    067             * Returns the predecessor terminal node in the linear order of the terminal nodes.
    068             *
    069             * @return the predecessor terminal node in the linear order of the terminal nodes.
    070             */
    071            public TokenNode getPredecessor() {
    072                    return predecessor;
    073            }
    074
    075            /**
    076             * Returns the successor terminal node in the linear order of the terminal nodes.
    077             *
    078             * @return the successor terminal node in the linear order of the terminal nodes.
    079             */
    080            public TokenNode getSuccessor() {
    081                    return successor;
    082            }
    083
    084            public int getRank() {
    085                    return rank;
    086            }
    087
    088            public void setRank(int r) {
    089                    this.rank = r;
    090            }
    091
    092            public DependencyNode findComponent() {
    093                    return findComponent(this);
    094            }
    095
    096            private DependencyNode findComponent(DependencyNode x) {
    097                    if (x != x.getComponent()) {
    098                            x.setComponent(findComponent(x.getComponent()));
    099                    }
    100                    return x.getComponent();
    101            }
    102
    103            public DependencyNode getComponent() {
    104                    return component;
    105            }
    106
    107            public void setComponent(DependencyNode x) {
    108                    this.component = x;
    109            }
    110
    111            public void addIncomingEdge(Edge in) throws MaltChainedException {
    112                    super.addIncomingEdge(in);
    113                    if (in.getSource() != null) {
    114                            if (in.getType() == Edge.DEPENDENCY_EDGE && in.getSource() instanceof DependencyNode) {
    115                                    if (heads.size() >= 1) {
    116                                            heads.add((DependencyNode)in.getSource());
    117                                    } else {
    118                                            heads.add((DependencyNode)in.getSource());
    119                                    }
    120                            } else if (in.getType() == Edge.PHRASE_STRUCTURE_EDGE && in.getSource() instanceof PhraseStructureNode) {
    121                                    parent = (PhraseStructureNode)in.getSource();
    122                            }
    123                    }
    124            }
    125
    126            public void removeIncomingEdge(Edge in) throws MaltChainedException {
    127                    super.removeIncomingEdge(in);
    128                    if (in.getSource() != null) {
    129                            if (in.getType() == Edge.DEPENDENCY_EDGE && in.getSource() instanceof DependencyNode) {
    130                                    heads.remove((DependencyNode)in.getSource());
    131                            } else if (in.getType() == Edge.PHRASE_STRUCTURE_EDGE && in.getSource() instanceof PhraseStructureNode) {
    132                                    if (in.getSource() == parent) {
    133                                            this.parent = null;
    134                                    }
    135                            }
    136                    }
    137            }
    138
    139            public void addOutgoingEdge(Edge out) throws MaltChainedException {
    140                    super.addOutgoingEdge(out);
    141                    if (out.getType() == Edge.DEPENDENCY_EDGE && out.getTarget() instanceof DependencyNode) {
    142                            final DependencyNode dependent = (DependencyNode)out.getTarget();
    143                            if (compareTo(dependent) > 0) {
    144                                    leftDependents.add((DependencyNode)dependent);
    145                            } else if (compareTo(dependent) < 0) {
    146                                    rightDependents.add((DependencyNode)dependent);
    147                            }
    148                    }
    149            }
    150
    151            public void removeOutgoingEdge(Edge out) throws MaltChainedException {
    152                    super.removeOutgoingEdge(out);
    153                    if (out.getType() == Edge.DEPENDENCY_EDGE && out.getTarget() instanceof DependencyNode) {
    154                            final DependencyNode dependent = (DependencyNode)out.getTarget();
    155                            if (compareTo(dependent) > 0) {
    156                                    leftDependents.remove((DependencyNode)dependent);
    157                            } else if (compareTo(dependent) < 0) {
    158                                    rightDependents.remove((DependencyNode)dependent);
    159                            }
    160                    }
    161            }
    162
    163            public void setIndex(int index) throws MaltChainedException {
    164                    if (index > 0) {
    165                            this.index = index;
    166                    } else {
    167                            throw new SyntaxGraphException("A terminal node must have a positive integer value and not index "+index+". ");
    168                    }
    169            }
    170
    171            public int getIndex() {
    172                    return index;
    173            }
    174
    175            public int getCompareToIndex() {
    176                    return index;
    177            }
    178
    179            public boolean isRoot() {
    180                    return false;
    181            }
    182
    183            public DependencyNode getAncestor() throws MaltChainedException {
    184                    if (!this.hasHead()) {
    185                            return this;
    186                    }
    187
    188                    DependencyNode tmp = this;
    189                    while (tmp.hasHead()) {
    190                            tmp = tmp.getHead();
    191                    }
    192                    return tmp;
    193            }
    194
    195            public DependencyNode getProperAncestor() throws MaltChainedException {
    196                    if (!this.hasHead()) {
    197                            return null;
    198                    }
    199
    200                    DependencyNode tmp = this;
    201                    while (tmp.hasHead()) {
    202                            tmp = tmp.getHead();
    203                    }
    204                    return tmp;
    205            }
    206
    207            public ComparableNode getLeftmostProperDescendant() throws MaltChainedException {
    208                    ComparableNode candidate = null;
    209                    ComparableNode tmp = null;
    210                    for (DependencyNode ldep : leftDependents) {
    211                            if (candidate == null) {
    212                                    candidate = ldep;
    213                            } else if (ldep.getIndex() < candidate.getIndex() ) {
    214                                    candidate = ldep;
    215                            }
    216                            tmp = ((Token)ldep).getLeftmostProperDescendant();
    217                            if (tmp == null) {
    218                                    continue;
    219                            }
    220                            if (candidate == null) {
    221                                    candidate = tmp;
    222                            } else if (tmp.getIndex() < candidate.getIndex() ) {
    223                                    candidate = tmp;
    224                            }
    225                            if (candidate.getIndex() == 1) {
    226                                    return candidate;
    227                            }
    228                    }
    229                    for (DependencyNode rdep : rightDependents) {
    230                            if (candidate == null) {
    231                                    candidate = rdep;
    232                            } else if (rdep.getIndex() < candidate.getIndex() ) {
    233                                    candidate = rdep;
    234                            }
    235                            tmp = ((Token)rdep).getLeftmostProperDescendant();
    236                            if (tmp == null) {
    237                                    continue;
    238                            }
    239                            if (candidate == null) {
    240                                    candidate = tmp;
    241                            } else if (tmp.getIndex() < candidate.getIndex() ) {
    242                                    candidate = tmp;
    243                            }
    244                            if (candidate.getIndex() == 1) {
    245                                    return candidate;
    246                            }
    247                    }
    248                    return candidate;
    249            }
    250
    251            public ComparableNode getRightmostProperDescendant() throws MaltChainedException {
    252                    ComparableNode candidate = null;
    253                    ComparableNode tmp = null;
    254                    for (DependencyNode ldep : leftDependents) {
    255                            if (candidate == null) {
    256                                    candidate = ldep;
    257                            } else if (ldep.getIndex() > candidate.getIndex() ) {
    258                                    candidate = ldep;
    259                            }
    260                            tmp = ((Token)ldep).getRightmostProperDescendant();
    261                            if (tmp == null) {
    262                                    continue;
    263                            }
    264                            if (candidate == null) {
    265                                    candidate = tmp;
    266                            } else if (tmp.getIndex() > candidate.getIndex() ) {
    267                                    candidate = tmp;
    268                            }
    269                    }
    270                    for (DependencyNode rdep : rightDependents) {
    271                            if (candidate == null) {
    272                                    candidate = rdep;
    273                            } else if (rdep.getIndex() > candidate.getIndex() ) {
    274                                    candidate = rdep;
    275                            }
    276                            tmp = ((Token)rdep).getRightmostProperDescendant();
    277                            if (tmp == null) {
    278                                    continue;
    279                            }
    280                            if (candidate == null) {
    281                                    candidate = tmp;
    282                            } else if (tmp.getIndex() > candidate.getIndex() ) {
    283                                    candidate = tmp;
    284                            }
    285                    }
    286                    return candidate;
    287            }
    288
    289            public ComparableNode getLeftmostDescendant() throws MaltChainedException {
    290                    ComparableNode candidate = this;
    291                    ComparableNode tmp = null;
    292                    for (DependencyNode ldep : leftDependents) {
    293                            if (candidate == null) {
    294                                    candidate = ldep;
    295                            } else if (ldep.getIndex() < candidate.getIndex() ) {
    296                                    candidate = ldep;
    297                            }
    298                            tmp = ((Token)ldep).getLeftmostDescendant();
    299                            if (tmp == null) {
    300                                    continue;
    301                            }
    302                            if (candidate == null) {
    303                                    candidate = tmp;
    304                            } else if (tmp.getIndex() < candidate.getIndex() ) {
    305                                    candidate = tmp;
    306                            }
    307                            if (candidate.getIndex() == 1) {
    308                                    return candidate;
    309                            }
    310                    }
    311                    for (DependencyNode rdep : rightDependents) {
    312                            if (candidate == null) {
    313                                    candidate = rdep;
    314                            } else if (rdep.getIndex() < candidate.getIndex() ) {
    315                                    candidate = rdep;
    316                            }
    317                            tmp = ((Token)rdep).getLeftmostDescendant();
    318                            if (tmp == null) {
    319                                    continue;
    320                            }
    321                            if (candidate == null) {
    322                                    candidate = tmp;
    323                            } else if (tmp.getIndex() < candidate.getIndex() ) {
    324                                    candidate = tmp;
    325                            }
    326                            if (candidate.getIndex() == 1) {
    327                                    return candidate;
    328                            }
    329                    }
    330                    return candidate;
    331            }
    332
    333            public ComparableNode getRightmostDescendant() throws MaltChainedException {
    334                    ComparableNode candidate = this;
    335                    ComparableNode tmp = null;
    336                    for (DependencyNode ldep : leftDependents) {
    337                            if (candidate == null) {
    338                                    candidate = ldep;
    339                            } else if (ldep.getIndex() > candidate.getIndex() ) {
    340                                    candidate = ldep;
    341                            }
    342                            tmp = ((Token)ldep).getRightmostDescendant();
    343                            if (tmp == null) {
    344                                    continue;
    345                            }
    346                            if (candidate == null) {
    347                                    candidate = tmp;
    348                            } else if (tmp.getIndex() > candidate.getIndex() ) {
    349                                    candidate = tmp;
    350                            }
    351                    }
    352                    for (DependencyNode rdep : rightDependents) {
    353                            if (candidate == null) {
    354                                    candidate = rdep;
    355                            } else if (rdep.getIndex() > candidate.getIndex() ) {
    356                                    candidate = rdep;
    357                            }
    358                            tmp = ((Token)rdep).getRightmostDescendant();
    359                            if (tmp == null) {
    360                                    continue;
    361                            }
    362                            if (candidate == null) {
    363                                    candidate = tmp;
    364                            } else if (tmp.getIndex() > candidate.getIndex() ) {
    365                                    candidate = tmp;
    366                            }
    367                    }
    368                    return candidate;
    369            }
    370
    371            public PhraseStructureNode getParent() {
    372                    return parent;
    373            }
    374
    375            public Edge getParentEdge() throws MaltChainedException {
    376                    for (Edge e : incomingEdges) {
    377                            if (e.getSource() == parent && e.getType() == Edge.PHRASE_STRUCTURE_EDGE) {
    378                                    return e;
    379                            }
    380                    }
    381                    return null;
    382            }
    383
    384            public String getParentEdgeLabelSymbol(SymbolTable table) throws MaltChainedException {
    385                    for (Edge e : incomingEdges) {
    386                            if (e.getSource() == parent && e.getType() == Edge.PHRASE_STRUCTURE_EDGE) {
    387                                    return e.getLabelSymbol(table);
    388                            }
    389                    }
    390                    return null;
    391            }
    392
    393            public int getParentEdgeLabelCode(SymbolTable table) throws MaltChainedException {
    394                    for (Edge e : incomingEdges) {
    395                            if (e.getSource() == parent && e.getType() == Edge.PHRASE_STRUCTURE_EDGE) {
    396                                    return e.getLabelCode(table);
    397                            }
    398                    }
    399                    return -1;
    400            }
    401
    402            public boolean hasParentEdgeLabel(SymbolTable table) throws MaltChainedException {
    403                    for (Edge e : incomingEdges) {
    404                            if (e.getSource() == parent && e.getType() == Edge.PHRASE_STRUCTURE_EDGE) {
    405                                    return e.hasLabel(table);
    406                            }
    407                    }
    408                    return false;
    409            }
    410
    411            public boolean hasAtMostOneHead() {
    412                    return heads.size() <= 1;
    413            }
    414
    415            public boolean hasAncestorInside(int left, int right) throws MaltChainedException {
    416                    DependencyNode tmp = this;
    417                    if (tmp.getHead() != null) {
    418                            tmp = tmp.getHead();
    419                            if (tmp.getIndex() >= left && tmp.getIndex() <= right) {
    420                                    return true;
    421                            }
    422                    }
    423                    return false;
    424            }
    425
    426            public Set<Edge> getHeadEdges() throws MaltChainedException {
    427                    return incomingEdges;
    428            }
    429
    430            public Set<DependencyNode> getHeads() throws MaltChainedException {
    431                    return heads;
    432            }
    433
    434            public boolean hasHead() {
    435                    return heads.size() != 0;
    436            }
    437
    438            public DependencyNode getHead() throws MaltChainedException {
    439                    if (!hasHead()) {
    440                            return null;
    441                    }
    442                    if (heads.size() > 1) {
    443                            throw new SyntaxGraphException("The dependency node is multi-headed and it is ambigious to return a single-head dependency node. ");
    444                    }
    445                    // heads.first();
    446                    for (DependencyNode head : heads) {
    447                            return head;
    448                    }
    449                    return null;
    450            }
    451
    452            public Edge getHeadEdge() throws MaltChainedException {
    453                    if (heads.size() == 0) {
    454                            return null;
    455                    }
    456                    if (incomingEdges.size() == 1 && incomingEdges.first() instanceof DependencyNode) {
    457                            return incomingEdges.first();
    458                    }
    459                    if (heads.size() == 1) {
    460                            for (Edge e : incomingEdges) {
    461                                    if (e.getSource() == heads.first()) {
    462                                            return e;
    463                                    }
    464                            }
    465                    }
    466                    return null;
    467            }
    468
    469            public void addHeadEdgeLabel(SymbolTable table, String symbol) throws MaltChainedException {
    470                    if (hasHead()) {
    471                            getHeadEdge().addLabel(table, symbol);
    472                    }
    473            }
    474
    475            public void addHeadEdgeLabel(SymbolTable table, int code) throws MaltChainedException {
    476                    if (hasHead()) {
    477                            getHeadEdge().addLabel(table, code);
    478                    }
    479            }
    480
    481            public void addHeadEdgeLabel(LabelSet labelSet) throws MaltChainedException {
    482                    if (hasHead()) {
    483                            getHeadEdge().addLabel(labelSet);
    484                    }
    485            }
    486
    487            public boolean hasHeadEdgeLabel(SymbolTable table) throws MaltChainedException {
    488                    if (!hasHead()) {
    489                            return false;
    490                    }
    491                    return getHeadEdge().hasLabel(table);
    492            }
    493
    494            public String getHeadEdgeLabelSymbol(SymbolTable table) throws MaltChainedException {
    495                    return getHeadEdge().getLabelSymbol(table);
    496            }
    497
    498            public int getHeadEdgeLabelCode(SymbolTable table) throws MaltChainedException {
    499                    if (!hasHead()) {
    500                            return 0;
    501                    }
    502                    return getHeadEdge().getLabelCode(table);
    503            }
    504
    505            public boolean isHeadEdgeLabeled() throws MaltChainedException {
    506                    if (!hasHead()) {
    507                            return false;
    508                    }
    509                    return getHeadEdge().isLabeled();
    510            }
    511
    512            public int nHeadEdgeLabels() throws MaltChainedException {
    513                    if (!hasHead()) {
    514                            return 0;
    515                    }
    516                    return getHeadEdge().nLabels();
    517            }
    518
    519            public Set<SymbolTable> getHeadEdgeLabelTypes() throws MaltChainedException {
    520                    return getHeadEdge().getLabelTypes();
    521            }
    522
    523            public LabelSet getHeadEdgeLabelSet() throws MaltChainedException {
    524                    return getHeadEdge().getLabelSet();
    525            }
    526
    527            public boolean hasDependent() {
    528                    return hasLeftDependent() || hasRightDependent();
    529            }
    530
    531            /**
    532             * Returns <code>true</code> if the node has one or more left dependents, otherwise <code>false</code>.
    533             *
    534             * @return <code>true</code> if the node has one or more left dependents, otherwise <code>false</code>.
    535             */
    536            public boolean hasLeftDependent() {
    537                    return !leftDependents.isEmpty();
    538            }
    539
    540            /**
    541             * Returns the left dependent at the position <code>index</code>, where <code>index==0</code> equals the left most dependent.
    542             *
    543             * @param index the index
    544             * @return the left dependent at the position <code>index</code>, where <code>index==0</code> equals the left most dependent
    545             */
    546            public DependencyNode getLeftDependent(int index) {
    547                    if (0 <= index && index < leftDependents.size()) {
    548                            int i = 0;
    549                            DependencyNode candidate = null;
    550
    551                            for (DependencyNode node : leftDependents) {
    552                                    candidate = node;
    553                                    if (i == index) {
    554                                            return candidate;
    555                                    }
    556                                    i++;
    557                            }
    558                    }
    559                    return null;
    560            }
    561
    562            /**
    563             * Return the number of left dependents
    564             *
    565             * @return the number of left dependents
    566             */
    567            public int getLeftDependentCount() {
    568                    return leftDependents.size();
    569            }
    570
    571            public SortedSet<DependencyNode> getLeftDependents() {
    572                    return leftDependents;
    573            }
    574
    575            /**
    576             * Returns the left sibling if it exists, otherwise <code>null</code>
    577             *
    578             * @return the left sibling if it exists, otherwise <code>null</code>
    579             */
    580            public DependencyNode getLeftSibling() throws MaltChainedException {
    581                    if (getHead() == null) {
    582                            return null;
    583                    }
    584
    585                    DependencyNode candidate = null;
    586                    for (DependencyNode node : getHead().getLeftDependents()) {
    587                            if (node == this) {
    588                                    return candidate;
    589                            }
    590                            candidate = node;
    591                    }
    592                    for (DependencyNode node : getHead().getRightDependents()) {
    593                            if (node == this) {
    594                                    return candidate;
    595                            }
    596                            candidate = node;
    597                    }
    598                    return null;
    599            }
    600
    601            /**
    602             * Returns the left sibling at the same side of head as the node it self. If not found <code>null</code is returned
    603             *
    604             * @return the left sibling at the same side of head as the node it self. If not found <code>null</code is returned
    605             */
    606            public DependencyNode getSameSideLeftSibling() throws MaltChainedException {
    607                    if (getHead() == null) {
    608                            return null;
    609                    } else if (this.getIndex() < getHead().getIndex()) {
    610                            try {
    611                                    return getHead().getLeftDependents().headSet(this).last();
    612                            } catch (NoSuchElementException e) {
    613                                    return null;
    614                            }
    615                    } else if (this.getIndex() > getHead().getIndex()) {
    616                            try {
    617                                    return getHead().getRightDependents().headSet(this).last();
    618                            } catch (NoSuchElementException e) {
    619                                    return null;
    620                            }
    621                    }
    622                    return null;
    623            }
    624
    625            /**
    626             * Returns the closest left dependent to the node it self, if not found <code>null</code> is returned.
    627             *
    628             * @return the closest left dependent to the node it self, if not found <code>null</code> is returned.
    629             */
    630            public DependencyNode getClosestLeftDependent() {
    631                    try {
    632                            return leftDependents.last();
    633                    } catch (NoSuchElementException e) {
    634                            return null;
    635                    }
    636            }
    637
    638            public DependencyNode getLeftmostDependent() {
    639                    for (DependencyNode dep : leftDependents) {
    640                            return dep;
    641                    }
    642                    return null;
    643    //              try {
    644    //                      return leftDependents.first();
    645    //              } catch (NoSuchElementException e) {
    646    //                      return null;
    647    //              }
    648            }
    649
    650            public DependencyNode getRightDependent(int index) {
    651                    int size = rightDependents.size();
    652                    if (index < size) {
    653                            return rightDependents.toArray(new DependencyNode[size])[size - 1 - index];
    654                    }
    655                    return null;
    656    //              if (0 <= index && index < rightDependents.size()) {
    657    //                      int i = 0;
    658    //                      DependencyNode candidate = null;
    659    //
    660    //                      for (DependencyNode node : rightDependents) {
    661    //                              candidate = node;
    662    //                              if (i == index) {
    663    //                                      return candidate;
    664    //                              }
    665    //                              i++;
    666    //                      }
    667    //              }
    668    //              return null;
    669            }
    670
    671            /**
    672             * Return the number of right dependents
    673             *
    674             * @return the number of right dependents
    675             */
    676            public int getRightDependentCount() {
    677                    return rightDependents.size();
    678            }
    679
    680            /**
    681             * Returns a sorted set of right dependents.
    682             *
    683             * @return a sorted set of right dependents.
    684             */
    685            public SortedSet<DependencyNode> getRightDependents() {
    686                    return rightDependents;
    687            }
    688
    689            /**
    690             * Returns the right sibling if it exists, otherwise <code>null</code>
    691             *
    692             * @return the right sibling if it exists, otherwise <code>null</code>
    693             */
    694            public DependencyNode getRightSibling() throws MaltChainedException {
    695                    if (getHead() == null) {
    696                            return null;
    697                    }
    698
    699                    for (DependencyNode node : getHead().getLeftDependents()) {
    700                            if (node.getIndex() > this.getIndex()) {
    701                                    return node;
    702                            }
    703                    }
    704                    for (DependencyNode node : getHead().getRightDependents()) {
    705                            if (node.getIndex() > this.getIndex()) {
    706                                    return node;
    707                            }
    708                    }
    709                    return null;
    710            }
    711
    712            /**
    713             * Returns the right sibling at the same side of head as the node it self. If not found <code>null</code is returned
    714             *
    715             * @return the right sibling at the same side of head as the node it self. If not found <code>null</code is returned
    716             */
    717            public DependencyNode getSameSideRightSibling() throws MaltChainedException {
    718                    if (getHead() == null) {
    719                            return null;
    720                    } else if (this.getIndex() < getHead().getIndex()) {
    721                            final SortedSet<DependencyNode> tailSet = getHead().getLeftDependents().tailSet(this);
    722                            if (tailSet.size() <= 1)  {
    723                                    return null;
    724                            }
    725                            return tailSet.toArray(new DependencyNode[tailSet.size()])[1];
    726                    } else if (this.getIndex() > getHead().getIndex()) {
    727                            final SortedSet<DependencyNode> tailSet = getHead().getRightDependents().tailSet(this);
    728                            if (tailSet.size() <= 1)  {
    729                                    return null;
    730                            }
    731                            return tailSet.toArray(new DependencyNode[tailSet.size()])[1];
    732                    }
    733                    return null;
    734            }
    735
    736            /**
    737             * Returns the closest right dependent to the node it self, if not found <code>null</code> is returned.
    738             *
    739             * @return the closest right dependent to the node it self, if not found <code>null</code> is returned.
    740             */
    741            public DependencyNode getClosestRightDependent() {
    742                    for (DependencyNode dep : rightDependents) {
    743                            return dep;
    744                    }
    745                    return null;
    746    //              try {
    747    //                      return rightDependents.first();
    748    //              } catch (NoSuchElementException e) {
    749    //                      return null;
    750    //              }
    751            }
    752
    753            public DependencyNode getRightmostDependent() {
    754                    int n = rightDependents.size();
    755                    int i = 1;
    756                    for (DependencyNode node : rightDependents) {
    757                            if (i == n) {
    758                                    return node;
    759                            }
    760                            i++;
    761                    }
    762                    return null;
    763    //              try {
    764    //                      return rightDependents.last();
    765    //              } catch (NoSuchElementException e) {
    766    //                      return null;
    767    //              }
    768            }
    769
    770            protected void getDependencyDominationSet(SortedSet<DependencyNode> dominationSet) {
    771                    if (leftDependents.size() > 0 || rightDependents.size() > 0) {
    772                            dominationSet.addAll(leftDependents);
    773                            dominationSet.addAll(rightDependents);
    774
    775                            for (DependencyNode node : leftDependents) {
    776                                    ((Token)node).getDependencyDominationSet(dominationSet);
    777                            }
    778                            for (DependencyNode node : rightDependents) {
    779                                    ((Token)node).getDependencyDominationSet(dominationSet);
    780                            }
    781                    }
    782            }
    783
    784    //      private SortedSet<DependencyNode> getDependencyDominationSet() {
    785    //              SortedSet<DependencyNode> dominationSet = new TreeSet<DependencyNode>();
    786    //              getDependencyDominationSet(dominationSet);
    787    //              return dominationSet;
    788    //      }
    789
    790
    791            /**
    792             * Returns <code>true</code> if the node has one or more right dependents, otherwise <code>false</code>.
    793             *
    794             * @return <code>true</code> if the node has one or more right dependents, otherwise <code>false</code>.
    795             */
    796            public boolean hasRightDependent() {
    797                    return !rightDependents.isEmpty();
    798            }
    799
    800            public boolean isProjective() throws MaltChainedException {
    801                    if (hasHead() && !getHead().isRoot()) {
    802                            final DependencyNode head = getHead();
    803                            if (getHead().getIndex() < this.getIndex()) {
    804                                    TokenNode terminals = ((TokenNode)head);
    805                                    DependencyNode tmp = null;
    806                                    while (true) {
    807                                            if (terminals == null || terminals.getSuccessor() == null) {
    808                                                    return false;
    809                                            }
    810                                            if (terminals.getSuccessor() == this) {
    811                                                    break;
    812                                            }
    813                                            tmp = terminals = terminals.getSuccessor();
    814                                            while (tmp != this && tmp != head) {
    815                                                    if (!tmp.hasHead()) {
    816                                                            return false;
    817                                                    }
    818                                                    tmp = tmp.getHead();
    819                                            }
    820                                    }
    821                            } else {
    822                                    TokenNode terminals = ((TokenNode)this);
    823                                    DependencyNode tmp = null;
    824                                    while (true) {
    825                                            if (terminals == null || terminals.getSuccessor() == null) {
    826                                                    return false;
    827                                            }
    828                                            if (terminals.getSuccessor() == head) {
    829                                                    break;
    830                                            }
    831                                            tmp = terminals = terminals.getSuccessor();
    832                                            while (tmp != this && tmp != head) {
    833                                                    if (!tmp.hasHead()) {
    834                                                            return false;
    835                                                    }
    836                                                    tmp = tmp.getHead();
    837                                            }
    838                                    }
    839                            }
    840                    }
    841                    return true;
    842            }
    843
    844            public int getDependencyNodeDepth() throws MaltChainedException {
    845                    DependencyNode tmp = this;
    846                    int depth = 0;
    847                    while (tmp.hasHead()) {
    848                            depth++;
    849                            tmp = tmp.getHead();
    850                    }
    851                    return depth;
    852            }
    853
    854            public void clear() throws MaltChainedException {
    855                    super.clear();
    856                    predecessor = null;
    857                    successor = null;
    858                    component = this;
    859                    rank = 0;
    860                    parent = null;
    861                    heads.clear();
    862                    leftDependents.clear();
    863                    rightDependents.clear();
    864            }
    865
    866            @Override
    867            public int compareTo(ComparableNode that) {
    868                    final int BEFORE = -1;
    869                final int EQUAL = 0;
    870                final int AFTER = 1;
    871                if (this == that) return EQUAL;
    872
    873                if (that instanceof TokenNode) {
    874                        if (this.index < that.getCompareToIndex()) return BEFORE;
    875                        if (this.index > that.getCompareToIndex()) return AFTER;
    876                        return super.compareTo(that);
    877                }
    878                if (that instanceof NonTerminalNode) {
    879                    try {
    880                                final int thisLCorner = this.index;
    881                                final int thatLCorner = that.getLeftmostProperDescendantIndex();
    882                                final int thisRCorner = this.index;
    883                                final int thatRCorner = that.getRightmostProperDescendantIndex();
    884
    885    //                          if (thisLCorner == -1 || thatLCorner == -1) {
    886    //                                  if (thisRCorner < thatRCorner) return BEFORE;
    887    //                                  if (thisRCorner > thatRCorner) return AFTER;
    888    //                          }
    889    //                          if (thisRCorner == -1 || thatRCorner == -1) {
    890    //                                  if (thisLCorner < thatLCorner) return BEFORE;
    891    //                                  if (thisLCorner > thatLCorner) return AFTER;
    892    //                          }
    893
    894                                if (thisLCorner != -1 && thatLCorner != -1 && thisRCorner != -1 && thatRCorner != -1) {
    895                                        if (thisLCorner < thatLCorner && thisRCorner < thatRCorner) return BEFORE;
    896                                        if (thisLCorner > thatLCorner && thisRCorner > thatRCorner) return AFTER;
    897                                        if (thisLCorner > thatLCorner && thisRCorner < thatRCorner) return BEFORE;
    898                                        if (thisLCorner < thatLCorner && thisRCorner > thatRCorner) return AFTER;
    899                                } else {
    900                                        if (thisLCorner != -1 && thatLCorner != -1) {
    901                                                if (thisLCorner < thatLCorner) return BEFORE;
    902                                                if (thisLCorner > thatLCorner) return AFTER;
    903                                        }
    904                                        if (thisRCorner != -1 && thatRCorner != -1) {
    905                                                if (thisRCorner < thatRCorner) return BEFORE;
    906                                                if (thisRCorner > thatRCorner) return AFTER;
    907                                        }
    908                                }
    909
    910
    911
    912    //                          final int thisLCorner = this.index;
    913    //                          final int thatLCorner = that.getLeftmostDescendantIndex();
    914    //                          final int thisRCorner = this.index;
    915    //                          final int thatRCorner = that.getRightmostDescendantIndex();
    916    //
    917    //                          if (thisLCorner == -1 || thatLCorner == -1) {
    918    //                                  if (thisRCorner < thatRCorner) return BEFORE;
    919    //                                  if (thisRCorner > thatRCorner) return AFTER;
    920    //                          }
    921    //                          if (thisRCorner == -1 || thatRCorner == -1) {
    922    //                                  if (thisLCorner < thatLCorner) return BEFORE;
    923    //                                  if (thisLCorner > thatLCorner) return AFTER;
    924    //                          }
    925    //                          if (thisLCorner < thatLCorner && thisRCorner < thatRCorner) return BEFORE;
    926    //                          if (thisLCorner > thatLCorner && thisRCorner > thatRCorner) return AFTER;
    927    //                          if (thisLCorner > thatLCorner && thisRCorner < thatRCorner) return BEFORE;
    928    //                          if (thisLCorner < thatLCorner && thisRCorner > thatRCorner) return AFTER;
    929
    930
    931
    932    //                      int corner = that.getLeftmostDescendantIndex();
    933    //                      if (corner != -1) {
    934    //                              if (this.index < corner) return BEFORE;
    935    //                              if (this.index > corner) return AFTER;
    936    //                      }
    937    //                      corner = that.getRightmostDescendantIndex();
    938    //                      if (corner != -1) {
    939    //                              if (this.index < corner) return BEFORE;
    940    //                              if (this.index > corner) return AFTER;
    941    //                      }
    942                    } catch (MaltChainedException e) {
    943                                    if (SystemLogger.logger().isDebugEnabled()) {
    944                                            SystemLogger.logger().debug("",e);
    945                                    } else {
    946                                            SystemLogger.logger().error(e.getMessageChain());
    947                                    }
    948                                    System.exit(1);
    949                    }
    950                }
    951                if (this.index < that.getCompareToIndex()) return BEFORE;
    952                if (this.index > that.getCompareToIndex()) return AFTER;
    953                    return super.compareTo(that);
    954            }
    955
    956            public boolean equals(Object obj) {
    957                    Token v = (Token)obj;
    958                    if (!(this.predecessor == v.predecessor && this.successor == v.successor)) return false;
    959                    return super.equals(obj);
    960            }
    961
    962            public int hashCode() {
    963                    int hash = 7;
    964                    hash = 31 * hash + (null == predecessor ? 0 : predecessor.hashCode());
    965                    hash = 31 * hash + (null == successor ? 0 : successor.hashCode());
    966                    return 31 * hash + super.hashCode();
    967            }
    968
    969
    970            public String toString() {
    971                    final StringBuilder sb = new StringBuilder();
    972                    sb.append(super.toString());
    973                    return sb.toString();
    974            }
    975    }