001/*
002// $Id: Node.java 3 2009-05-11 08:11:57Z jhyde $
003// Clapham generates railroad diagrams to represent computer language grammars.
004// Copyright (C) 2008-2009 Julian Hyde
005// Copyright (c) 2005 Stefan Schoergenhumer, Markus Dopler
006//
007// This program is free software; you can redistribute it and/or modify it
008// under the terms of the GNU General Public License as published by the Free
009// Software Foundation; either version 2 of the License, or (at your option)
010// any later version approved by The Eigenbase Project.
011//
012// This program is distributed in the hope that it will be useful,
013// but WITHOUT ANY WARRANTY; without even the implied warranty of
014// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015// GNU General Public License for more details.
016//
017// You should have received a copy of the GNU General Public License
018// along with this program; if not, write to the Free Software
019// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
020*/
021package net.hydromatic.clapham.graph;
022
023import java.awt.*;
024import java.awt.geom.Point2D.Float;
025import java.util.List;
026import java.util.ArrayList;
027
028/**
029 * TODO:
030 *
031 * @author jhyde
032 * @version $Id: Node.java 3 2009-05-11 08:11:57Z jhyde $
033 * @since Jul 30, 2008
034 */
035public class Node {
036
037    public final int      n;                    // node number
038        public NodeType typ;            // t, nt, eps, alt, iter, opt, rerun
039        public Node     next;           // to successor node
040        public Node     down;           // alt: to next alternative
041        public Node     sub;            // alt, iter, opt: to first node of substructure
042        public boolean  up;                     // true: "next" leads to successor in enclosing structure
043        public Symbol   sym;            // nt, t: symbol represented by this node
044        public Node             itergraph;      // rerun: points to the b in "a {b a}", null if "a {a}"
045        private boolean  firstLevel; // true if the Node is in the first Level
046    private TextBox textBox;
047
048    public Node(Grammar grammar, Symbol sym) {
049                this.typ = sym.typ;
050        this.sym = sym;
051                n = grammar.nodes.size();
052                grammar.nodes.add(this);
053        }
054
055        public Node(Grammar grammar, NodeType typ, Node sub) {
056                this.typ = typ;
057                n = grammar.nodes.size();
058                grammar.nodes.add(this);
059                this.sub = sub;
060        }
061
062    //----------------- for printing ----------------------
063
064    //----------------- for drawing ----------------------
065
066    /*****************other variables needed for the drawing********/
067    Size        size            = new Size(0,0);                        // the required size to draw the node
068        private Size    altSize         = new Size(0,0);                        // the required size to draw a construct of alts or the size of the firstcomponent in the special rerun-node (itergraph!=null)
069        private Size    iterSize        = new Size(0,0);                        // the size of the second component in the special rerun Node (itergraph!=null)
070        final Float posBegin    = new Float(0,0);                       // the point in the left above corner of the component
071        public final Float posLine      = new Float(0,0);                       // the point of the line of the component
072        final Float posEnd              = new Float(0,0);                       // the point in the left down corner of the component
073
074    public void unparse(StringBuffer buf) {
075        switch (typ) {
076        case TERM:
077            buf.append('\'').append(sym.name).append('\'');
078            break;
079        case NONTERM:
080            buf.append('<').append(sym.name).append('>');
081            break;
082        case ALT:
083            final List<Node> alts = new ArrayList<Node>();
084            for (Node n = this; n != null; n = n.down) {
085                alts.add(n.sub);
086            }
087            int count = 0;
088            buf.append("(");
089            for (Node alt : alts) {
090                if (count++ > 0) {
091                    buf.append(" | ");
092                }
093                unparseList(buf, nextChildren(alt), "", " ", "");
094            }
095            buf.append(")");
096            break;
097        case ITER:
098            unparseList(buf, nextChildren(sub), "iter(", " ", ")");
099            break;
100        default:
101            buf.append("unknown <").append(typ).append(">");
102        }
103    }
104
105    private static List<Node> nextChildren(Node next) {
106        final List<Node> list = new ArrayList<Node>();
107        for (Node n = next; n != null; n = n.up ? null : n.next) {
108            list.add(n);
109        }
110        return list;
111    }
112
113    private void unparseList(
114        StringBuffer buf,
115        List<Node> list,
116        String before,
117        String mid, 
118        String after)
119    {
120        int count = 0;
121        buf.append(before);
122        for (Node n : list) {
123            if (count++ > 0) {
124                buf.append(mid);
125            }
126            n.unparse(buf);
127        }
128        buf.append(after);
129    }
130
131    // calculates the size if there are wraps in the rule
132        public void setWrapSize(Chart chart) {
133        Node n = this;
134        float maxH = 0;
135        while (n != null) {
136            n.firstLevel = true;
137            switch (n.typ) {
138            case WRAP:
139                n.size.setHeight(maxH);
140                maxH = 0;
141                break;
142            case ITER:
143                if (maxH
144                    < n.size.getHeight()
145                    + (chart.getFontHeight() + chart.componentGapHeight)
146                    / 2) {
147                    maxH =
148                        n.size.getHeight()
149                            + (chart.getFontHeight()
150                            + chart.componentGapHeight) / 2;
151                }
152                break;
153            default:
154                if (maxH < n.size.getHeight()
155                    || maxH < n.altSize.getHeight()) {
156                    if (n.altSize.getHeight() != 0) {
157                        maxH = n.altSize.getHeight();
158                    } else {
159                        maxH = n.size.getHeight();
160                    }
161                }
162                break;
163            }
164            n = n.next;
165        }
166    }
167
168    /**
169     * Calculates the size of each symbol.
170     */
171    public Size calcSize(Chart chart) {
172        Node n = this;                             //current node in the level
173        Size s = new Size(); // alt,iter,opt: size of current construct
174        int iterCompensation = 0;
175        boolean samelevel = true;                    //next node in same level?
176        int realHeight = n.calcHeight(chart);
177        Size maxTotalSize = new Size(0, 0);
178        while (n != null && samelevel) {
179            switch (n.typ) {
180            case TERM:
181            case NONTERM:
182                n.textBox =
183                    new TextBox(
184                        chart, n.sym.name, chart.charFont, chart.charColor);
185                n.size.setHeight(
186                    n.textBox.height
187                        + chart.symbolGapHeight * 2
188                        + chart.componentGapHeight);
189                n.size.setWidth(
190                    n.textBox.width
191                        + chart.symbolGapWidth * 2);
192                if (n.typ == NodeType.TERM) {
193                    n.size.maxWidth(
194                        chart.componentArcSize);
195                }
196                if (!n.up
197                    && n.next != null
198                    && n.next.typ == NodeType.WRAP
199                    && n.next.size.getHeight() == 0) {
200                    if (!n.next.up
201                        && n.next.next != null
202                        && (n.next.next.typ == NodeType.TERM
203                        || n.next.next.typ == NodeType.NONTERM)) {
204                        s.incWidth(chart.componentGapWidth / 2);
205                    }
206                }
207                if (!n.up && n.next != null
208                    && (n.next.typ == NodeType.TERM
209                    || n.next.typ == NodeType.NONTERM)) {
210                    s.incWidth(chart.componentGapWidth / 2);
211                }
212                break;
213            case EPS:
214                n.size.setHeight(
215                    chart.getFontHeight() + chart.componentGapHeight);
216                n.size.setWidth(chart.componentGapWidth);
217                break;
218            case OPT:
219                n.size = n.sub.calcSize(chart);
220                n.size.incWidth(chart.componentGapWidth * 2);
221                n.size.incHeight(chart.componentGapHeight / 2);
222                break;
223            case ITER:
224                n.size = n.sub.calcSize(chart);
225                n.size.incWidth(chart.componentGapWidth * 2);
226                break;
227            case WRAP:
228                maxTotalSize.incHeight(
229                    s.getHeight()
230                        - chart.componentGapHeight / 2);
231                maxTotalSize.maxWidth(s.getWidth());
232                s.setHeight(0);
233                s.setWidth(0);
234                break;
235            case RERUN:
236                n.size = n.sub.calcSize(chart);
237                if (n.itergraph != null) {
238                    n.altSize = n.size;
239                    n.size.maxWidth(n.itergraph.calcSize(chart).getWidth());
240                    n.size.incHeight(n.itergraph.calcSize(chart).getHeight());
241                    n.iterSize = n.itergraph.calcSize(chart);
242                } else {
243                    n.size.incHeight(chart.componentGapHeight / 2);
244                }
245                n.size.incWidth(chart.componentGapWidth * 2);
246                break;
247            case ALT: {
248                Node a = n;
249                int maxH = -chart.componentGapHeight;
250                float maxW = 0;
251                while (a != null) {
252                    a.size = a.sub.calcSize(chart);
253                    maxH += a.size.getHeight();
254                    if (a.size.getWidth() > maxW) {
255                        maxW = a.size.getWidth();
256                    }
257                    a = a.down;
258                }
259                if (n.sub.typ == NodeType.ITER && realHeight != 0) {
260                    maxH +=
261                        (chart.getFontHeight() + chart.componentGapHeight) / 2;
262                }
263                maxW += 2 * chart.componentGapWidth;
264                maxH += chart.componentGapHeight;
265
266                n.altSize.setHeight(maxH);
267                n.altSize.setWidth(maxW);
268            }
269            break;
270            }
271            if (n.typ == NodeType.ITER && realHeight != 0) {
272                iterCompensation =
273                    (chart.getFontHeight() + chart.componentGapHeight) / 2;
274            }
275            if (n.typ == NodeType.ALT) {
276                s.maxHeight(n.altSize.getHeight());
277                s.incWidth(n.altSize.getWidth());
278            } else {
279                s.maxHeight(n.size.getHeight());
280                s.incWidth(n.size.getWidth());
281            }
282            if (n.typ == NodeType.ITER) {
283                s.maxHeight(n.size.getHeight() + iterCompensation);
284            }
285            if (n.up) {
286                samelevel = false;
287            }
288            n = n.next;
289        }
290        if (maxTotalSize.getWidth() != 0) {
291            maxTotalSize.incHeight(
292                s.getHeight()
293                    - chart.componentGapHeight / 2);
294            maxTotalSize.maxWidth(s.getWidth());
295            return maxTotalSize;
296        } else {
297            return s;
298        }
299    }
300
301    /**
302     * Calculates the total height of all symbols wich are in the same
303     * horizontal level.
304     */
305    int calcHeight(Chart chart) {
306        Node n = this;                             //current node in the level
307        float realHeight = 0;
308        boolean samelevel = true;                    //next node in same level?
309        while (n != null && samelevel) {
310            if (n.typ == NodeType.NONTERM || n.typ == NodeType.TERM) {
311                if (realHeight < n.size.getHeight()) {
312                    realHeight = n.size.getHeight();
313                }
314            } else if (n.typ == NodeType.ITER) {
315                int tmpHeight = 0;
316                if (realHeight < tmpHeight) {
317                    realHeight = tmpHeight;
318                }
319            } else if (n.typ == NodeType.OPT
320                || n.typ == NodeType.RERUN) {
321                int tmpHeight = n.sub.calcHeight(chart);
322                if (realHeight < tmpHeight) {
323                    // REVIEW:
324                }
325                realHeight = tmpHeight;
326            } else if (n.typ == NodeType.ALT) {
327                int tmpHeight = n.sub.calcHeight(chart);
328                if (realHeight < tmpHeight) {
329                    // REVIEW:
330                }
331                realHeight = tmpHeight;
332            } else if (n.typ == NodeType.EPS) {
333                if (realHeight < chart.getFontHeight() * 3 / 2) {
334                    realHeight =
335                        chart.getFontHeight() + chart.componentGapHeight;
336                }
337            }
338            if (n.up) {
339                samelevel = false;
340            }
341            n = n.next;
342        }
343        return (int) realHeight;
344    }
345
346    /**
347     * Calculates the horizontal position of the symbols.
348     */
349    public void calcPos(Chart chart, float posBegin) {
350        Node n = this;                             //current node in the level
351        int realHeight = calcHeight(chart);
352        boolean samelevel = true;                    //next node in same level?
353        while (n != null && samelevel) {
354            if (n.typ == NodeType.NONTERM || n.typ == NodeType.TERM) {
355                n.posLine.y = posBegin + realHeight / 2;
356                n.posBegin.y =
357                    n.posLine.y
358                        - (n.size.getHeight() - chart.componentGapHeight) / 2;
359                n.posEnd.y =
360                    n.posLine.y
361                        + (n.size.getHeight() - chart.componentGapHeight) / 2;
362            } else if (n.typ == NodeType.EPS) {
363                n.posLine.y = posBegin + n.size.getHeight() / 2;
364                n.posBegin.y = posBegin;
365                n.posEnd.y = posBegin + n.size.getHeight();
366            } else if (n.typ == NodeType.OPT) {
367                n.posLine.y = posBegin + realHeight / 2;
368                n.posBegin.y = posBegin;
369                n.posEnd.y = posBegin + n.size.getHeight();
370                n.sub.calcPos(chart, n.posBegin.y);
371            } else if (n.typ == NodeType.RERUN) {
372                n.posLine.y = posBegin + realHeight / 2;
373                n.posBegin.y = posBegin;
374                n.posEnd.y = posBegin + n.size.getHeight();
375                if (n.itergraph != null) {
376                    n.itergraph.calcPos(
377                        chart,
378                        posBegin + n.altSize.getHeight());
379                }
380                n.sub.calcPos(chart, n.posBegin.y);
381            } else if (n.typ == NodeType.ITER) {
382                if (realHeight == 0) {
383                    n.posLine.y = posBegin + realHeight / 2;
384                    n.posBegin.y = posBegin;
385                    n.posEnd.y = posBegin + n.size.getHeight();
386                } else {
387                    n.posLine.y = posBegin + realHeight / 2;
388                    n.posBegin.y =
389                        posBegin
390                            + (chart.getFontHeight() + chart.componentGapHeight)
391                            / 2;
392                    n.posEnd.y = n.posBegin.y + n.size.getHeight();
393                }
394                n.sub.calcPos(chart, n.posLine.y);
395            } else if (n.typ == NodeType.WRAP && firstLevel) {
396                n.posLine.y = posBegin + realHeight / 2;
397                n.posEnd.y = posBegin + n.size.getHeight();
398                posBegin = posBegin + n.size.getHeight();
399            } else if (n.typ == NodeType.ALT) {
400                n.posLine.y = posBegin + realHeight / 2;
401                n.posBegin.y = posBegin;
402                n.posEnd.y = posBegin + n.altSize.getHeight();
403                if (n.sub.typ == NodeType.ITER
404                    && n.calcHeight(chart) != 0
405                    && n.altSize.getHeight() != 0) {
406                    posBegin +=
407                        (chart.getFontHeight() + chart.componentGapHeight) / 2;
408                }
409                n.sub.calcPos(chart, posBegin);
410                if (n.down != null) {
411                    n.down.calcPos(chart, posBegin + n.size.getHeight());
412                }
413                if (n.sub.typ == NodeType.ITER
414                    && n.calcHeight(chart) != 0
415                    && n.altSize.getHeight() != 0) {
416                    posBegin -=
417                        (chart.getFontHeight() + chart.componentGapHeight) / 2;
418                }
419            }
420            if (n.up) {
421                samelevel = false;
422            }
423            n = n.next;
424        }
425    }
426
427        /**
428         * Draws the components from left to right.
429     *
430     * <p>Each component paints itself and then give its coordinates to its
431     * sub-components for a recursive call, or if applicable, a call to
432     * the {@link #drawComponentsInverse} method.
433        */
434    public void drawComponents(Chart chart, Float p, Size s) {
435        Node n = this;                             // current node in the level
436        boolean samelevel = true; // next node in same level?
437
438        while (n != null && samelevel) {
439            switch (n.typ) {
440            case TERM:
441            case NONTERM:
442                if (chart.showBorders) {
443                    chart.drawRectangle(
444                        Chart.RERUN_COLOR,
445                        Chart.STROKE1,
446                        p.x,
447                        n.posBegin.y - chart.componentGapHeight / 2,
448                        n.size.getWidth(),
449                        n.size.getHeight());
450                }
451                if (n.typ == NodeType.TERM) {
452                    // the quarter Arcs
453                    final float foo =
454                        (n.size.getHeight() - chart.componentGapHeight) / 2;
455                    chart.drawArcCorner(
456                        p.x,
457                        n.posBegin.y,
458                        foo,
459                        180);
460                    chart.drawArcCorner(
461                        p.x,
462                        n.posLine.y,
463                        foo,
464                        90);
465                    chart.drawArcCorner(
466                        p.x + n.size.getWidth() - foo,
467                        n.posBegin.y,
468                        foo,
469                        270);
470                    chart.drawArcCorner(
471                        p.x + n.size.getWidth() - foo,
472                        n.posLine.y,
473                        foo,
474                        0);
475
476                    n.textBox.drawAtCenter(
477                        p.x,
478                        n.posBegin.y,
479                        n.size.getWidth() - foo,
480                        n.posLine.y - n.posBegin.y);
481
482                    // the short vertical and horizontal lines between the quarter Arcs
483                    final float quarterHeight =
484                        (n.size.getHeight() - chart.componentGapHeight)
485                            / 4;
486                    chart.drawLine(
487                        p.x + quarterHeight - 1,
488                        n.posBegin.y,
489                        p.x + n.size.getWidth() - quarterHeight + 1,
490                        n.posBegin.y);
491                    chart.drawLine(
492                        p.x + quarterHeight - 1,
493                        n.posEnd.y,
494                        p.x + n.size.getWidth() - quarterHeight + 1,
495                        n.posEnd.y);
496                    chart.drawLine(
497                        p.x,
498                        n.posLine.y + quarterHeight + 1,
499                        p.x,
500                        n.posLine.y - quarterHeight - 1);
501                    chart.drawLine(
502                        p.x + n.size.getWidth(),
503                        n.posLine.y + quarterHeight + 1,
504                        p.x + n.size.getWidth(),
505                        n.posLine.y - quarterHeight - 1);
506                } else {
507                    n.posBegin.x = p.x;
508                    n.posEnd.x = p.x + n.size.getWidth();
509                    chart.drawRectangle(
510                        chart.lineColor,
511                        chart.lineStroke,
512                        n.posBegin.x,
513                        n.posBegin.y,
514                        n.size.getWidth(),
515                        n.size.getHeight() - chart.componentGapHeight);
516
517                    n.textBox.drawAtCenter(
518                        n.posBegin.x,
519                        n.posBegin.y,
520                        n.size.getWidth(),
521                        n.size.getHeight() - chart.componentGapHeight);
522                }
523                if (Grammar.TRACE) {
524                    System.out.println("text=" + n.sym.name);
525                    System.out.println("n.posBegin.y=" + n.posBegin.y);
526                    System.out.println(
527                        "chart.getFontHeight()=" + chart.getFontHeight());
528                    System.out.println("n.size=" + n.size.getHeight());
529                    System.out.println(
530                        "2=" + +(n.size.getHeight()
531                                 - chart.componentGapHeight));
532                    System.out.println(
533                        "3="
534                        + (n.size.getHeight() - chart.componentGapHeight - chart
535                            .getFontHeight()) / 2);
536                }
537                if (false)
538                chart.drawString(
539                    n.sym.name,
540                    chart.charFont,
541                    chart.charColor,
542                    p.x
543                        + chart.symbolGapWidth,
544                    n.posBegin.y
545                        + (n.size.getHeight() - chart.componentGapHeight)
546                        - chart.symbolGapHeight);
547                chart.drawArrow(
548                    p.x,
549                    n.posLine.y,
550                    p.x,
551                    n.posLine.y,
552                    Grammar.Direction.RIGHT);
553                p.x += n.size.getWidth();
554                // draw lines between t and nt nodes
555                if (!n.up && n.next != null
556                    && (n.next.typ == NodeType.TERM
557                    || n.next.typ == NodeType.NONTERM)) {
558                    chart.drawArrow(
559                        p.x,
560                        n.posLine.y,
561                        p.x
562                            + chart.componentGapWidth / 2,
563                        n.posLine.y,
564                        Grammar.Direction.RIGHT);
565                    p.x += chart.componentGapWidth / 2;
566                }
567                if (!n.up
568                    && n.next != null
569                    && n.next.typ == NodeType.WRAP
570                    && n.next.size.getHeight() == 0) {
571                    chart.drawArrow(
572                        p.x,
573                        n.posLine.y,
574                        p.x
575                            + chart.componentGapWidth / 2,
576                        n.posLine.y,
577                        Grammar.Direction.RIGHT);
578                    p.x += chart.componentGapWidth / 2;
579                }
580                break;
581            case EPS:
582                if (chart.showBorders) {
583                    chart.drawRectangle(
584                        Chart.EPS_COLOR,
585                        chart.lineStroke,
586                        p.x,
587                        n.posBegin.y,
588                        n.size.getWidth(),
589                        n.size.getHeight());
590                }
591
592                chart.drawLine(
593                    p.x,
594                    n.posLine.y,
595                    p.x + n.size.getWidth(),
596                    n.posLine.y);
597                break;
598            case OPT:
599                if (chart.showBorders) {
600                    chart.drawRectangle(
601                        Chart.EPS_COLOR,
602                        Chart.STROKE1,
603                        p.x,
604                        n.posBegin.y,
605                        n.size.getWidth(),
606                        n.size.getHeight());
607                }
608
609                // the two short lines at the beginning and the end
610                chart.drawLine(
611                    p.x,
612                    n.posLine.y,
613                    p.x + chart.componentGapWidth,
614                    n.posLine.y);
615                chart.drawLine(
616                    p.x + n.size.getWidth(),
617                    n.posLine.y,
618                    p.x
619                        + n.size.getWidth()
620                        - chart.componentGapWidth,
621                    n.posLine.y);
622                // the quarter Arcs
623                chart.drawArcCorner(
624                    p.x
625                        + chart.componentGapWidth / 4
626                        - chart.componentArcSize / 2,
627                    n.posLine.y,
628                    270);
629                chart.drawArcCorner(
630                    p.x + chart.componentGapWidth / 4
631                        + chart.componentArcSize / 2,
632                    n.posEnd.y
633                        - chart.componentArcSize
634                        - chart.componentGapHeight / 2,
635                    90);
636                chart.drawArcCorner(
637                    p.x
638                        - chart.componentGapWidth / 4
639                        - chart.componentArcSize / 2
640                        + n.size.getWidth(),
641                    n.posLine.y,
642                    180);
643                chart.drawArcCorner(
644                    p.x
645                        - chart.componentGapWidth / 4
646                        - chart.componentArcSize * 3 / 2
647                        + n.size.getWidth(),
648                    n.posEnd.y
649                        - chart.componentArcSize
650                        - chart.componentGapHeight / 2,
651                    0);
652                // the short vertical lines between the quarter Arcs
653                chart.drawLine(
654                    p.x
655                        + chart.componentGapWidth / 4
656                        + chart.componentArcSize / 2,
657                    n.posLine.y
658                        + chart.componentArcSize / 2,
659                    p.x
660                        + chart.componentGapWidth / 4
661                        + chart.componentArcSize / 2,
662                    n.posEnd.y
663                        - chart.componentArcSize / 2
664                        - chart.componentGapHeight / 2 + 1);
665                chart.drawLine(
666                    p.x - chart.componentGapWidth / 4
667                        - chart.componentArcSize / 2
668                        + n.size.getWidth(),
669                    n.posLine.y
670                        + chart.componentArcSize / 2,
671                    p.x
672                        - chart.componentGapWidth / 4
673                        - chart.componentArcSize / 2
674                        + n.size.getWidth(),
675                    n.posEnd.y
676                        - chart.componentArcSize / 2
677                        - chart.componentGapHeight / 2 + 1);
678                // the the long horizontal line between the quarter Arcs
679                chart.drawLine(
680                    p.x + chart.componentGapWidth / 4
681                        + chart.componentArcSize,
682                    n.posEnd.y
683                        - chart.componentGapHeight / 2,
684                    p.x
685                        - chart.componentGapWidth / 4
686                        - chart.componentArcSize
687                        + n.size.getWidth() + 1,
688                    n.posEnd.y
689                        - chart.componentGapHeight / 2);
690
691                n.sub.drawComponents(
692                    chart,
693                    new Float(
694                        p.x + chart.componentGapWidth,
695                        0),
696                    n.size);
697                p.x += n.size.getWidth();
698                break;
699            case RERUN:
700                if (n.itergraph == null) {
701                    if (chart.showBorders) {
702                        chart.drawRectangle(
703                            Chart.RERUN_COLOR,
704                            Chart.STROKE1,
705                            p.x,
706                            n.posBegin.y,
707                            n.size.getWidth(),
708                            n.size.getHeight());
709                    }
710
711                    // the two short lines at the beginning and the end
712                    chart.drawLine(
713                        p.x,
714                        n.posLine.y,
715                        p.x + chart.componentGapWidth,
716                        n.posLine.y);
717                    chart.drawLine(
718                        p.x + n.size.getWidth(),
719                        n.posLine.y,
720                        p.x
721                            + n.size.getWidth()
722                            - chart.componentGapWidth,
723                        n.posLine.y);
724                    // the quarter Arcs
725                    chart.drawArcCorner(
726                        p.x
727                            + chart.componentGapWidth / 4
728                            + chart.componentArcSize / 2,
729                        n.posEnd.y
730                            - chart.componentGapHeight / 2
731                            - chart.componentArcSize,
732                        90);
733                    chart.drawArcCorner(
734                        p.x
735                            + chart.componentGapWidth / 4
736                            + chart.componentArcSize / 2,
737                        n.posLine.y,
738                        180);
739                    chart.drawArcCorner(
740                        p.x
741                            - chart.componentGapWidth / 4
742                            - chart.componentArcSize * 3 / 2
743                            + n.size.getWidth(),
744                        n.posEnd.y
745                            - chart.componentGapHeight / 2
746                            - chart.componentArcSize,
747                        0);
748                    chart.drawArcCorner(
749                        p.x
750                            - chart.componentGapWidth / 4
751                            - chart.componentArcSize * 3 / 2
752                            + n.size.getWidth(),
753                        n.posLine.y,
754                        270);
755                    // the short vertical lines between the quarter Arcs
756                    chart.drawLine(
757                        p.x
758                            + chart.componentGapWidth / 4
759                            + chart.componentArcSize / 2,
760                        n.posLine.y
761                            + chart.componentArcSize / 2,
762                        p.x
763                            + chart.componentGapWidth / 4
764                            + chart.componentArcSize / 2,
765                        n.posEnd.y
766                            - chart.componentGapHeight / 2
767                            - chart.componentArcSize / 2 + 1);
768                    chart.drawLine(
769                        p.x
770                            - chart.componentGapWidth / 4
771                            - chart.componentArcSize / 2
772                            + n.size.getWidth(),
773                        n.posLine.y
774                            + chart.componentArcSize / 2,
775                        p.x
776                            - chart.componentGapWidth / 4
777                            - chart.componentArcSize / 2
778                            + n.size.getWidth(),
779                        n.posEnd.y
780                            - chart.componentGapHeight / 2
781                            - chart.componentArcSize / 2 + 1);
782                    // the the long horizontal line between the quarter Arcs
783                    chart.drawLine(
784                        p.x
785                            + chart.componentGapWidth / 4
786                            + chart.componentArcSize - 1,
787                        n.posEnd.y
788                            - chart.componentGapHeight / 2,
789                        p.x
790                            - chart.componentGapWidth / 4
791                            - chart.componentArcSize
792                            + n.size.getWidth() + 1,
793                        n.posEnd.y
794                            - chart.componentGapHeight / 2);
795
796                    n.sub.drawComponents(
797                        chart,
798                        new Float(
799                            p.x + chart.componentGapWidth,
800                            0),
801                        n.size);
802                    p.x += n.size.getWidth();
803                } else {
804                    if (chart.showBorders) {
805                        chart.drawRectangle(
806                            Chart.RERUN1_COLOR,
807                            Chart.STROKE1,
808                            p.x,
809                            n.posBegin.y,
810                            n.size.getWidth(),
811                            n.size.getHeight());
812                    }
813
814                    // the two short lines at the beginning and the end of the first component
815                    chart.drawLine(
816                        p.x,
817                        n.posLine.y,
818                        p.x
819                            + n.size.getWidth() / 2
820                            - n.altSize.getWidth() / 2
821                            - 1,
822                        n.posLine.y);
823                    chart.drawLine(
824                        p.x
825                            + n.size.getWidth() / 2
826                            + n.altSize.getWidth() / 2
827                            + 1,
828                        n.posLine.y,
829                        p.x
830                            + n.size.getWidth(),
831                        n.posLine.y);
832                    // the quarter Arcs
833                    chart.drawArcCorner(
834                        p.x
835                            + chart.componentGapWidth / 4
836                            + chart.componentArcSize / 2,
837                        n.itergraph.posLine.y
838                            - chart.componentArcSize,
839                        90);
840                    chart.drawArcCorner(
841                        p.x
842                            + chart.componentGapWidth / 4
843                            + chart.componentArcSize / 2,
844                        n.posLine.y,
845                        180);
846                    chart.drawArcCorner(
847                        p.x
848                            - chart.componentGapWidth / 4
849                            - chart.componentArcSize * 3 / 2
850                            + n.size.getWidth(),
851                        n.itergraph.posLine.y
852                            - chart.componentArcSize,
853                        0);
854                    chart.drawArcCorner(
855                        p.x
856                            - chart.componentGapWidth / 4
857                            - chart.componentArcSize * 3 / 2
858                            + n.size.getWidth(),
859                        n.posLine.y,
860                        270);
861                    // the short vertical lines between the quarter Arcs
862                    chart.drawLine(
863                        p.x
864                            + chart.componentGapWidth / 4
865                            + chart.componentArcSize / 2,
866                        n.posLine.y
867                            + chart.componentArcSize / 2,
868                        p.x
869                            + chart.componentGapWidth / 4
870                            + chart.componentArcSize / 2,
871                        n.itergraph.posLine.y
872                            - chart.componentArcSize / 2 + 1);
873                    chart.drawLine(
874                        p.x
875                            - chart.componentGapWidth / 4
876                            - chart.componentArcSize / 2
877                            + n.size.getWidth(),
878                        n.posLine.y
879                            + chart.componentArcSize / 2,
880                        p.x
881                            - chart.componentGapWidth / 4
882                            - chart.componentArcSize / 2
883                            + n.size.getWidth(),
884                        n.itergraph.posLine.y
885                            - chart.componentArcSize / 2 + 1);
886                    // the two short lines at the beginning and the end of the second component
887                    chart.drawLine(
888                        p.x
889                            + chart.componentGapWidth / 4
890                            + chart.componentArcSize,
891                        n.itergraph.posLine.y,
892                        p.x
893                            + n.size.getWidth() / 2
894                            - n.iterSize.getWidth() / 2
895                            - 1,
896                        n.itergraph.posLine.y);
897                    chart.drawLine(
898                        p.x
899                            + n.size.getWidth() / 2
900                            + n.iterSize.getWidth() / 2
901                            + 1,
902                        n.itergraph.posLine.y,
903                        p.x
904                            - chart.componentGapWidth / 4
905                            - chart.componentArcSize
906                            + n.size.getWidth()
907                            + 1,
908                        n.itergraph.posLine.y);
909
910                    n.itergraph.drawComponentsInverse(
911                        chart,
912                        new Float(
913                            p.x
914                                + n.size.getWidth() / 2
915                                + n.iterSize.getWidth() / 2,
916                            n.posEnd.y),
917                        n.size);
918                    n.sub.drawComponents(
919                        chart,
920                        new Float(
921                            p.x
922                                + n.size.getWidth() / 2
923                                - n.altSize.getWidth() / 2,
924                            n.posEnd.y), n.size);
925                    p.x += n.size.getWidth();
926                }
927                break;
928            case ITER:
929                if (chart.showBorders) {
930                    chart.drawRectangle(
931                        Chart.ITER_COLOR,
932                        Chart.STROKE1,
933                        p.x,
934                        n.posBegin.y,
935                        n.size.getWidth(),
936                        n.size.getHeight());
937                }
938
939                // the quarter Arcs
940                chart.drawArcCorner(
941                    p.x
942                        + chart.componentGapWidth / 4
943                        + chart.componentArcSize / 2,
944                    n.sub.posLine.y
945                        - chart.componentArcSize,
946                    90);
947                chart.drawArcCorner(
948                    p.x
949                        + chart.componentGapWidth / 4
950                        + chart.componentArcSize / 2,
951                    n.posLine.y,
952                    180);
953                chart.drawArcCorner(
954                    p.x
955                        - chart.componentGapWidth / 4
956                        - chart.componentArcSize * 3 / 2
957                        + n.size.getWidth(),
958                    n.sub.posLine.y
959                        - chart.componentArcSize,
960                    0);
961                chart.drawArcCorner(
962                    p.x
963                        - chart.componentGapWidth / 4
964                        - chart.componentArcSize * 3 / 2
965                        + n.size.getWidth(),
966                    n.posLine.y,
967                    270);
968                // the short vertical lines between the quarter Arcs
969                chart.drawLine(
970                    p.x
971                        + chart.componentGapWidth / 4
972                        + chart.componentArcSize / 2,
973                    n.posLine.y
974                        + chart.componentArcSize / 2,
975                    p.x
976                        + chart.componentGapWidth / 4
977                        + chart.componentArcSize / 2,
978                    n.sub.posLine.y
979                        - chart.componentArcSize / 2 + 1);
980                chart.drawLine(
981                    p.x
982                        - chart.componentGapWidth / 4
983                        - chart.componentArcSize / 2
984                        + n.size.getWidth(),
985                    n.posLine.y
986                        + chart.componentArcSize / 2,
987                    p.x
988                        - chart.componentGapWidth / 4
989                        - chart.componentArcSize / 2
990                        + n.size.getWidth(),
991                    n.sub.posLine.y
992                        - chart.componentArcSize / 2 + 1);
993                // the two short horizontal lines between the quater Arcs and the components
994                chart.drawLine(
995                    p.x
996                        + chart.componentGapWidth / 4
997                        + chart.componentArcSize - 1,
998                    n.sub.posLine.y,
999                    p.x
1000                        + chart.componentGapWidth,
1001                    n.sub.posLine.y);
1002                chart.drawLine(
1003                    p.x
1004                        - chart.componentGapWidth
1005                        + n.size.getWidth(),
1006                    n.sub.posLine.y,
1007                    p.x
1008                        + n.size.getWidth()
1009                        - chart.componentGapWidth / 4
1010                        - chart.componentArcSize + 1,
1011                    n.sub.posLine.y);
1012                // the long horizontal line in the middle
1013                chart.drawLine(
1014                    p.x,
1015                    n.posLine.y,
1016                    p.x + n.size.getWidth(),
1017                    n.posLine.y);
1018
1019                n.sub.drawComponentsInverse(
1020                    chart,
1021                    new Float(
1022                        p.x - chart.componentGapWidth + n.size.getWidth(),
1023                        0),
1024                    n.size);
1025                p.x += n.size.getWidth();
1026                break;
1027            case WRAP:
1028                if (n.size.getHeight() != 0
1029                    && n.next != null) {
1030
1031                    // the short horizontal line after the first component
1032                    chart.drawLine(
1033                        p.x, n.posLine.y, p.x
1034                        + chart.componentGapWidth / 4 + 1, n.posLine.y);
1035                    // the short horizontal line at the beginning of the second component
1036                    chart.drawLine(
1037                        chart.beginningXCoordinate,
1038                        n.next.posLine.y,
1039                        chart.beginningXCoordinate
1040                            - chart.componentGapWidth / 4,
1041                        n.next.posLine.y);
1042                    // the quarter Arcs
1043                    chart.drawArcCorner(
1044                        p.x + chart.componentGapWidth / 4 -
1045                            chart.componentArcSize / 2,
1046                        n.posLine.y,
1047                        270);
1048                    chart.drawArcCorner(
1049                        p.x + chart.componentGapWidth / 4
1050                            - chart.componentArcSize / 2,
1051                        n.posEnd.y
1052                            - chart.componentArcSize,
1053                        0);
1054                    chart.drawArcCorner(
1055                        (float) (chart.beginningXCoordinate
1056                            - chart.componentGapWidth / 4
1057                            - chart.componentArcSize / 2),
1058                        n.posEnd.y,
1059                        180);
1060                    chart.drawArcCorner(
1061                        (float) (chart.beginningXCoordinate
1062                            - chart.componentGapWidth / 4
1063                            - chart.componentArcSize / 2),
1064                        n.next.posLine.y
1065                            - chart.componentArcSize,
1066                        90);
1067                    // the short vertical lines between the quarter Arcs
1068                    chart.drawLine(
1069                        p.x
1070                            + chart.componentGapWidth / 4
1071                            + chart.componentArcSize / 2,
1072                        n.posLine.y
1073                            + chart.componentArcSize / 2,
1074                        p.x
1075                            + chart.componentGapWidth / 4
1076                            + chart.componentArcSize / 2,
1077                        n.posEnd.y
1078                            - chart.componentArcSize / 2 + 1);
1079                    chart.drawLine(
1080                        chart.beginningXCoordinate
1081                            - chart.componentGapWidth / 4
1082                            - chart.componentArcSize / 2,
1083                        n.posEnd.y + chart.componentArcSize / 2,
1084                        chart.beginningXCoordinate
1085                            - chart.componentGapWidth / 4
1086                            - chart.componentArcSize / 2,
1087                        n.next.posLine.y
1088                            - chart.componentArcSize / 2 + 1);
1089                    // the long horizontal line in the middle oft the two components
1090                    chart.drawLine(
1091                        p.x + chart.componentGapWidth / 4 + 1,
1092                        n.posEnd.y,
1093                        chart.beginningXCoordinate
1094                            - chart.componentGapWidth / 4,
1095                        n.posEnd.y);
1096
1097                    p.x = chart.beginningXCoordinate;
1098                }
1099                break;
1100            case ALT: {
1101                if (chart.showBorders) {
1102                    chart.drawRectangle(
1103                        Color.RED,
1104                        Chart.STROKE1,
1105                        p.x,
1106                        n.posBegin.y,
1107                        n.altSize.getWidth(),
1108                        n.altSize.getHeight());
1109                }
1110
1111                // the two short lines at the beginning and the end of the alt
1112                // component
1113                chart.drawLine(
1114                    p.x,
1115                    n.posLine.y,
1116                    p.x
1117                        + chart.componentArcSize * 3 / 2,
1118                    n.posLine.y);
1119                chart.drawLine(
1120                    p.x + n.altSize.getWidth(),
1121                    n.posLine.y,
1122                    p.x
1123                        + n.altSize.getWidth()
1124                        - chart.componentArcSize * 3 / 2,
1125                    n.posLine.y);
1126                Node a = n;
1127                boolean first = true;
1128                while (a != null) {
1129                    // the horizontal lines at the beginning and the end
1130                    chart.drawLine(
1131                        p.x
1132                            + chart.componentArcSize * 3 / 2,
1133                        a.sub.posLine.y,
1134                        p.x
1135                            + (n.altSize.getWidth() - a.size.getWidth()) / 2,
1136                        a.sub.posLine.y);
1137                    chart.drawLine(
1138                        p.x
1139                            - chart.componentArcSize * 3 / 2
1140                            + n.altSize.getWidth()
1141                            + 1,
1142                        a.sub.posLine.y,
1143                        p.x
1144                            + (n.altSize.getWidth() - a.size.getWidth()) / 2
1145                            + a.size.getWidth(),
1146                        a.sub.posLine.y);
1147                    // the first alternative draws different arcs
1148                    if (first) {
1149                        chart.drawArcCorner(
1150                            p.x,
1151                            n.posLine.y,
1152                            270);
1153                        chart.drawArcCorner(
1154                            p.x
1155                                + n.altSize.getWidth()
1156                                - chart.componentArcSize,
1157                            n.posLine.y,
1158                            180);
1159                        first = false;
1160                    } else {
1161                        // else draw other arcs and vertical lines
1162                        chart.drawArcCorner(
1163                            p.x + chart.componentArcSize,
1164                            a.sub.posLine.y
1165                                - chart.componentArcSize,
1166                            90);
1167                        chart.drawLine(
1168                            p.x + chart.componentArcSize,
1169                            n.posLine.y
1170                                + chart.componentArcSize / 2,
1171                            p.x
1172                                + chart.componentArcSize,
1173                            a.posLine.y
1174                                - chart.componentArcSize / 2 + 1);
1175                        chart.drawArcCorner(
1176                            p.x
1177                                - chart.componentArcSize * 2
1178                                + n.altSize.getWidth(),
1179                            a.sub.posLine.y
1180                                - chart.componentArcSize,
1181                            0);
1182                        chart.drawLine(
1183                            p.x
1184                                - chart.componentArcSize
1185                                + n.altSize.getWidth(),
1186                            n.posLine.y
1187                                + chart.componentArcSize / 2,
1188                            p.x
1189                                - chart.componentArcSize
1190                                + n.altSize.getWidth(),
1191                            a.posLine.y
1192                                - chart.componentArcSize / 2 + 1);
1193                    }
1194                    a.sub.drawComponents(
1195                        chart,
1196                        new Float(
1197                            p.x
1198                                + (n.altSize.getWidth() - a.size.getWidth())
1199                                / 2, a.posEnd.y), a.size);
1200                    a = a.down;
1201                }
1202                p.x += n.altSize.getWidth();
1203            }
1204            break;
1205            }
1206
1207            if (n.up) {
1208                samelevel = false;
1209            }
1210            if (n.next == null && firstLevel) {
1211                chart.drawLine(
1212                    p.x,
1213                    n.posLine.y,
1214                    p.x
1215                        + chart.componentGapWidth / 4,
1216                    n.posLine.y);
1217                chart.drawArrow(
1218                    p.x
1219                        + chart.componentGapWidth / 4
1220                        + chart.arrowSize,
1221                    n.posLine.y,
1222                    p.x
1223                        + chart.componentGapWidth / 4
1224                        + chart.arrowSize,
1225                    n.posLine.y,
1226                    Grammar.Direction.RIGHT);
1227            }
1228            n = n.next;
1229        }
1230    }
1231
1232    /*
1233      * Draw the components from right to left.
1234      * Needed if for example in an iter-node.
1235      */
1236    void drawComponentsInverse(
1237        Chart chart, Float p, Size s)
1238    {
1239        Node n = this;                             //current node in the level
1240        boolean samelevel = true;                    //next node in same level?
1241        Float p1 = new Float(0, 0);
1242
1243        while (n != null && samelevel) {
1244            p.x -= n.size.getWidth();
1245            if (n.typ == NodeType.TERM || n.typ == NodeType.NONTERM) {
1246                if (chart.showBorders) {
1247                    chart.drawRectangle(
1248                        Chart.N_NT_COLOR,
1249                        Chart.STROKE1,
1250                        p.x,
1251                        n.posBegin.y - chart.componentGapHeight / 2,
1252                        n.size.getWidth(),
1253                        n.size.getHeight());
1254                }
1255                if (n.typ == NodeType.TERM) {
1256                    // the quarter Arcs
1257                    final float foo =
1258                        (n.size.getHeight() - chart.componentGapHeight) / 2;
1259                    chart.drawArc(
1260                        chart.lineStroke,
1261                        chart.lineColor,
1262                        p.x,
1263                        n.posBegin.y,
1264                        foo,
1265                        foo,
1266                        180,
1267                        90);
1268                    chart.drawArc(
1269                        chart.lineStroke,
1270                        chart.lineColor,
1271                        p.x,
1272                        n.posLine.y,
1273                        foo,
1274                        foo,
1275                        90,
1276                        90);
1277                    chart.drawArc(
1278                        chart.lineStroke,
1279                        chart.lineColor,
1280                        p.x + n.size.getWidth() - foo,
1281                        n.posBegin.y,
1282                        foo,
1283                        foo,
1284                        270,
1285                        90);
1286                    chart.drawArc(
1287                        chart.lineStroke,
1288                        chart.lineColor,
1289                        p.x + n.size.getWidth() - foo,
1290                        n.posLine.y,
1291                        foo,
1292                        foo,
1293                        0,
1294                        90);
1295                    // the short vertical and horizontal lines between the quarter Arcs
1296                    chart.drawLine(
1297                        p.x
1298                        + (n.size.getHeight() - chart.componentGapHeight) / 4
1299                        - 1, n.posBegin.y, p.x
1300                        + n.size.getWidth()
1301                        - (n.size.getHeight() - chart.componentGapHeight) / 4
1302                        + 1, n.posBegin.y);
1303                    chart.drawLine(
1304                        p.x
1305                        + (n.size.getHeight() - chart.componentGapHeight) / 4
1306                        - 1, n.posEnd.y, p.x
1307                        + n.size.getWidth()
1308                        - (n.size.getHeight() - chart.componentGapHeight) / 4
1309                        + 1, n.posEnd.y);
1310                    chart.drawLine(
1311                        p.x,
1312                        n.posLine.y
1313                            + (n.size.getHeight() - chart.componentGapHeight) / 4
1314                            + 1, p.x,
1315                        n.posLine.y
1316                            - (n.size.getHeight() - chart.componentGapHeight) / 4
1317                            - 1);
1318                    chart.drawLine(
1319                        p.x + n.size.getWidth(),
1320                        n.posLine.y
1321                            + (n.size.getHeight() - chart.componentGapHeight)
1322                            / 4 + 1,
1323                        p.x + n.size.getWidth(),
1324                        n.posLine.y
1325                            - (n.size.getHeight() - chart.componentGapHeight)
1326                            / 4 - 1);
1327                } else {
1328                    n.posBegin.x = p.x;
1329                    n.posEnd.x = p.x + n.size.getWidth();
1330                    chart.drawRectangle(
1331                        chart.lineColor,
1332                        chart.lineStroke,
1333                        n.posBegin.x,
1334                        n.posBegin.y,
1335                        n.size.getWidth(),
1336                        (n.size.getHeight() - chart.componentGapHeight));
1337                }
1338//                              StringFormat drawFormat  = new StringFormat();
1339//                              drawFormat.setAlignment(StringAlignment.Center);
1340//                              drawFormat.setLineAlignment(StringAlignment.Center);
1341//                              DrawString(n.sym.name , charFont , charColor , new Rectangle((int)p.x,(int)n.posBegin.y,n.size.getWidth(),n.size.getHeight()-componentGapHeight-2),drawFormat);
1342                chart.drawString(
1343                    n.sym.name,
1344                    chart.charFont,
1345                    chart.charColor,
1346                    p.x
1347                        + chart.symbolGapWidth,
1348                    n.posBegin.y
1349                        + (n.size.getHeight() - chart.componentGapHeight)
1350                        - chart.symbolGapHeight);
1351                chart.drawArrow(
1352                    p.x + n.size.getWidth(),
1353                    n.posLine.y,
1354                    p.x + n.size.getWidth(),
1355                    n.posLine.y,
1356                    Grammar.Direction.LEFT);
1357
1358                if (!n.up
1359                    && n.next != null
1360                    && (n.next.typ == NodeType.TERM
1361                    || n.next.typ == NodeType.NONTERM))
1362                {
1363                    chart.drawArrow(
1364                        p.x,
1365                        n.posLine.y,
1366                        p.x - chart.componentGapWidth / 2,
1367                        n.posLine.y,
1368                        Grammar.Direction.LEFT);
1369                    p.x -= chart.componentGapWidth / 2;
1370                }
1371                if (!n.up
1372                    && n.next != null
1373                    && n.next.typ == NodeType.WRAP
1374                    && n.next.size.getHeight() == 0)
1375                {
1376                    if (!n.next.up
1377                        && n.next.next != null
1378                        && (n.next.next.typ == NodeType.TERM
1379                        || n.next.next.typ == NodeType.NONTERM))
1380                    {
1381                        chart.drawArrow(
1382                            p.x,
1383                            n.posLine.y,
1384                            p.x
1385                                - chart.componentGapWidth / 2,
1386                            n.posLine.y,
1387                            Grammar.Direction.LEFT);
1388                        p.x -= chart.componentGapWidth / 2;
1389                    }
1390                }
1391            } else if (n.typ == NodeType.EPS) {
1392                if (chart.showBorders) {
1393                    chart.drawRectangle(
1394                        Chart.EPS_COLOR,
1395                        Chart.STROKE1,
1396                        p.x,
1397                        n.posBegin.y,
1398                        n.size.getWidth(),
1399                        n.size.getHeight());
1400                }
1401
1402                chart.drawLine(
1403                    p.x,
1404                    n.posLine.y,
1405                    p.x + n.size.getWidth(),
1406                    n.posLine.y);
1407            } else if (n.typ == NodeType.OPT) {
1408                if (chart.showBorders) {
1409                    chart.drawRectangle(
1410                        Chart.OPT_COLOR,
1411                        Chart.STROKE1,
1412                        p.x,
1413                        n.posBegin.y,
1414                        n.size.getWidth(),
1415                        n.size.getHeight());
1416                }
1417
1418                // the two short lines at the beginning and the end
1419                chart.drawLine(
1420                    p.x,
1421                    n.posLine.y,
1422                    p.x + chart.componentGapWidth,
1423                    n.posLine.y);
1424                chart.drawLine(
1425                    p.x + n.size.getWidth(),
1426                    n.posLine.y,
1427                    p.x
1428                        + n.size.getWidth() - chart.componentGapWidth,
1429                    n.posLine.y);
1430                // the quarter Arcs
1431                chart.drawArcCorner(
1432                    p.x
1433                        + chart.componentGapWidth / 4
1434                        - chart.componentArcSize / 2,
1435                    n.posLine.y,
1436                    270);
1437                chart.drawArcCorner(
1438                    p.x
1439                        + chart.componentGapWidth / 4
1440                        + chart.componentArcSize / 2,
1441                    n.posEnd.y
1442                        - chart.componentArcSize
1443                        - chart.componentGapHeight / 2,
1444                    90);
1445                chart.drawArcCorner(
1446                    p.x
1447                        - chart.componentGapWidth / 4
1448                        - chart.componentArcSize / 2
1449                        + n.size.getWidth(),
1450                    n.posLine.y,
1451                    180);
1452                chart.drawArcCorner(
1453                    p.x
1454                        - chart.componentGapWidth / 4
1455                        - chart.componentArcSize * 3 / 2
1456                        + n.size.getWidth(),
1457                    n.posEnd.y
1458                        - chart.componentArcSize
1459                        - chart.componentGapHeight / 2,
1460                    0);
1461                // the short vertical lines between the quarter Arcs
1462                chart.drawLine(
1463                    p.x
1464                        + chart.componentGapWidth / 4
1465                        + chart.componentArcSize / 2,
1466                    n.posLine.y
1467                        + chart.componentArcSize / 2,
1468                    p.x
1469                        + chart.componentGapWidth / 4
1470                        + chart.componentArcSize / 2,
1471                    n.posEnd.y
1472                        - chart.componentArcSize / 2
1473                        - chart.componentGapHeight / 2 + 1);
1474                chart.drawLine(
1475                    p.x
1476                        - chart.componentGapWidth / 4
1477                        - chart.componentArcSize / 2
1478                        + n.size.getWidth(),
1479                    n.posLine.y
1480                        + chart.componentArcSize / 2,
1481                    p.x
1482                        - chart.componentGapWidth / 4
1483                        - chart.componentArcSize / 2
1484                        + n.size.getWidth(),
1485                    n.posEnd.y
1486                        - chart.componentArcSize / 2
1487                        - chart.componentGapHeight / 2 + 1);
1488                // the the long horizontal line between the quarter Arcs
1489                chart.drawLine(
1490                    p.x
1491                        + chart.componentGapWidth / 4
1492                        + chart.componentArcSize,
1493                    n.posEnd.y
1494                        - chart.componentGapHeight / 2,
1495                    p.x
1496                        - chart.componentGapWidth / 4
1497                        - chart.componentArcSize
1498                        + n.size.getWidth() + 1,
1499                    n.posEnd.y
1500                        - chart.componentGapHeight / 2);
1501
1502                p1.x = p.x + n.size.getWidth() - chart.componentGapWidth;
1503                n.sub.drawComponentsInverse(chart, p1, n.size);
1504            } else if (n.typ == NodeType.RERUN && n.itergraph == null) {
1505                if (chart.showBorders) {
1506                    chart.drawRectangle(
1507                        Chart.RERUN_COLOR,
1508                        Chart.STROKE1,
1509                        p.x,
1510                        n.posBegin.y,
1511                        n.size.getWidth(),
1512                        n.size.getHeight());
1513                }
1514
1515                // the two short lines at the beginning and the end
1516                chart.drawLine(
1517                    p.x,
1518                    n.posLine.y,
1519                    p.x + chart.componentGapWidth,
1520                    n.posLine.y);
1521                chart.drawLine(
1522                    p.x + n.size.getWidth(),
1523                    n.posLine.y,
1524                    p.x
1525                        + n.size.getWidth() - chart.componentGapWidth,
1526                    n.posLine.y);
1527                // the quarter Arcs
1528                chart.drawArcCorner(
1529                    p.x
1530                        + chart.componentGapWidth / 4
1531                        + chart.componentArcSize / 2,
1532                    n.posEnd.y
1533                        - chart.componentGapHeight / 2
1534                        - chart.componentArcSize,
1535                    90);
1536                chart.drawArcCorner(
1537                    p.x
1538                        + chart.componentGapWidth / 4
1539                        + chart.componentArcSize / 2,
1540                    n.posLine.y,
1541                    180);
1542                chart.drawArcCorner(
1543                    p.x
1544                        - chart.componentGapWidth / 4
1545                        - chart.componentArcSize * 3 / 2
1546                        + n.size.getWidth(),
1547                    n.posEnd.y
1548                        - chart.componentGapHeight / 2
1549                        - chart.componentArcSize,
1550                    0);
1551                chart.drawArcCorner(
1552                    p.x
1553                        - chart.componentGapWidth / 4
1554                        - chart.componentArcSize * 3 / 2
1555                        + n.size.getWidth(),
1556                    n.posLine.y,
1557                    270);
1558                // the short vertical lines between the quarter Arcs
1559                chart.drawLine(
1560                    p.x
1561                        + chart.componentGapWidth / 4
1562                        + chart.componentArcSize / 2,
1563                    n.posLine.y
1564                        + chart.componentArcSize / 2,
1565                    p.x
1566                        + chart.componentGapWidth / 4
1567                        + chart.componentArcSize / 2,
1568                    n.posEnd.y
1569                        - chart.componentGapHeight / 2
1570                        - chart.componentArcSize / 2 + 1);
1571                chart.drawLine(
1572                    p.x
1573                        - chart.componentGapWidth / 4
1574                        - chart.componentArcSize / 2
1575                        + n.size.getWidth(),
1576                    n.posLine.y
1577                        + chart.componentArcSize / 2,
1578                    p.x
1579                        - chart.componentGapWidth / 4
1580                        - chart.componentArcSize / 2
1581                        + n.size.getWidth(),
1582                    n.posEnd.y
1583                        - chart.componentGapHeight / 2
1584                        - chart.componentArcSize / 2 + 1);
1585                // the the long horizontal line between the quarter Arcs
1586                chart.drawLine(
1587                    p.x
1588                        + chart.componentGapWidth / 4
1589                        + chart.componentArcSize - 1,
1590                    n.posEnd.y
1591                        - chart.componentGapHeight / 2,
1592                    p.x
1593                        - chart.componentGapWidth / 4
1594                        - chart.componentArcSize
1595                        + n.size.getWidth() + 1,
1596                    n.posEnd.y
1597                        - chart.componentGapHeight / 2);
1598
1599                p1.x = p.x + n.size.getWidth() - chart.componentGapWidth;
1600                n.sub.drawComponentsInverse(chart, p1, n.size);
1601            } else if (n.typ == NodeType.RERUN && n.itergraph != null) {
1602                if (chart.showBorders) {
1603                    chart.drawRectangle(
1604                        Chart.RERUN1_COLOR,
1605                        Chart.STROKE1,
1606                        p.x,
1607                        n.posBegin.y,
1608                        n.size.getWidth(),
1609                        n.size.getHeight());
1610                }
1611
1612                // the two short lines at the beginning and the end of the first component
1613                chart.drawLine(
1614                    p.x,
1615                    n.posLine.y,
1616                    p.x
1617                        + n.size.getWidth() / 2
1618                        - n.altSize.getWidth() / 2 - 1,
1619                    n.posLine.y);
1620                chart.drawLine(
1621                    p.x
1622                        + n.size.getWidth() / 2
1623                        + n.altSize.getWidth() / 2 + 1,
1624                    n.posLine.y,
1625                    p.x
1626                        + n.size.getWidth(),
1627                    n.posLine.y);
1628                // the quarter Arcs
1629                chart.drawArcCorner(
1630                    p.x
1631                        + chart.componentGapWidth / 4
1632                        + chart.componentArcSize / 2,
1633                    n.itergraph.posLine.y
1634                        - chart.componentArcSize,
1635                    90);
1636                chart.drawArcCorner(
1637                    p.x
1638                        + chart.componentGapWidth / 4
1639                        + chart.componentArcSize / 2,
1640                    n.posLine.y,
1641                    180);
1642                chart.drawArcCorner(
1643                    p.x
1644                        - chart.componentGapWidth / 4
1645                        - chart.componentArcSize * 3 / 2
1646                        + n.size.getWidth(),
1647                    n.itergraph.posLine.y
1648                        - chart.componentArcSize,
1649                    0);
1650                chart.drawArcCorner(
1651                    p.x
1652                        - chart.componentGapWidth / 4
1653                        - chart.componentArcSize * 3 / 2
1654                        + n.size.getWidth(),
1655                    n.posLine.y,
1656                    270);
1657                // the short vertical lines between the quarter Arcs
1658                chart.drawLine(
1659                    p.x
1660                        + chart.componentGapWidth / 4
1661                        + chart.componentArcSize / 2,
1662                    n.posLine.y
1663                        + chart.componentArcSize / 2,
1664                    p.x
1665                        + chart.componentGapWidth / 4
1666                        + chart.componentArcSize / 2,
1667                    n.itergraph.posLine.y
1668                        - chart.componentArcSize / 2 + 1);
1669                chart.drawLine(
1670                    p.x
1671                        - chart.componentGapWidth / 4
1672                        - chart.componentArcSize / 2
1673                        + n.size.getWidth(),
1674                    n.posLine.y
1675                        + chart.componentArcSize / 2,
1676                    p.x
1677                        - chart.componentGapWidth / 4
1678                        - chart.componentArcSize / 2
1679                        + n.size.getWidth(),
1680                    n.itergraph.posLine.y
1681                        - chart.componentArcSize / 2 + 1);
1682                // the two short lines at the beginning and the end of the second component
1683                chart.drawLine(
1684                    p.x
1685                        + chart.componentGapWidth / 4
1686                        + chart.componentArcSize,
1687                    n.itergraph.posLine.y,
1688                    p.x
1689                        + n.size.getWidth() / 2
1690                        - n.iterSize.getWidth() / 2
1691                        - 1,
1692                    n.itergraph.posLine.y);
1693                chart.drawLine(
1694                    p.x
1695                        + n.size.getWidth() / 2
1696                        + n.iterSize.getWidth() / 2
1697                        + 1,
1698                    n.itergraph.posLine.y,
1699                    p.x
1700                        - chart.componentGapWidth / 4
1701                        - chart.componentArcSize
1702                        + n.size.getWidth() + 1,
1703                    n.itergraph.posLine.y);
1704
1705                n.sub.drawComponentsInverse(
1706                    chart,
1707                    new Float(
1708                        p.x
1709                            + n.size.getWidth() / 2 + n.altSize.getWidth() / 2,
1710                        n.posEnd.y),
1711                    n.size);
1712                n.itergraph.drawComponents(
1713                    chart,
1714                    new Float(
1715                        p.x + n.size.getWidth() / 2
1716                            - n.iterSize.getWidth() / 2,
1717                        n.posEnd.y),
1718                    n.size);
1719            } else if (n.typ == NodeType.ITER) {
1720                if (chart.showBorders) {
1721                    chart.drawRectangle(
1722                        Chart.ITER_COLOR,
1723                        Chart.STROKE1,
1724                        p.x,
1725                        n.posBegin.y,
1726                        n.size.getWidth(),
1727                        n.size.getHeight());
1728                }
1729
1730                // the quarter Arcs
1731                chart.drawArcCorner(
1732                    p.x
1733                        + chart.componentGapWidth / 4
1734                        + chart.componentArcSize / 2,
1735                    n.sub.posLine.y
1736                        - chart.componentArcSize,
1737                    90);
1738                chart.drawArcCorner(
1739                    p.x
1740                        + chart.componentGapWidth / 4
1741                        + chart.componentArcSize / 2,
1742                    n.posLine.y,
1743                    180);
1744                chart.drawArcCorner(
1745                    p.x
1746                        - chart.componentGapWidth / 4
1747                        - chart.componentArcSize * 3 / 2
1748                        + n.size.getWidth(),
1749                    n.sub.posLine.y
1750                        - chart.componentArcSize,
1751                    0);
1752                chart.drawArcCorner(
1753                    p.x
1754                        - chart.componentGapWidth / 4
1755                        - chart.componentArcSize * 3 / 2
1756                        + n.size.getWidth(),
1757                    n.posLine.y,
1758                    270);
1759                // the short vertical lines between the quarter Arcs
1760                chart.drawLine(
1761                    p.x
1762                        + chart.componentGapWidth / 4
1763                        + chart.componentArcSize / 2,
1764                    n.posLine.y
1765                        + chart.componentArcSize / 2,
1766                    p.x
1767                        + chart.componentGapWidth / 4
1768                        + chart.componentArcSize / 2,
1769                    n.sub.posLine.y
1770                        - chart.componentArcSize / 2 + 1);
1771                chart.drawLine(
1772                    p.x
1773                        - chart.componentGapWidth / 4
1774                        - chart.componentArcSize / 2
1775                        + n.size.getWidth(),
1776                    n.posLine.y
1777                        + chart.componentArcSize / 2,
1778                    p.x
1779                        - chart.componentGapWidth / 4
1780                        - chart.componentArcSize / 2
1781                        + n.size.getWidth(),
1782                    n.sub.posLine.y
1783                        - chart.componentArcSize / 2 + 1);
1784                // the two short horizontal lines between the quater Arcs and the components
1785                chart.drawLine(
1786                    p.x
1787                        + chart.componentGapWidth / 4
1788                        + chart.componentArcSize - 1,
1789                    n.sub.posLine.y,
1790                    p.x
1791                        + chart.componentGapWidth,
1792                    n.sub.posLine.y);
1793                chart.drawLine(
1794                    p.x
1795                        - chart.componentGapWidth
1796                        + n.size.getWidth(),
1797                    n.sub.posLine.y,
1798                    p.x
1799                        + n.size.getWidth()
1800                        - chart.componentGapWidth / 4
1801                        - chart.componentArcSize + 1,
1802                    n.sub.posLine.y);
1803                // the long horizontal line in the middle
1804                chart.drawLine(
1805                    p.x,
1806                    n.posLine.y,
1807                    p.x + n.size.getWidth(),
1808                    n.posLine.y);
1809
1810                p1.x = p.x + chart.componentGapWidth;
1811                n.sub.drawComponents(chart, p1, n.size);
1812            } else if (n.typ == NodeType.ALT) {
1813                p.x -= n.altSize.getWidth() - n.size.getWidth();
1814                if (chart.showBorders) {
1815                    chart.drawRectangle(
1816                        Color.RED,
1817                        Chart.STROKE1,
1818                        p.x,
1819                        n.posBegin.y,
1820                        n.altSize.getWidth(),
1821                        n.altSize.getHeight());
1822                }
1823
1824                // the two short lines at the beginning and the end of the altcomponent
1825                chart.drawLine(
1826                    p.x,
1827                    n.posLine.y,
1828                    p.x
1829                        + chart.componentArcSize * 3 / 2,
1830                    n.posLine.y);
1831                chart.drawLine(
1832                    p.x
1833                        + n.altSize.getWidth(),
1834                    n.posLine.y,
1835                    p.x
1836                        + n.altSize.getWidth()
1837                        - chart.componentArcSize * 3 / 2,
1838                    n.posLine.y);
1839                p1.x = p.x + 2 * chart.componentGapWidth;
1840                p1.y = p1.y + chart.componentGapHeight;
1841                Node a = n;
1842                boolean first = true;
1843                while (a != null) {
1844
1845                    // the horizontal lines at the beginning and the end
1846                    chart.drawLine(
1847                        p.x + chart.componentArcSize * 3 / 2,
1848                        a.sub.posLine.y,
1849                        p.x
1850                            + (n.altSize.getWidth() - a.size.getWidth()) / 2,
1851                        a.sub.posLine.y);
1852                    chart.drawLine(
1853                        p.x
1854                            - chart.componentArcSize * 3 / 2
1855                            + n.altSize.getWidth()
1856                            + 1,
1857                        a.sub.posLine.y,
1858                        p.x
1859                            + (n.altSize.getWidth() - a.size.getWidth()) / 2
1860                            + a.size.getWidth(),
1861                        a.sub.posLine.y);
1862                    // if the first Alternative draw differnt Arcs
1863                    if (first) {
1864                        chart.drawArcCorner(
1865                            p.x,
1866                            n.posLine.y,
1867                            270);
1868                        chart.drawArcCorner(
1869                            p.x
1870                                + n.altSize.getWidth()
1871                                - chart.componentArcSize,
1872                            n.posLine.y,
1873                            180);
1874                        first = false;
1875                    } else {
1876                        // else draw other Arcs and vertical lines
1877                        chart.drawArcCorner(
1878                            p.x + chart.componentArcSize,
1879                            a.sub.posLine.y
1880                                - chart.componentArcSize,
1881                            90);
1882                        chart.drawLine(
1883                            p.x + chart.componentArcSize,
1884                            n.posLine.y
1885                                + chart.componentArcSize / 2,
1886                            p.x
1887                                + chart.componentArcSize,
1888                            a.posLine.y
1889                                - chart.componentArcSize / 2 + 1);
1890                        chart.drawArcCorner(
1891                            p.x
1892                                - chart.componentArcSize * 2
1893                                + n.altSize.getWidth(),
1894                            a.sub.posLine.y
1895                            - chart.componentArcSize,
1896                            0);
1897                        chart.drawLine(
1898                            p.x
1899                                - chart.componentArcSize
1900                                + n.altSize.getWidth(),
1901                            n.posLine.y
1902                                + chart.componentArcSize / 2,
1903                            p.x
1904                                - chart.componentArcSize
1905                                + n.altSize.getWidth(),
1906                            a.posLine.y
1907                                - chart.componentArcSize / 2 + 1);
1908                    }
1909                    Float pf = new Float(
1910                        p.x
1911                            + (n.altSize.getWidth() + a.size.getWidth()) / 2,
1912                        p1.y);
1913                    a.sub.drawComponentsInverse(chart, pf, a.size);
1914                    a = a.down;
1915                }
1916            }
1917            if (n.up) {
1918                samelevel = false;
1919            }
1920            n = n.next;
1921        }
1922    }
1923
1924    public void accept(Chart.NodeVisitor nodeVisitor) {
1925        nodeVisitor.visit(this);
1926    }
1927
1928    public void visitChildren(Chart.NodeVisitor visitor) {
1929        switch (typ) {
1930        case TERM:
1931        case NONTERM:
1932            break;
1933        case ALT:
1934            final List<Node> alts = new ArrayList<Node>();
1935            for (Node n = this; n != null; n = n.down) {
1936                n.sub.accept(visitor);
1937            }
1938            break;
1939        case ITER:
1940            for (Node node : nextChildren(sub)) {
1941                node.accept(visitor);
1942            }
1943            break;
1944        default:
1945            throw new RuntimeException("unknown <" + typ + ">");
1946        }
1947    }
1948}
1949
1950// End Node.java