/**
 *  Licensed under GPL. For more information, see
 *    http://jaxodraw.sourceforge.net/license.html
 *  or the LICENSE file in the jaxodraw distribution.
 */
package net.sf.jaxodraw.io.imports;

import java.awt.Color;
import java.awt.geom.Point2D;

import java.util.ArrayList;
import java.util.List;

import net.sf.jaxodraw.object.JaxoObject;
import net.sf.jaxodraw.object.JaxoObjectFactory;
import net.sf.jaxodraw.util.JaxoColor;
import net.sf.jaxodraw.util.JaxoConstants;


/** Defines a number of axodraw LaTeX commands and all the methods to convert
 * them into JaxoObjects. This is responsible for the import option.
 * @since 2.0
 */
public class JaxoAxodraw {
    protected static final String LINE = "\\Line";
    protected static final String COLOR = "color";
    protected static final String REL_WIDTH = "relativeWidth";
    protected static final String REL_HEIGHT = "relativeHeight";
    protected static final String PAINT_ARROW = "paintArrow";
    protected static final String STROKE_WIDTH = "strokeWidth";
    protected static final String FREQ_FROM_WIGGLES = "frequencyFromWiggles";
    protected static final String DOUBLE_LINE = "doubleLine";
    protected static final String DL_SEP = "dLSeparation";
    protected static final String AMP = "amp";
    protected static final String DASH = "dash";

    private static final String CTRI = "\\CTri";
    private static final String FILL_COLOR = "fillColor";
    private static final String FILLED = "filled";
    private static final String ARROW_POS = "arrowPosition";
    private static final String FLIP = "flip";
    private static final String ROT_ANGLE = "rotationAngle";

    private static final String[] KNOWN_COMMANDS =
    {
        "\\ArrowArcn", "\\ArrowArc", "\\ArrowLine", "\\CArc", "\\CBox",
        "\\CCirc", "\\COval", CTRI, "\\DashArrowArcn", "\\DashArrowArc",
        "\\DashArrowLine", "\\DashCArc", "\\DashLine", "\\GBox", "\\GCirc",
        "\\GlueArc", "\\Gluon", "\\GOval", "\\GTri", LINE,
        "\\LongArrowArcn", "\\LongArrowArc", "\\LongArrow", "\\PhotonArc",
        "\\Photon", "\\SetColor", "\\SetWidth", "\\Text", "\\Vertex",
        "\\ZigZag", "\\EBox", "\\Oval", "\\ETri"
    };
    private static final int N_OF_COMMANDS = KNOWN_COMMANDS.length;
    private static final String[] REQUIRED_COMMANDS =
    {"\\documentclass", "\\begin{document}", "\\begin{picture}"};
    private static final int N_OF_REQUIRED = REQUIRED_COMMANDS.length;
    private final boolean[] isValid = new boolean[3];
    private String string = "";
    private int index;
    private Color color = JaxoColor.BLACK;
    private float stroke = 0.5f;
    private float scaleFactor = 1.f; // default, will be set later
    private String comment = "";
    private float bBoxHeight; // set when a \begin{picture} command is read
    private final List<String> packageList;

    /** Constructor: Initializes the list of Latex packages
     *  (axodraw and color).
     */
    public JaxoAxodraw() {
        this.packageList = new ArrayList<String>(3);
        packageList.add("axodraw");
        packageList.add(COLOR);
    }

    /**
     * Returns a JaxoObject corresponding to a axodraw command.
     *
     * @param newString One line of a latex file
     * @return A JaxoObject the corresponds to the axodraw command
     * of the input line, or null, if nothing corresponds
     */
    public JaxoObject getJaxoObject(final String newString) {
        this.string = newString;

        if (!isValidJaxoCommand(string)) {
            return null;
        }

        JaxoObject newOb = null;

        if (index == -5) { // Circle cross unfilled
            newOb = newVertexT2Unfilled();
        } else if (index == -4) { // Circle cross gray
            newOb = newVertexT2Gray();
        } else if (index == -3) { // Diamond
            newOb = newVertexT6();
        } else if (index == -2) { // Cross
            newOb = newVertexT4();
        } else if (index == -1) { // Circle Cross
            newOb = newVertexT2();
        } else if (index == getIndex("\\ArrowArcn")) { // ArrowArcn
            newOb = newFLoop(true, true, false);
        } else if (index == getIndex("\\ArrowArc")) { // ArrowArc
            newOb = newFLoop(false, true, false);
        } else if (index == getIndex("\\ArrowLine")) { // ArrowLine
            newOb = newLine(true, false);
        } else if (index == getIndex("\\CArc")) { // CArc
            newOb = newFLoop(false, false, false);
        } else if (index == getIndex("\\CBox")) { // CBox
            newOb = newCBox();
        } else if (index == getIndex("\\CCirc")) { // CCirc
            newOb = newCCirc();
        } else if (index == getIndex("\\COval")) { // COval
            newOb = newCOval();
        } else if (index == getIndex(CTRI)) { // CTri
            newOb = newCTri();
        } else if (index == getIndex("\\DashArrowArcn")) { // DashArrowArcn
            newOb = newDashArc(true, true);
        } else if (index == getIndex("\\DashArrowArc")) { // DashArrowArc
            newOb = newDashArc(false, true);
        } else if (index == getIndex("\\DashArrowLine")) { // DashArrowLine
            newOb = newDashLine(true);
        } else if (index == getIndex("\\DashCArc")) { // DashCArc
            newOb = newDashArc(false, false);
        } else if (index == getIndex("\\DashLine")) { // DashLine
            newOb = newDashLine(false);
        } else if (index == getIndex("\\GBox")) { // GBox
            newOb = newGBox();
        } else if (index == getIndex("\\GCirc")) { // GCirc
            newOb = newGCirc();
        } else if (index == getIndex("\\GlueArc")) { // GlueArc
            newOb = newGlArc();
        } else if (index == getIndex("\\Gluon")) { // Gluon
            newOb = newGlLine();
        } else if (index == getIndex("\\GOval")) { // GOval
            newOb = newGOval();
        } else if (index == getIndex("\\GTri")) { // GTri
            newOb = newGTri();
        } else if (index == getIndex(LINE)) { // Line
            newOb = newLine(false, false);
        } else if (index == getIndex("\\LongArrowArcn")) { // ArrowArc with clockwise arrow at the end
            newOb = newFLoop(true, true, true);
        } else if (index == getIndex("\\LongArrowArc")) { // ArrowArc with counterclockwise arrow at the end
            newOb = newFLoop(false, true, true);
        } else if (index == getIndex("\\LongArrow")) { // ArrowLine with arrow at the end
            newOb = newLine(true, true);
        } else if (index == getIndex("\\PhotonArc")) { // PhotonArc
            newOb = newPArc();
        } else if (index == getIndex("\\Photon")) { // Photon
            newOb = newPLine();
        } else if (index == getIndex("\\SetColor")) { // SetColor
            this.color = JaxoColor.getColor(getOneCurl(string));
        } else if (index == getIndex("\\SetWidth")) { // SetWidth
            this.stroke = Float.parseFloat(getOneCurl(string));
        } else if (index == getIndex("\\Text")) { // Text
            newOb = newText();
        } else if (index == getIndex("\\Vertex")) { // Vertex
            newOb = newVertexT1();
        } else if (index == getIndex("\\ZigZag")) { // ZigZag
            newOb = newZigZagLine();
        } else if (index == getIndex("\\EBox")) { // unfilled Box
            newOb = newEBox();
        } else if (index == getIndex("\\Oval")) { // unfilled Blob
            newOb = newOval();
        } else if (index == getIndex("\\ETri")) { // unfilled vertex T5
            newOb = newETri();
        }

        return newOb;
    }

    /**
     * Checks whether the given string starts with one of "\documentclass",
     * "\begin{document}" or "\begin{picture}".
     *
     * @param newString The input string.
     */
    public final void checkRequired(final String newString) {
        this.string = newString;

        if (string.startsWith("\\usepackage")) {
            addPackage(getOneCurl(string));
        } else if (string.startsWith("%%JaxoComment:")) {
            this.comment = string.replaceFirst("%%JaxoComment:", "").trim();
        } else if (string.startsWith("%%JaxoScale")) {
            this.scaleFactor = Float.parseFloat(getOneCurl(string));
        } else {
            boolean isRequiredCommand = false;
            int i = 0;

            while (!string.startsWith(REQUIRED_COMMANDS[i])
                    && (i < (N_OF_REQUIRED - 1))) {
                i++;
            }

            if ((i == (N_OF_REQUIRED - 1))
                    && !string.startsWith(REQUIRED_COMMANDS[i])) {
                i++;
            }

            isRequiredCommand = (i < N_OF_REQUIRED);

            if (isRequiredCommand) {
                isValid[i] = true;

                if (i == 2) { // read the \begin(picture) parameters
                    final int[] pic = getTwoInts(string);
                    this.bBoxHeight = (float) pic[1] * getScaleFactor();
                }
            }
        }
    }

    /**
     * Returns an array that indicates which required LaTeX commands
     * were found.
     *
     * @return An array of three boolean variables, the first is true
     * if "\documentclass" was found, the second is true if
     * "\begin{document}" was found, the third is true if
     * "\begin{picture}" was found
     */
    public final boolean[] getValid() {
        final int length = isValid.length;
        final boolean[] newArray = new boolean[length];
        System.arraycopy(isValid, 0, newArray, 0, length);
        return newArray;
    }

    /**
     * Returns the current list of LaTeX packages included in the graph.
     *
     * @return A List that contains strings of latex packages.
     */
    public final List<String> getPackages() {
        return packageList;
    }

    /**
     * Adds a latex package if it is not already contained in the package list.
     *
     * @param pack the package to add.
     */
    public final void addPackage(final String pack) {
        if (!this.packageList.contains(pack)) {
            this.packageList.add(pack);
        }
    }

    /**
     * Removes a latex package if it is contained in the package list.
     *
     * @param pack the package to remove.
     * @return true if the list contained the package, ie the list was modified.
     */
    public final boolean removePackage(final String pack) {
        return this.packageList.remove(pack);
    }

    /**
     * Returns the comment (description) of this axodraw object.
     *
     * @return The axodraw comment
     */
    public final String getComment() {
        return comment;
    }

    /** Returns the scale factor of this axodraw object.
     * @return The axodraw scale factor.
     */
    public final float getScaleFactor() {
        return scaleFactor;
    }

      //
     // private
    //

    private boolean isValidJaxoCommand(final String s) {
        int i = 0;

        while (!s.startsWith(KNOWN_COMMANDS[i]) && (i < (N_OF_COMMANDS - 1))) {
            i++;
        }

        if ((i == (N_OF_COMMANDS - 1)) && !s.startsWith(KNOWN_COMMANDS[i])) {
            i++;
        }

        this.index = i;

        // check for CircleCross, Cross vertex and diamonds
        if (i == getIndex("\\COval")) {
            if (s.indexOf(LINE, 6) > 0) {
                this.index = -1;
            }
        } else if (i == getIndex("\\GOval")) {
            if (s.indexOf(LINE, 6) > 0) {
                this.index = -4;
            }
        } else if (i == getIndex(LINE)) {
            if ((s.indexOf(LINE, 6) > 0) && (s.indexOf('%') == -1)) {
                this.index = -2;
            }
        } else if (i == getIndex(CTRI)) {
            if (s.indexOf(CTRI, 6) > 0) {
                this.index = -3;
            }
        } else if (i == getIndex("\\Oval")) {
            if (s.indexOf(LINE, 6) > 0) {
                this.index = -5;
            }
        }

        return (i < N_OF_COMMANDS);
    }

    private int getIndex(final String s) {
        int i = 0;

        while ((KNOWN_COMMANDS[i].compareTo(s) != 0)
                && (i < (N_OF_COMMANDS - 1))) {
            i++;
        }

        if (KNOWN_COMMANDS[i].compareTo(s) == 0) {
            return i;
        } else {
            return N_OF_COMMANDS;
        }
    }

/*
    private String getLatexCommand(int i) {
        if (i < N_OF_COMMANDS) {
            return KNOWN_COMMANDS[i];
        } else {
            return "?";
        }
    }

    private boolean isAxodrawCommand(String s) {
        int i = getIndex(s);

        return (i < N_OF_COMMANDS);
    }
*/
    protected int[] getLineParams(final int[] in, final String st) {
        // xi = in[0], yi = in[1], xf = in[2], yf = in[3],
        final int[] out = new int[4];

        out[0] = Math.round(in[0] * getScaleFactor());
        out[1] = Math.round(getBBoxHeight() - (in[1] * getScaleFactor()));
        out[2] = Math.round((in[2] - in[0]) * getScaleFactor());
        out[3] = Math.round((in[1] - in[3]) * getScaleFactor());

        if (!(st.indexOf('%') == -1)) {
            final double theta =
                Math.atan2((in[1] - in[3]) * getScaleFactor(),
                    (in[2] - in[0]) * getScaleFactor());
            final float dlSep = theDLSeparation(st);
            out[0] = Math.round(out[0] - (float) (dlSep * Math.sin(theta)));
            out[1] = Math.round(out[1] + (float) (dlSep * Math.cos(theta)));
        }

        return out;
    }

    private int[] getBoxParams(final int[] in) {
        // xi = in[0], yi = in[1], xf = in[2], yf = in[3],
        final int[] out = new int[4];

        out[2] = Math.round((in[2] - in[0]) * getScaleFactor());
        out[3] = Math.round((in[3] - in[1]) * getScaleFactor());
        out[0] = Math.round(in[0] * getScaleFactor());
        out[1] = Math.round(getBBoxHeight() - (in[3] * getScaleFactor()));

        return out;
    }

    private int[] getCircParams(final int[] in, final String rad) {
        final int[] out = new int[3];

        out[0] = Math.round(in[0] * getScaleFactor());
        out[1] = Math.round(getBBoxHeight() - (in[1] * getScaleFactor()));
        out[2] = Math.round(Float.parseFloat(rad) * getScaleFactor());

        return out;
    }

    private int[] getBlobParams(final String[] in) {
        // xi = in[0], yi = in[1], xf = in[2], yf = in[3],
        final int[] out = new int[5];

        out[2] = Math.round(Float.parseFloat(in[2]) * getScaleFactor());
        out[3] = Math.round(Float.parseFloat(in[3]) * getScaleFactor());
        out[0] = Math.round(Float.parseFloat(in[0]) * getScaleFactor());
        out[1] =
            Math.round(getBBoxHeight() - (Float.parseFloat(in[1]) * getScaleFactor()));
        out[4] = Math.round(Float.parseFloat(in[4]));

        return out;
    }

    private int[] getT1Params(final String[] st) {
        int[] out = new int[2];

        final float x = Float.parseFloat(st[0]);
        final float y = Float.parseFloat(st[1]);

        out[0] = Math.round(x * getScaleFactor());
        out[1] = Math.round(getBBoxHeight() - (y * getScaleFactor()));

        return out;
    }

    private int[] getT2Params(final String[] st) {
        final int[] out = new int[4];

        final float radius = Float.parseFloat(st[2]) * getScaleFactor();
        final float angle = (float) Math.toRadians(Float.parseFloat(st[4]));
        final float cx = Float.parseFloat(st[0]) * getScaleFactor();
        final float cy = Float.parseFloat(st[1]) * getScaleFactor();

        out[2] = (int) Math.round(radius * Math.sin(angle));
        out[3] = (int) Math.round(radius * Math.cos(angle));

        if ((out[2] > 0) && (out[3] >= 0)) {
            out[0] = Math.round(cx);
            out[1] = Math.round(getBBoxHeight() - cy);
        } else if ((out[2] >= 0) && (out[3] < 0)) {
            out[0] = Math.round(cx + out[3]);
            out[1] = Math.round(getBBoxHeight() - cy);
        } else if ((out[2] <= 0) && (out[3] > 0)) {
            out[0] = Math.round(cx);
            out[1] = Math.round((getBBoxHeight() + out[2]) - cy);
        } else if ((out[2] < 0) && (out[3] <= 0)) {
            out[0] = Math.round(cx + out[3]);
            out[1] = Math.round((getBBoxHeight() + out[2]) - cy);
        }

        return out;
    }

    private int[] getT3Params(final int[] in) {
        final int[] out = new int[4];

        out[0] = Math.round((in[2] + in[0]) / 2.f);
        out[1] = Math.round(getBBoxHeight() - ((in[3] + in[1]) / 2.f));
        out[2] =
            (int) Math.round((
                    Math.abs(in[2] - in[0]) * Math.sin(Math.toRadians(45))
                ) / 2);
        out[3] =
            (int) Math.round((
                    Math.abs(in[2] - in[0]) * Math.cos(Math.toRadians(45))
                ) / 2);

        return out;
    }

    protected int[] getT4Params(final int[] firstl, final int[] secondl) {
        final int[] out = new int[4];

        out[2] = Math.round(((secondl[2] - secondl[0]) * getScaleFactor()) / 2);

        out[3] = Math.round(((secondl[1] - secondl[3]) * getScaleFactor()) / 2);

        if (((secondl[2] - secondl[0]) > 0) && ((firstl[2] - firstl[0]) > 0)) {
            out[0] = Math.round((secondl[0] * getScaleFactor()) + out[2]);
            out[1] =
                Math.round(getBBoxHeight() - (secondl[1] * getScaleFactor()) + out[3]);
        } else if (((secondl[2] - secondl[0]) > 0)
                && ((firstl[2] - firstl[0]) < 0)) {
            out[0] = Math.round((secondl[0] * getScaleFactor()) + out[2]);
            out[1] =
                Math.round(getBBoxHeight() - (secondl[1] * getScaleFactor())
                    + (2 * out[3]));
        } else if (((secondl[2] - secondl[0]) < 0)
                && ((firstl[2] - firstl[0]) < 0)) {
            out[0] = Math.round((secondl[0] * getScaleFactor()) + (2 * out[2]));
            out[1] =
                Math.round(getBBoxHeight() - (secondl[1] * getScaleFactor())
                    + (2 * out[3]));
        } else if (((secondl[2] - secondl[0]) < 0)
                && ((firstl[2] - firstl[0]) > 0)) {
            out[0] = Math.round((secondl[0] * getScaleFactor()) + (2 * out[2]));
            out[1] =
                Math.round(getBBoxHeight() - (secondl[1] * getScaleFactor()) + out[3]);
        }

        return out;
    }

    protected Point2D[] getArcPoints(final String[] st, final boolean clock) {
        final double cx = Double.parseDouble(st[0]) * getScaleFactor();
        final double cy = getBBoxHeight() - (Double.parseDouble(st[1]) * getScaleFactor());
        final double radius = Double.parseDouble(st[2]) * getScaleFactor();
        final double phi1 = Double.parseDouble(st[3]);
        final double phi2 = Double.parseDouble(st[4]);

        final Point2D.Double cp = new Point2D.Double(cx, cy);

        final Point2D.Double fpt =
            new Point2D.Double(cx + (
                    radius * Math.cos(Math.toRadians(-phi1))
                ), cy + (radius * Math.sin(Math.toRadians(-phi1))));

        final Point2D.Double tpt = new Point2D.Double(cx + (
                    radius * Math.cos(Math.toRadians(-phi2))
                ), cy + (radius * Math.sin(Math.toRadians(-phi2))));

        final Point2D.Double spt = getSecondArcPoint(cp, fpt, tpt, clock);

        return new Point2D[] {fpt, spt, tpt};
    }

    private Point2D.Double getSecondArcPoint(final Point2D.Double cp,
            final Point2D.Double p1, final Point2D.Double p3, final boolean clock) {
        final double rsq = ((p1.x - cp.x) * (p1.x - cp.x)) + ((p1.y - cp.y) * (p1.y - cp.y));

        // to get the mid-arc point, we intersect the circle with the
        // perpendicular of the line P1-P3 going through the point between them
        final double x13 = (p3.x + p1.x) / 2.d;
        final double y13 = (p3.y + p1.y) / 2.d;

        double px1, px2, py1, py2;

        if (Math.round(p1.x) == Math.round(p3.x)) {
            py1 = y13;
            py2 = y13;
            px1 = cp.x - Math.sqrt(rsq - ((y13 - cp.y) * (y13 - cp.y)));
            px2 = cp.x + Math.sqrt(rsq - ((y13 - cp.y) * (y13 - cp.y)));
        } else if (Math.round(p1.y) == Math.round(p3.y)) {
            px1 = x13;
            px2 = x13;
            py1 = cp.y - Math.sqrt(rsq - ((x13 - cp.x) * (x13 - cp.x)));
            py2 = cp.y + Math.sqrt(rsq - ((x13 - cp.x) * (x13 - cp.x)));
        } else {
            final double ma = (p3.y - p1.y) / (p3.x - p1.x);
            final double a = 1.d + (1 / ma / ma);
            final double b =
                ((2 * cp.y) / ma) - (2 * cp.x) - ((2 * y13) / ma)
                - ((2 * x13) / ma / ma);
            final double c =
                (
                    (
                        (cp.x * cp.x) + ((x13 * x13) / ma / ma) + (y13 * y13)
                        + ((2 * y13 * x13) / ma)
                    ) - ((2 * cp.y * x13) / ma) - (2 * cp.y * y13)
                    + (cp.y * cp.y)
                ) - rsq;
            final double rad = Math.sqrt((b * b) - (4 * a * c));
            px1 = (-b + rad) / 2 / a;
            px2 = (-b - rad) / 2 / a;
            py1 = (-(px1 - x13) / ma) + y13;
            py2 = (-(px2 - x13) / ma) + y13;
        }

        // there are two solutions: (px1, py1) and (px2, py2),
        // we want the one that is in clock (parameter) direction
        double px = px1;
        double py = py1;

        final double cross = (p1.x - cp.x) * (py1 - cp.y) - (p1.y - cp.y) * (px1 - cp.x);
        final boolean cl = (cross < 0);

        if (cl == clock) {
            px = px2;
            py = py2;
        }

        return new Point2D.Double(px, py);
    }

    protected int[] getLoopPars(final String[] st, final String st1, final boolean cntrclk) {
        final int[] out = new int[4];

        final float x = Float.parseFloat(st[0]);
        final float y = Float.parseFloat(st[1]);
        float r = Float.parseFloat(st[2]);
        final int phi1 = Math.round(Float.parseFloat(st[3]));
        final int phi2 = Math.round(Float.parseFloat(st[4]));

        if (!(st1.indexOf('%') == -1)) {
            r -= theDLSeparation(st1);
        }

        double alpha = 0;

        if (cntrclk) {
            if (phi1 > phi2) {
                alpha = Math.toRadians(-phi1 + 180);
            } else {
                alpha = Math.toRadians(-phi2 + 180);
            }
        } else {
            if (phi1 > phi2) {
                alpha = Math.toRadians(-phi2 + 180);
            } else {
                alpha = Math.toRadians(-phi1 + 180);
            }
        }

        out[0] = (int) (x * getScaleFactor());
        out[1] = (int) (getBBoxHeight() - (y * getScaleFactor()));
        out[2] = (int) Math.round(r * getScaleFactor() * Math.cos(alpha));
        out[3] = (int) Math.round(r * getScaleFactor() * Math.sin(alpha));

        return out;
    }

    /**
     * Returns the five strings s1-s5 contained in a string
     * of the form " # (s1, s2) (s3, s4) (s5) * " where * can be anything
     * and # doesn't contain any parenthesis.
     */
    private String[] getOvalBrackets(final String str) {
        final String[] st = new String[5];

        int start = str.indexOf('(');
        int comma = str.indexOf(',', start);
        int stop = str.indexOf(')', start);
        st[0] = str.substring(start + 1, comma);
        st[1] = str.substring(comma + 1, stop);

        int offset = stop + 1;

        start = str.indexOf('(', offset);
        comma = str.indexOf(',', offset);
        stop = str.indexOf(')', offset);
        st[2] = str.substring(start + 1, comma);
        st[3] = str.substring(comma + 1, stop);

        offset = stop + 1;

        start = str.indexOf('(', offset);
        stop = str.indexOf(')', offset);

        st[4] = str.substring(start + 1, stop);

        return st;
    }

    /**
     * Returns the four integers xi,yi,xf,yf contained in a string
     * of the form " # (xi,yi) (xf,yf) * " where * can be anything
     * and # doesn't contain any parenthesis.
     *
     * @param str the string.
     * @return the four ints.
     */
    protected int[] getFourInts(final String str) {
        return getFourInts(str, 0);
    }

    /**
     * Returns the two integers xi,yi contained in a string
     * of the form " # (xi,yi) * " where * can be anything
     * and # doesn't contain any parenthesis.
     *
     * @param str the string.
     * @return the two ints.
     */
    protected int[] getTwoInts(final String str) {
        final int[] ints = new int[2];

        final int start = str.indexOf('(');
        final int comma = str.indexOf(',', start);
        final int stop = str.indexOf(')', start);
        ints[0] =
            Math.round(Float.parseFloat(str.substring(start + 1, comma)));
        ints[1] = Math.round(Float.parseFloat(str.substring(comma + 1, stop)));

        return ints;
    }

    /**
     * Returns the four integers xi,yi,xf,yf contained in a string
     * of the form " # (xi,yi) (xf,yf) * " where * can be anything
     * and # doesn't contain any parenthesis.
     *
     * @param str the string.
     * @param fromIndex the starting index.
     * @return the four ints.
     */
    protected int[] getFourInts(final String str, final int fromIndex) {
        final int[] ints = new int[4];

        int start = str.indexOf('(', fromIndex);
        int comma = str.indexOf(',', start);
        int stop = str.indexOf(')', start);
        ints[0] =
            Math.round(Float.parseFloat(str.substring(start + 1, comma)));
        ints[1] = Math.round(Float.parseFloat(str.substring(comma + 1, stop)));

        final int offset = stop + 1;
        start = str.indexOf('(', offset);
        comma = str.indexOf(',', offset);
        stop = str.indexOf(')', offset);
        ints[2] =
            Math.round(Float.parseFloat(str.substring(start + 1, comma)));
        ints[3] = Math.round(Float.parseFloat(str.substring(comma + 1, stop)));

        return ints;
    }

    /**
     * Returns the six integers x1, y1,x2,y2,x3,y3 contained in a string
     * of the form " # (x1, y1) (x2,y2) (x3,y3) * " where * can be anything
     * and # doesn't contain any parenthesis.
     *
     * @param str the string.
     * @return the six ints.
     */
    protected int[] getSixInts(final String str) {
        final int[] ints = new int[6];

        int start = str.indexOf('(');
        int comma = str.indexOf(',', start);
        int stop = str.indexOf(')', start);
        ints[0] =
            Math.round(Float.parseFloat(str.substring(start + 1, comma)));
        ints[1] = Math.round(Float.parseFloat(str.substring(comma + 1, stop)));

        int offset = stop + 1;
        start = str.indexOf('(', offset);
        comma = str.indexOf(',', offset);
        stop = str.indexOf(')', offset);
        ints[2] =
            Math.round(Float.parseFloat(str.substring(start + 1, comma)));
        ints[3] = Math.round(Float.parseFloat(str.substring(comma + 1, stop)));

        offset = stop + 1;
        start = str.indexOf('(', offset);
        comma = str.indexOf(',', offset);
        stop = str.indexOf(')', offset);
        ints[4] =
            Math.round(Float.parseFloat(str.substring(start + 1, comma)));
        ints[5] = Math.round(Float.parseFloat(str.substring(comma + 1, stop)));

        return ints;
    }

    private int[] getTriangleParameters(final int[] coords) {
        final int[] out = {0, 0, 0, 0, 0, 0};

        out[0] = Math.round(coords[0] * getScaleFactor());
        out[1] = Math.round(getBBoxHeight() - (coords[1] * getScaleFactor()));
        out[2] = Math.round(coords[2] * getScaleFactor());
        out[3] = Math.round(getBBoxHeight() - (coords[3] * getScaleFactor()));
        out[4] = Math.round(coords[4] * getScaleFactor());
        out[5] = Math.round(getBBoxHeight() - (coords[5] * getScaleFactor()));

        return out;
    }

    private int getTeXAllign(final String str) {
        final List<String> possible = new ArrayList<String>(9);
        possible.add("lt");
        possible.add("l");
        possible.add("lb");
        possible.add("t");
        possible.add("");
        possible.add("b");
        possible.add("rt");
        possible.add("r");
        possible.add("rb");

        return possible.indexOf(str);
    }

    private Color getTeXColor(final String str) {
        final int offset = str.indexOf("{\\");
        final int start = str.indexOf('\\', offset);
        final int stop = str.indexOf('$');

        if ((stop > start) && (start != -1)) {
            return JaxoColor.getColor(str.substring(start + 1, stop - 1));
        }

        return JaxoColor.BLACK;
    }

    private int getTeXSize(final String str) {
        String st;

        final int start = str.indexOf('\\');
        final int stop = str.indexOf('{', start);

        if ((stop > start) && (start != -1)) {
            st = str.substring(start + 1, stop);

            final List<String> possible = new ArrayList<String>(10);
            possible.add("tiny");
            possible.add("scriptsize");
            possible.add("footnotesize");
            possible.add("small");
            possible.add("normalsize");
            possible.add("large");
            possible.add("Large");
            possible.add("LARGE");
            possible.add("huge");
            possible.add("Huge");

            if (possible.indexOf(st) == -1) {
                return 4;
            } else {
                return possible.indexOf(st);
            }
        } else {
            return 4;
        }
    }

    private String getTeXText(final String str) {
        final int start = str.indexOf('$');
        final int stop = str.lastIndexOf('$');

        return str.substring(start + 1, stop);
    }

    private int getTexRotangle(final String str) {
        final int start = str.indexOf('{');
        final int stop = str.indexOf('}', start + 1);

        return Math.round(Float.parseFloat(str.substring(start + 1, stop)));
    }

    private String getRotatedTexText(final String str, final String fullstr) {
        final int start = str.indexOf('{');
        final int stop = str.indexOf('}', start + 1);
        final int offset = fullstr.indexOf('$');
        final int stop1 = fullstr.indexOf('$', offset + 1);

        return fullstr.substring(offset + stop + 3, stop1 - 1);
    }

    /**
     * Returns the two integers xi,yi contained in a string
     * of the form " # (xi,yi) * " where * can be anything
     * and # doesn't contain any parenthesis.
     *
     * @param str the String.
     * @return the two ints.
     */
    protected String[] getOneBracket(final String str) {
        final String[] st = new String[2];

        final int start = str.indexOf('(');
        final int comma = str.indexOf(',', start);
        final int stop = str.indexOf(')', start);

        st[0] = str.substring(start + 1, comma);
        st[1] = str.substring(comma + 1, stop);

        return st;
    }

    /**
     * Returns the four integers xi,yi,xf,yf contained in a string
     * of the form " # [String] * " where * can be anything
     * and # doesn't contain any braces.
     *
     * @param str the String.
     * @return the four ints.
     */
    protected String getOneBrace(final String str) {
        final int start = str.indexOf('[');
        final int stop = str.indexOf(']', start);

        return str.substring(start + 1, stop);
    }

    /**
     * Returns the string "String" contained in a string
     * of the form " # {String} * " where * can be anything
     * and # doesn't contain any curly brackets.
     *
     * @param str the String.
     * @return the String.
     */
    protected String getOneCurl(final String str) {
        final int start = str.indexOf('{');
        final int stop = str.indexOf('}', start);

        return str.substring(start + 1, stop);
    }

    /**
     * Returns the two strings s1, s2 contained in a string
     * of the form " # {s1}{s2} * " where * can be anything
     * and # doesn't contain any curly brackets.
     *
     * @param str the String.
     * @return the Strings.
     */
    protected String[] getTwoCurls(final String str) {
        final String[] st = new String[2];

        int start = str.indexOf('{');
        int stop = str.indexOf('}', start);
        st[0] = str.substring(start + 1, stop);

        final int offset = stop + 1;

        start = str.indexOf('{', offset);
        stop = str.indexOf('}', offset);
        st[1] = str.substring(start + 1, stop);

        return st;
    }

    /**
     * Returns the three strings s1, s2, s3 contained in a string
     * of the form " # {s1}{s2}{s3} * " where * can be anything
     * and # doesn't contain any curly brackets.
     *
     * @param str the String.
     * @return the Strings.
     */
    protected String[] getThreeCurls(final String str) {
        final String[] st = new String[3];

        int start = str.indexOf('{');
        int stop = str.indexOf('}');
        st[0] = str.substring(start + 1, stop);

        int offset = stop + 1;

        start = str.indexOf('{', offset);
        stop = str.indexOf('}', offset);
        st[1] = str.substring(start + 1, stop);

        offset = stop + 1;

        start = str.indexOf('{', offset);
        stop = str.indexOf('}', offset);
        st[2] = str.substring(start + 1, stop);

        return st;
    }

    /**
     * Returns the five strings s1 - s5 contained in a string
     * of the form " # (s1, s2) (s3, s4, s5) * " where * can be anything
     * and # doesn't contain any parenthesis.
     *
     * @param str the String.
     * @return the Strings.
     */
    protected String[] getArcBrackets(final String str) {
        final String[] st = new String[5];

        int start = str.indexOf('(');
        final int comma = str.indexOf(',', start);
        int stop = str.indexOf(')', start);
        st[0] = str.substring(start + 1, comma);
        st[1] = str.substring(comma + 1, stop);

        final int offset = stop + 1;

        start = str.indexOf('(', offset);

        final int comma1 = str.indexOf(',', offset);
        final int comma2 = str.indexOf(',', comma1 + 1);
        stop = str.indexOf(')', offset);
        st[2] = str.substring(start + 1, comma1);
        st[3] = str.substring(comma1 + 1, comma2);
        st[4] = str.substring(comma2 + 1, stop);

        return st;
    }

    private float theDLSeparation(final String str) {
        final int offset = str.indexOf('%') + 1;
        final int start = str.indexOf('(', offset);
        final int stop = str.indexOf(')', offset);

        return Float.parseFloat(str.substring(start + 1, stop));
    }

    private void setDoubleLine(final JaxoObject newOb) {
        if (string.indexOf('%') == -1) {
            newOb.setParameter(DOUBLE_LINE, false);
            newOb.setParameter(DL_SEP, 2.f);
        } else {
            newOb.setParameter(DOUBLE_LINE, true);
            newOb.setParameter(DL_SEP, Math.abs(theDLSeparation(string)));
        }
    }

    private JaxoObject newVertexT4() {
        final int[] firstl = getFourInts(string);
        final int[] secondl = getFourInts(string, string.lastIndexOf(LINE));

        final int[] pars = getT4Params(firstl, secondl);


        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.VERTEXT4);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, pars[2]);
        newOb.setParameter(REL_HEIGHT, pars[3]);
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());

        return newOb;
    }

    private JaxoObject newVertexT2() {
        final int[] pars = getT2Params(getOvalBrackets(string));
        final String[] colors = getTwoCurls(string);

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.VERTEXT2);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, pars[3]);
        newOb.setParameter(REL_HEIGHT, pars[2]);
        newOb.setParameter(COLOR, JaxoColor.getColor(colors[0]));
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(FILL_COLOR, JaxoColor.getColor(colors[1]));

        return newOb;
    }

    private JaxoObject newVertexT2Unfilled() {
        final int[] pars = getT2Params(getOvalBrackets(string));

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.VERTEXT2);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, pars[3]);
        newOb.setParameter(REL_HEIGHT, pars[2]);
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, JaxoColor.getColor("Black"));
        newOb.setParameter(FILL_COLOR, JaxoColor.WHITE);
        newOb.setParameter(FILLED, false);

        return newOb;
    }

    private JaxoObject newVertexT2Gray() {
        final int[] pars = getT2Params(getOvalBrackets(string));

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.VERTEXT2);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, pars[3]);
        newOb.setParameter(REL_HEIGHT, pars[2]);
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, JaxoColor.getColor("Black"));
        newOb.setParameter(FILL_COLOR, JaxoColor.getGrayScaleColor(Float.parseFloat(
                    getOneCurl(string))));

        return newOb;
    }

    private JaxoObject newFLoop(final boolean arcn, final boolean arrow, final boolean atend) {
        JaxoObject newOb = null;

        final String[] st = getArcBrackets(string);

        final int phi1 = Math.round(Float.parseFloat(st[3]));
        final int phi2 = Math.round(Float.parseFloat(st[4]));

        if (Math.abs(phi1 - phi2) >= 360) {
            final int[] pars = getLoopPars(st, string, arcn);

            newOb = JaxoObjectFactory.newObject(JaxoConstants.FLOOP);
            newOb.setParameter("x", pars[0]);
            newOb.setParameter("y", pars[1]);
            newOb.setParameter(REL_WIDTH, pars[2]);
            newOb.setParameter(REL_HEIGHT, pars[3]);
            newOb.setParameter(STROKE_WIDTH, getStroke());
            newOb.setParameter(COLOR, getColor());
            newOb.setParameter(PAINT_ARROW, arrow);
            if (arrow) {
                newOb.setParameter(ARROW_POS, 0.5f);
            }
            newOb.setParameter(FLIP, arcn);
            setDoubleLine(newOb);
        } else {
            final Point2D[] pts = getArcPoints(st, arcn);
            final Point2D p0 = pts[0];
            final Point2D p1 = pts[1];
            final Point2D p2 = pts[2];

            newOb = JaxoObjectFactory.newObject(JaxoConstants.FARC);
            newOb.setParameter("x",  (int) Math.round(p0.getX()));
            newOb.setParameter("y",  (int) Math.round(p0.getY()));
            newOb.setParameter("x2", (int) Math.round(p1.getX()));
            newOb.setParameter("y2", (int) Math.round(p1.getY()));
            newOb.setParameter("x3", (int) Math.round(p2.getX()));
            newOb.setParameter("y3", (int) Math.round(p2.getY()));

            newOb.setParameter(STROKE_WIDTH, getStroke());
            newOb.setParameter(COLOR, getColor());
            newOb.setParameter(PAINT_ARROW, arrow);
            newOb.setParameter(FLIP, false);
            if (atend) {
                newOb.setParameter(ARROW_POS, 1.f);
            } else {
                newOb.setParameter(ARROW_POS, 0.5f);
            }

            setDoubleLine(newOb);
        }

        return newOb;
    }

    private JaxoObject newLine(final boolean arrow, final boolean atend) {
        final int[] pars = getLineParams(getFourInts(string), string);

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.FLINE);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, pars[2]);
        newOb.setParameter(REL_HEIGHT, pars[3]);
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());
        newOb.setParameter(PAINT_ARROW, arrow);
        if (atend) {
            newOb.setParameter(ARROW_POS, 1.f);
        } else {
            newOb.setParameter(ARROW_POS, 0.5f);
        }
        newOb.setParameter(FLIP, false);

        setDoubleLine(newOb);

        return newOb;
    }

    private JaxoObject newCBox() {
        JaxoObject newOb = null;

        if (string.indexOf('%') == -1) {
            final int[] pars = getBoxParams(getFourInts(string));
            final String[] colors = getTwoCurls(string);

            newOb = JaxoObjectFactory.newObject(JaxoConstants.BOX);
            newOb.setParameter("x", pars[0]);
            newOb.setParameter("y", pars[1]);
            newOb.setParameter(REL_WIDTH, pars[2]);
            newOb.setParameter(REL_HEIGHT, pars[3]);
            newOb.setParameter(STROKE_WIDTH, getStroke());
            newOb.setParameter(COLOR, JaxoColor.getColor(colors[0]));
            newOb.setParameter(FILL_COLOR, JaxoColor.getColor(colors[1]));
        } else {
            final int[] pars = getT3Params(getFourInts(string));
            final String[] colors = getTwoCurls(string);

            newOb = JaxoObjectFactory.newObject(JaxoConstants.VERTEXT3);
            newOb.setParameter("x", pars[0]);
            newOb.setParameter("y", pars[1]);
            newOb.setParameter(REL_WIDTH, pars[2]);
            newOb.setParameter(REL_HEIGHT, pars[3]);
            newOb.setParameter(COLOR, JaxoColor.getColor(colors[0]));
        }

        return newOb;
    }

    private JaxoObject newCCirc() {
        final String[] radcol = getThreeCurls(string);
        final int[] pars = getCircParams(getTwoInts(string), radcol[0]);

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.BLOB);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, pars[2]);
        newOb.setParameter(REL_HEIGHT, pars[2]);
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(ROT_ANGLE, 0);
        newOb.setParameter(COLOR, JaxoColor.getColor(radcol[1]));
        newOb.setParameter(FILL_COLOR, JaxoColor.getColor(radcol[2]));

        return newOb;
    }

    private JaxoObject newCOval() {
        final int[] pars = getBlobParams(getOvalBrackets(string));
        final String[] colors = getTwoCurls(string);

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.BLOB);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, pars[3]);
        newOb.setParameter(REL_HEIGHT, pars[2]);
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(ROT_ANGLE, -pars[4]);
        newOb.setParameter(COLOR, JaxoColor.getColor(colors[0]));
        newOb.setParameter(FILL_COLOR, JaxoColor.getColor(colors[1]));

        return newOb;
    }

    private JaxoObject newCTri() {
        final String[] colors = getTwoCurls(string);

        final int[] pars = getTriangleParameters(getSixInts(string));

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.VERTEXT5);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter("x2", pars[2]);
        newOb.setParameter("y2", pars[3]);
        newOb.setParameter("x3", pars[4]);
        newOb.setParameter("y3", pars[5]);

        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, JaxoColor.getColor(colors[0]));
        newOb.setParameter(FILL_COLOR, JaxoColor.getColor(colors[1]));

        return newOb;
    }

    private JaxoObject newDashArc(final boolean arcn, final boolean arrow) {
        final String[] st = getArcBrackets(string);
        float dash = Float.parseFloat(getOneCurl(string)) * getScaleFactor();
        JaxoObject newOb = null;

        if (!arrow && !(string.indexOf('%') == -1)) {
            final float r = Float.parseFloat(st[2]);
            dash =
                (float) Math.round((dash * r) / (r + theDLSeparation(string)));
        }

        final int phi1 = Math.round(Float.parseFloat(st[3]));
        final int phi2 = Math.round(Float.parseFloat(st[4]));

        if (Math.abs(phi1 - phi2) >= 360) {
            final int[] pars = getLoopPars(st, string, arcn);

            if (dash > 5.f) {
                newOb = JaxoObjectFactory.newObject(JaxoConstants.SLOOP);
            } else {
                newOb = JaxoObjectFactory.newObject(JaxoConstants.GLOOP);
            }

            newOb.setParameter("x", pars[0]);
            newOb.setParameter("y", pars[1]);
            newOb.setParameter(REL_WIDTH, pars[2]);
            newOb.setParameter(REL_HEIGHT, pars[3]);
            newOb.setParameter(STROKE_WIDTH, getStroke());
            newOb.setParameter(COLOR, getColor());
            newOb.setParameter(PAINT_ARROW, arrow);
            if (arrow) {
                newOb.setParameter(ARROW_POS, 0.5f);
            }
            newOb.setParameter(FLIP, arcn);
            newOb.setParameter(DASH, dash);

            setDoubleLine(newOb);
        } else {
            final Point2D[] pts = getArcPoints(st, arcn);
            final Point2D p0 = pts[0];
            final Point2D p1 = pts[1];
            final Point2D p2 = pts[2];

            if (dash > 5.f) {
                newOb = JaxoObjectFactory.newObject(JaxoConstants.SARC);
            } else {
                newOb = JaxoObjectFactory.newObject(JaxoConstants.GARC);
            }

            newOb.setParameter("x", (int) Math.round(p0.getX()));
            newOb.setParameter("y", (int) Math.round(p0.getY()));
            newOb.setParameter("x2", (int) Math.round(p1.getX()));
            newOb.setParameter("y2", (int) Math.round(p1.getY()));
            newOb.setParameter("x3", (int) Math.round(p2.getX()));
            newOb.setParameter("y3", (int) Math.round(p2.getY()));

            newOb.setParameter(STROKE_WIDTH, getStroke());
            newOb.setParameter(COLOR, getColor());
            newOb.setParameter(PAINT_ARROW, arrow);
            if (arrow) {
                newOb.setParameter(ARROW_POS, 0.5f);
            }
            newOb.setParameter(FLIP, arcn);
            newOb.setParameter(DASH, dash);

            setDoubleLine(newOb);
        }

        return newOb;
    }

    private JaxoObject newDashLine(final boolean arrow) {
        final int[] pars = getLineParams(getFourInts(string), string);
        final float dash = Float.parseFloat(getOneCurl(string)) * getScaleFactor();
        JaxoObject newOb = null;

        if (dash > 5.f) {
            newOb = JaxoObjectFactory.newObject(JaxoConstants.SLINE);
        } else {
            newOb = JaxoObjectFactory.newObject(JaxoConstants.GLINE);
        }

        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, pars[2]);
        newOb.setParameter(REL_HEIGHT, pars[3]);
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());
        newOb.setParameter(PAINT_ARROW, arrow);
        if (arrow) {
            newOb.setParameter(ARROW_POS, 0.5f);
        }
        newOb.setParameter(FLIP, false);
        newOb.setParameter(DASH, dash);

        setDoubleLine(newOb);

        return newOb;
    }

    private JaxoObject newGBox() {
        final int[] pars = getBoxParams(getFourInts(string));

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.BOX);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, pars[2]);
        newOb.setParameter(REL_HEIGHT, pars[3]);
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());
        newOb.setParameter(FILL_COLOR, JaxoColor.getGrayScaleColor(Float.parseFloat(
                    getOneCurl(string))));

        return newOb;
    }

    private JaxoObject newEBox() {
        final int[] pars = getBoxParams(getFourInts(string));

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.BOX);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, pars[2]);
        newOb.setParameter(REL_HEIGHT, pars[3]);
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());
        newOb.setParameter(FILL_COLOR, JaxoColor.WHITE);
        newOb.setParameter(FILLED, false);

        return newOb;
    }

    private JaxoObject newGCirc() {
        final String[] radcol = getTwoCurls(string);
        final int[] pars = getCircParams(getTwoInts(string), radcol[0]);

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.BLOB);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, pars[2]);
        newOb.setParameter(REL_HEIGHT, pars[2]);
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(ROT_ANGLE, 0);
        newOb.setParameter(COLOR, getColor());
        newOb.setParameter(FILL_COLOR, JaxoColor.getGrayScaleColor(Float.parseFloat(
                    radcol[1])));

        return newOb;
    }

    private JaxoObject newGlArc() {
        JaxoObject newOb = null;

        final String[] st = getArcBrackets(string);
        final String[] ampwig = getTwoCurls(string);

        final int phi1 = Math.round(Float.parseFloat(st[3]));
        final int phi2 = Math.round(Float.parseFloat(st[4]));

        if (Math.abs(phi1 - phi2) >= 360) {
            final int[] pars = getLoopPars(st, string, false);

            newOb = JaxoObjectFactory.newObject(JaxoConstants.GLLOOP);
            newOb.setParameter("x", pars[0]);
            newOb.setParameter("y", pars[1]);
            newOb.setParameter(REL_WIDTH, -pars[2]);
            newOb.setParameter(REL_HEIGHT, -pars[3]);
            newOb.setParameter(STROKE_WIDTH, getStroke());
            newOb.setParameter(COLOR, getColor());

            newOb.setParameter(AMP, Math.round(
                        Float.parseFloat(ampwig[0]) * 2 * getScaleFactor()));

            final float nOfWiggles = Float.parseFloat(ampwig[1]) * getScaleFactor();

            newOb.setParameter(FREQ_FROM_WIGGLES, Math.round(nOfWiggles));

            setDoubleLine(newOb);
        } else {
            final Point2D[] pts = getArcPoints(st, false);
            final Point2D p0 = pts[0];
            final Point2D p1 = pts[1];
            final Point2D p2 = pts[2];

            newOb = JaxoObjectFactory.newObject(JaxoConstants.GLARC);
            newOb.setParameter("x", (int) Math.round(p0.getX()));
            newOb.setParameter("y", (int) Math.round(p0.getY()));
            newOb.setParameter("x2", (int) Math.round(p1.getX()));
            newOb.setParameter("y2", (int) Math.round(p1.getY()));
            newOb.setParameter("x3", (int) Math.round(p2.getX()));
            newOb.setParameter("y3", (int) Math.round(p2.getY()));

            newOb.setParameter(STROKE_WIDTH, getStroke());
            newOb.setParameter(COLOR, getColor());
            newOb.setParameter(AMP, -Math.round(
                    Float.parseFloat(ampwig[0]) * 2 * getScaleFactor()));

            final float nOfWiggles = Float.parseFloat(ampwig[1]) * getScaleFactor();

            newOb.setParameter(FREQ_FROM_WIGGLES, Math.round(nOfWiggles));

            setDoubleLine(newOb);
        }

        return newOb;
    }

    private JaxoObject newGlLine() {
        final int[] pars = getLineParams(getFourInts(string), string);
        final String[] ampwig = getTwoCurls(string);

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.GLLINE);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, pars[2]);
        newOb.setParameter(REL_HEIGHT, pars[3]);
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());

        newOb.setParameter(AMP, Math.round(
                Float.parseFloat(ampwig[0]) * 2 * getScaleFactor()));

        final float nOfWiggles = Float.parseFloat(ampwig[1]) * getScaleFactor();
        newOb.setParameter(FREQ_FROM_WIGGLES, Math.round(nOfWiggles));

        setDoubleLine(newOb);

        return newOb;
    }

    private JaxoObject newOval() {
        final int[] pars = getBlobParams(getOvalBrackets(string));

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.BLOB);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, pars[3]);
        newOb.setParameter(REL_HEIGHT, pars[2]);
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(ROT_ANGLE, -pars[4]);
        newOb.setParameter(COLOR, getColor());
        newOb.setParameter(FILL_COLOR, JaxoColor.WHITE);
        newOb.setParameter(FILLED, false);

        return newOb;
    }

    private JaxoObject newGOval() {
        final int[] pars = getBlobParams(getOvalBrackets(string));

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.BLOB);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, pars[3]);
        newOb.setParameter(REL_HEIGHT, pars[2]);
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(ROT_ANGLE, -pars[4]);
        newOb.setParameter(COLOR, getColor());
        newOb.setParameter(FILL_COLOR, JaxoColor.getGrayScaleColor(Float.parseFloat(
                    getOneCurl(string))));

        return newOb;
    }

    private JaxoObject newGTri() {
        final int[] pars = getTriangleParameters(getSixInts(string));

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.VERTEXT5);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter("x2", pars[2]);
        newOb.setParameter("y2", pars[3]);
        newOb.setParameter("x3", pars[4]);
        newOb.setParameter("y3", pars[5]);

        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());
        newOb.setParameter(FILL_COLOR, JaxoColor.getGrayScaleColor(Float.parseFloat(
                    getOneCurl(string))));

        return newOb;
    }

    private JaxoObject newETri() {
        final int[] pars = getTriangleParameters(getSixInts(string));

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.VERTEXT5);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter("x2", pars[2]);
        newOb.setParameter("y2", pars[3]);
        newOb.setParameter("x3", pars[4]);
        newOb.setParameter("y3", pars[5]);

        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());
        newOb.setParameter(FILL_COLOR, JaxoColor.WHITE);
        newOb.setParameter(FILLED, false);

        return newOb;
    }

    private JaxoObject newPArc() {
        JaxoObject newOb = null;

        final String[] st = getArcBrackets(string);
        final String[] ampwig = getTwoCurls(string);

        final int phi1 = Math.round(Float.parseFloat(st[3]));
        final int phi2 = Math.round(Float.parseFloat(st[4]));

        if (Math.abs(phi1 - phi2) >= 360) {
            final int[] pars = getLoopPars(st, string, false);

            newOb = JaxoObjectFactory.newObject(JaxoConstants.PLOOP);
            newOb.setParameter("x", pars[0]);
            newOb.setParameter("y", pars[1]);
            newOb.setParameter(REL_WIDTH, -pars[2]);
            newOb.setParameter(REL_HEIGHT, -pars[3]);
            newOb.setParameter(STROKE_WIDTH, getStroke());
            newOb.setParameter(COLOR, getColor());

            newOb.setParameter(AMP, Math.round(
                        Float.parseFloat(ampwig[0]) * 2 * getScaleFactor()));

            final float nOfWiggles = Float.parseFloat(ampwig[1]); // * scaleFactor;

            newOb.setParameter(FREQ_FROM_WIGGLES, Math.round(nOfWiggles));
            setDoubleLine(newOb);
        } else {
            final Point2D[] pts = getArcPoints(st, false);
            final Point2D p0 = pts[0];
            final Point2D p1 = pts[1];
            final Point2D p2 = pts[2];

            newOb = JaxoObjectFactory.newObject(JaxoConstants.PARC);
            newOb.setParameter("x", (int) Math.round(p0.getX()));
            newOb.setParameter("y", (int) Math.round(p0.getY()));
            newOb.setParameter("x2", (int) Math.round(p1.getX()));
            newOb.setParameter("y2", (int) Math.round(p1.getY()));
            newOb.setParameter("x3", (int) Math.round(p2.getX()));
            newOb.setParameter("y3", (int) Math.round(p2.getY()));

            newOb.setParameter(STROKE_WIDTH, getStroke());
            newOb.setParameter(COLOR, getColor());
            newOb.setParameter(AMP, Math.round(
                    Float.parseFloat(ampwig[0]) * 2 * getScaleFactor()));

            final float nOfWiggles = Float.parseFloat(ampwig[1]);
            final boolean symmetric = (Math.round(nOfWiggles) - nOfWiggles) > 0.001;

            newOb.setParameter("symmetric", symmetric);
            newOb.setParameter(FREQ_FROM_WIGGLES, (int) Math.floor(nOfWiggles));

            setDoubleLine(newOb);
        }

        return newOb;
    }

    protected JaxoObject newPLine() {
        final int[] pars = getLineParams(getFourInts(string), string);
        final String[] ampwig = getTwoCurls(string);

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.PLINE);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, pars[2]);
        newOb.setParameter(REL_HEIGHT, pars[3]);
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());

        newOb.setParameter(AMP, Math.round(
                Float.parseFloat(ampwig[0]) * 2 * getScaleFactor()));

        final float nOfWiggles = Float.parseFloat(ampwig[1]);
        final boolean symmetric = (Math.round(nOfWiggles) - nOfWiggles) > 0.001;

        newOb.setParameter("symmetric", symmetric);
        newOb.setParameter(FREQ_FROM_WIGGLES, (int) Math.floor(nOfWiggles));

        setDoubleLine(newOb);

        return newOb;
    }

    private JaxoObject newText() {
        final int[] pos = getT1Params(getOneBracket(string));
        final int allign = getTeXAllign(getOneBrace(string));
        final int size = getTeXSize(getOneCurl(string));
        int rotangle = 0;
        String text = getTeXText(string);

        if (text.indexOf("\\rput", 0) == 0) {
            rotangle = -getTexRotangle(text); // pstricks counts angles counter-clockwise
            text = getRotatedTexText(text, string);
        }

        final Color txtcolor = getTeXColor(getOneCurl(string));

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.LATEX);
        newOb.setParameter("x", pos[0]);
        newOb.setParameter("y", pos[1]);
        newOb.setParameter(COLOR, txtcolor);
        newOb.setParameter("textString", text);
        newOb.setParameter("allign", allign);
        newOb.setParameter("latexTextSize", size);
        newOb.setParameter(ROT_ANGLE, rotangle);

        return newOb;
    }

    private JaxoObject newVertexT1() {
        final int[] center = getT1Params(getOneBracket(string));
        final String radius = getOneCurl(string);
        final int relwh = (int) Math.round(
                (Float.parseFloat(radius) * getScaleFactor()) / Math.sqrt(2));

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.VERTEXT1);
        newOb.setParameter("x", center[0]);
        newOb.setParameter("y", center[1]);
        newOb.setParameter(REL_WIDTH, relwh);
        newOb.setParameter(REL_HEIGHT, relwh);
        newOb.setParameter(COLOR, getColor());

        return newOb;
    }

    private JaxoObject newVertexT6() {
        final int[] pars = getTriangleParameters(getSixInts(string));
        final String[] colors = getTwoCurls(string);
        final double length = (pars[4] - pars[0]) / 2.d;

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.VERTEXT6);
        newOb.setParameter("x", (int) Math.round(pars[0] + length));
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, (int) Math.round(length * 0.5d));
        newOb.setParameter(REL_HEIGHT, (int) Math.round(length * 0.5d));
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, JaxoColor.getColor(colors[0]));

        return newOb;
    }

    private JaxoObject newZigZagLine() {
        final int[] pars = getLineParams(getFourInts(string), string);
        final String[] ampwig = getTwoCurls(string);

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.ZIGZAG);
        newOb.setParameter("x", pars[0]);
        newOb.setParameter("y", pars[1]);
        newOb.setParameter(REL_WIDTH, pars[2]);
        newOb.setParameter(REL_HEIGHT, pars[3]);
        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());

        newOb.setParameter(AMP, Math.round(
                Float.parseFloat(ampwig[0]) * 2 * getScaleFactor()));

        final float nOfWiggles = Float.parseFloat(ampwig[1]);
        final boolean symmetric = (Math.round(nOfWiggles) - nOfWiggles) > 0.001;

        newOb.setParameter("symmetric", symmetric);
        newOb.setParameter(FREQ_FROM_WIGGLES, (int) Math.floor(nOfWiggles));

        setDoubleLine(newOb);

        return newOb;
    }

    /**
     * Return the current color.
     *
     * @return The current color.
     */
    protected Color getColor() {
        return color;
    }

    /**
     * Return the current stroke (line width).
     *
     * @return The current stroke.
     */
    protected float getStroke() {
        return stroke;
    }

    /**
     * Return the current bounding box height.
     *
     * @return The current bounding box height.
     */
    protected float getBBoxHeight() {
        return bBoxHeight;
    }
}
