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