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