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