/**
 *  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.geom.Point2D;

import net.sf.jaxodraw.object.arrow.JaxoDefaultArrow;
import net.sf.jaxodraw.object.JaxoObject;
import net.sf.jaxodraw.object.arrow.JaxoArrow;
import net.sf.jaxodraw.object.JaxoObjectFactory;
import net.sf.jaxodraw.util.JaxoConstants;
import net.sf.jaxodraw.util.JaxoPrefs;


/**
 * Extension to JaxoAxodraw that adds Bezier imports.
 *
 * @since 2.0
 */
public class JaxoAxodraw4J extends JaxoAxodraw {
    private static final String[] KNOWN_COMMANDS =
    {
        "\\Bezier", "\\DashBezier", LINE, "\\Arc", "\\PhotonArc",
        "\\Photon", "\\GluonArc", "\\GlueArc", "\\Gluon"
    };
    private static final int N_OF_COMMANDS = KNOWN_COMMANDS.length;
    private String string = "";
    private int index;

    /** Constructor: just calls super(). */
    public JaxoAxodraw4J() {
        super();
        removePackage("axodraw");
        addPackage("axodraw4j");
    }

    /**
     * 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
     */
    @Override
    public JaxoObject getJaxoObject(final String newString) {
        this.string = newString;

        JaxoObject newob = null;

        // first check if it's a new axodraw4j command
        final boolean valid = validJaxo4JCommand(string);

        if (valid) {
            if (index == -10) { // Fermionic Bezier
                newob = newFBezier();
            } else if (index == -9) { // Scalar Bezier
                newob = newSBezier();
            } else if (index == -8) { // Ghost Bezier
                newob = newGBezier();
            } else if (index == -7) { // Photon Bezier
                newob = newPBezier();
            } else if (index == -6) { // Gluon Bezier
                newob = newGlBezier();
            } else if (index == -5) { // Fermion/Scalar/Ghost Lines
                newob = newA4JLine();
            } else if (index == -4) { // Fermion/Scalar/Ghost Arcs/Loops
                newob = newA4JArc();
            } else if (index == -3) { // Photon line (for double option)
                newob = newA4JPLine();
            } else if (index == -2) { // Gluon Line (for double option)
                newob = newA4JGlLine();
            } else if (index == -1) { // Photon Arcs/Loops (for double option)
                newob = newA4JPArc();
            } else if (index == 0) { // Gluon Arcs/Loops (for double option)
                newob = newA4JGlArc();
            } else if (index == 1) {
                newob = newVertexT4();
            }
        } else {
            // then check if it's an old axodraw command
            newob = super.getJaxoObject(newString);
        }

        return newob;
    }

    private boolean validJaxo4JCommand(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;

        if (i == getIndex("\\Bezier")) {
            if (s.indexOf("%JaxoID:FBez") > 0) {
                this.index = -10;
            } else if (s.indexOf("%JaxoID:PBez") > 0) {
                this.index = -7;
            } else if (s.indexOf("%JaxoID:GlBez") > 0) {
                this.index = -6;
            } else if (s.indexOf("%JaxoID:SBez") > 0) {
                this.index = -9;
            } else if (s.indexOf("%JaxoID:GBez") > 0) {
                this.index = -8;
            }
        } else if (i == getIndex("\\DashBezier")) {
            if (s.indexOf("%JaxoID:SBez") > 0) {
                this.index = -9;
            } else if (s.indexOf("%JaxoID:GBez") > 0) {
                this.index = -8;
            }
        } else if (i == getIndex(LINE)) {
           // Need to check here for the cross vertex otherwise it will be broken
            if ((s.indexOf(LINE, 6) > 0) && (s.indexOf('%') == -1)) {
                this.index = +1;
            } else {
                this.index = -5;
            }
        } else if (i == getIndex("\\Arc")) {
            this.index = -4;
        } else if (i == getIndex("\\Photon")) {
            this.index = -3;
        } else if (i == getIndex("\\Gluon")) {
            this.index = -2;
        } else if (i == getIndex("\\PhotonArc")) {
            this.index = -1;
        } else if (i == getIndex("\\GluonArc") || i == getIndex("\\GlueArc")) {
            this.index = 0;
        }

        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;
        }
    }

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

    /**
     * Returns the eight integers x1, y1,x2,y2,x3,y3,x4,y4 contained in a string
     * of the form " # (x1, y1) (x2,y2) (x3,y3) (x4,y4) * " where * can be anything
     * and # doesn't contain any parenthesis.
     *
     * @param str the String.
     * @param fromIndex the index to start with.
     * @return the eight ints.
     */
    protected int[] getEightInts(final String str, final int fromIndex) {
        final int[] ints = new int[8];

        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)));

        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)));

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

        return ints;
    }

    private int[] getBezierParams(final int[] coords) {
        int[] out = {0, 0, 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()));
        out[6] = Math.round(coords[6] * getScaleFactor());
        out[7] = Math.round(getBBoxHeight() - (coords[7] * getScaleFactor()));

        return out;
    }

    private String[] getOptions(final String str) {

        int start = str.indexOf('[');

        if (start == -1) {
            return new String[] {};
        }

        //A maximum of 12 options can be currently set by JD
        final String[] options = new String[20];

        final int stop = str.indexOf(']');
        int cindex = str.indexOf(',', start);
        int optnumb = 0;

        while (cindex < stop) {
            options[optnumb] = str.substring(start + 1, cindex);
            start = cindex;
            cindex = str.indexOf(',', start + 1);
            optnumb++;
        }

        options[optnumb] = str.substring(start + 1, stop);

        final String[] result = new String[optnumb + 1];
        System.arraycopy(options, 0, result, 0, optnumb + 1);

        return result;
    }

    private boolean isArrow(final String[] options) {
        boolean itis = false;
        for (int i = 0; i < options.length; i++) {
            if (options[i].equals("arrow")) {
                itis = true;
            }
        }

        return itis;
    }

    private boolean isDouble(final String[] options) {
        boolean itis = false;
        for (int i = 0; i < options.length; i++) {
            if (options[i].equals("double")) {
                itis = true;
            }
        }

        return itis;
    }

    private static boolean contains(final String string, final String token) {
        return (string.indexOf(token) != -1);
    }

    private float[] getArrowParameters(final String[] options) {
        // position/length/width/inset/scale/flip
        final float[] arrowParameters = {-1, -1, -1, -1, 1, 0};

        final float[] defaults = get4jArrowDefaults(options);

        for (int i = 0; i < options.length; i++) {
            final int start = options[i].indexOf('=');
            final int stop = options[i].length();

            if (contains(options[i], "arrowpos")) {
                arrowParameters[0] = Float.parseFloat(options[i].
                        substring(start + 1, stop));
            } else if (contains(options[i], "arrowlength")) {
                arrowParameters[1] = Float.parseFloat(options[i].
                        substring(start + 1, stop));
            } else if (contains(options[i], "arrowwidth")) {
                arrowParameters[2] = Float.parseFloat(options[i].
                        substring(start + 1, stop));
            } else if (contains(options[i], "arrowinset")) {
                arrowParameters[3] = Float.parseFloat(options[i].
                        substring(start + 1, stop));
            }  else if (contains(options[i], "arrowscale")) {
                arrowParameters[4] = Float.parseFloat(options[i].
                        substring(start + 1, stop));
            } else if (contains(options[i], "flip")) {
                arrowParameters[5] = 1;
            }
        }

        // preserve default ratio if only one of width/length is given

        if (arrowParameters[1] == -1 && arrowParameters[2] != -1) {
                arrowParameters[1] = 2.5f * arrowParameters[2];
        }

        if (arrowParameters[2] == -1 && arrowParameters[1] != -1) {
                arrowParameters[2] = arrowParameters[1] / 2.5f;
        }

        for (int j = 0; j < arrowParameters.length - 1; j++) {
            if (arrowParameters[j] == -1) {
                arrowParameters[j] = defaults[j];
            }

            if (arrowParameters[4] != 1) {
                arrowParameters[j] = arrowParameters[j] * arrowParameters[4];
            }
        }

        return arrowParameters;
    }

    private float getDashParameter(final String[] options) {
        float dashSize = 0;

        for (int i = 0; i < options.length; i++) {
            final int start = options[i].indexOf('=');
            final int stop = options[i].length();

            if (contains(options[i], "dashsize") || contains(options[i], "dsize")) {
                dashSize = Float.parseFloat(options[i].
                        substring(start + 1, stop));
            }
        }

        return dashSize;
    }

    private float getDoubleLineParameter(final String[] options) {
        float dlSeparation = -1;

        for (int i = 0; i < options.length; i++) {
            final int start = options[i].indexOf('=');
            final int stop = options[i].length();

            if (contains(options[i], "sep")) {
                dlSeparation = Float.parseFloat(options[i].
                        substring(start + 1, stop));
            }
        }

        if (dlSeparation == -1) {
            dlSeparation = JaxoPrefs.getFloatPref(JaxoPrefs.PREF_DLSEP);
        }

        return dlSeparation;
    }

    private boolean getClockwiseParameter(final String[] options) {
        boolean isClock = false;

        for (int i = 0; i < options.length; i++) {
            if (contains(options[i], "clock")) {
                isClock = true;
            }
        }

        return isClock;
    }

    private JaxoObject newFBezier() {
        final int[] pars = getBezierParams(getEightInts(string));

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.FBEZ);
        setBezierPoints(newOb, pars);

        if (string.indexOf('[') > 0) {
            setArrow(getOptions(string), newOb);
        } else {
            newOb.setParameter(PAINT_ARROW, false);
        }

        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());

        return newOb;
    }

    private JaxoObject newSBezier() {
        final int[] pars = getBezierParams(getEightInts(string));
        float dash;
        try {
            dash = Float.parseFloat(getOneCurl(string)) * getScaleFactor();
        } catch (StringIndexOutOfBoundsException e) {
            dash = getDashParameter(getOptions(string)) * getScaleFactor();
        }


        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.SBEZ);
        setBezierPoints(newOb, pars);

        final int arrowPos = string.indexOf(LINE);
        if (arrowPos > 0) {
            setArrow(getOptions(string.substring(arrowPos)), newOb);
        } else {
            newOb.setParameter(PAINT_ARROW, false);
        }

        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());
        newOb.setParameter(DASH, dash);

        return newOb;
    }

    private JaxoObject newGBezier() {
        final int[] pars = getBezierParams(getEightInts(string));
        float dash;
        try {
            dash = Float.parseFloat(getOneCurl(string)) * getScaleFactor();
        } catch (StringIndexOutOfBoundsException e) {
            dash = getDashParameter(getOptions(string)) * getScaleFactor();
        }

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.GBEZ);
        setBezierPoints(newOb, pars);

        final int arrowPos = string.indexOf(LINE);
        if (arrowPos > 0) {
            setArrow(getOptions(string.substring(arrowPos)), newOb);
        } else {
            newOb.setParameter(PAINT_ARROW, false);
        }

        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());
        newOb.setParameter(DASH, dash);

        return newOb;
    }

    private JaxoObject newPBezier() {
        final int[] pars = getEightInts(string, string.indexOf('%'));
        final String[] ampwig = getTwoCurls(string);
        final String redshift = getOneBrace(string);

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.PBEZ);
        setBezierPoints(newOb, pars);

        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());
        newOb.setParameter(AMP, Math.round(Float.parseFloat(ampwig[0])));
        newOb.setParameter("noFreqStretching", Boolean.parseBoolean(redshift));
        newOb.setParameter(FREQ_FROM_WIGGLES, Math.round(Float.parseFloat(ampwig[1])));

        return newOb;
    }

    private JaxoObject newGlBezier() {
        final int[] pars = getEightInts(string, string.indexOf('%'));
        final String[] ampwig = getTwoCurls(string);
        final String redshift = getOneBrace(string);

        final JaxoObject newOb = JaxoObjectFactory.newObject(JaxoConstants.GLBEZ);
        setBezierPoints(newOb, pars);

        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());
        newOb.setParameter(AMP, Math.round(Float.parseFloat(ampwig[0])));
        newOb.setParameter("noFreqStretching", Boolean.parseBoolean(redshift));
        newOb.setParameter(FREQ_FROM_WIGGLES, Math.round(Float.parseFloat(ampwig[1])));

        return newOb;
    }

    private JaxoObject newA4JLine() {

        final String[] options = getOptions(string);

        final boolean isarr = isArrow(options);
        final boolean isdoub = isDouble(options);
        final float dsize = getDashParameter(options) * getScaleFactor();

        final int[] pars = getLineParams(getFourInts(string), string);

        JaxoObject newOb = null;
        if (dsize == 0) {
            newOb = JaxoObjectFactory.newObject(JaxoConstants.FLINE);
        } else {
            if (dsize > 5.f) {
                newOb = JaxoObjectFactory.newObject(JaxoConstants.SLINE);
            } else {
                newOb = JaxoObjectFactory.newObject(JaxoConstants.GLINE);
            }

            newOb.setParameter(DASH, dsize);
        }

        if (isarr) {
            setArrow(options, newOb);
        } else {
            newOb.setParameter(PAINT_ARROW, false);
        }

        if (isdoub) {
            final float dlsep = getDoubleLineParameter(options) * getScaleFactor();
            newOb.setParameter(DOUBLE_LINE, true);
            newOb.setParameter(DL_SEP, dlsep);
        } else {
            newOb.setParameter(DOUBLE_LINE, false);
            newOb.setParameter(DL_SEP,
                JaxoPrefs.getFloatPref(JaxoPrefs.PREF_DLSEP));
        }

        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 newA4JArc() {

        final String[] options = getOptions(string);

        final boolean isarr = isArrow(options);
        final boolean isdoub = isDouble(options);
        final float dsize = getDashParameter(options) * getScaleFactor();
        final boolean clock = getClockwiseParameter(options);

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

        JaxoObject newOb = null;

        if (Math.abs(phi1 - phi2) >= 360) {
            //This is a loop

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

                newOb.setParameter(DASH, dsize);
            }

            final int[] pars = getLoopPars(st, string, clock);

            newOb.setParameter("x", pars[0]);
            newOb.setParameter("y", pars[1]);
            newOb.setParameter(REL_WIDTH, pars[2]);
            newOb.setParameter(REL_HEIGHT, pars[3]);

        } else {
        //This is a genuine arc
            if (dsize == 0) {
                newOb = JaxoObjectFactory.newObject(JaxoConstants.FARC);
            } else {
                if (dsize > 5.f) {
                    newOb = JaxoObjectFactory.newObject(JaxoConstants.SARC);
                } else {
                    newOb = JaxoObjectFactory.newObject(JaxoConstants.GARC);
                }

                newOb.setParameter(DASH, dsize);
            }

            setArcPoints(st, clock, newOb);
        }

        //Common to loops and arcs

        if (isarr) {
            setArrow(options, newOb);
        } else {
            newOb.setParameter(PAINT_ARROW, false);
        }

        if (isdoub) {
            final float dlsep = getDoubleLineParameter(options) * getScaleFactor();
            newOb.setParameter(DOUBLE_LINE, true);
            newOb.setParameter(DL_SEP, dlsep);
        } else {
            newOb.setParameter(DOUBLE_LINE, false);
            newOb.setParameter(DL_SEP,
                JaxoPrefs.getFloatPref(JaxoPrefs.PREF_DLSEP));
        }

        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());

        return newOb;
    }

    private JaxoObject newA4JPLine() {

        final String[] options = getOptions(string);

        final boolean isdoub = isDouble(options);

        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));

        if (isdoub) {
            final float dlsep = getDoubleLineParameter(options) * getScaleFactor();
            newOb.setParameter(DOUBLE_LINE, true);
            newOb.setParameter(DL_SEP, dlsep);
        } else {
            newOb.setParameter(DOUBLE_LINE, false);
            newOb.setParameter(DL_SEP,
                JaxoPrefs.getFloatPref(JaxoPrefs.PREF_DLSEP));
        }

        return newOb;
    }

    private JaxoObject newA4JGlLine() {

        final String[] options = getOptions(string);
        final boolean isdoub = isDouble(options);

        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));

        if (isdoub) {
            final float dlsep = getDoubleLineParameter(options) * getScaleFactor();
            newOb.setParameter(DOUBLE_LINE, true);
            newOb.setParameter(DL_SEP, dlsep);
        } else {
            newOb.setParameter(DOUBLE_LINE, false);
            newOb.setParameter(DL_SEP,
                JaxoPrefs.getFloatPref(JaxoPrefs.PREF_DLSEP));
        }

        return newOb;
    }

    private JaxoObject newA4JPArc() {

        final String[] options = getOptions(string);
        final boolean isdoub = isDouble(options);
        final boolean clock = getClockwiseParameter(options);

        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) {
            // this is a loop

            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]);

        } else {
            // this is a genuine arc

            newOb = JaxoObjectFactory.newObject(JaxoConstants.PARC);
            setArcPoints(st, clock, newOb);

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

            newOb.setParameter("symmetric", symmetric);
        }

        // Common to both loops and arcs

        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());

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

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

        if ((Math.round(nOfWiggles) - nOfWiggles) > 0.001) { //symmetric arc
            nOfWiggles = nOfWiggles - 0.5f;
        }

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

        if (isdoub) {
            final float dlsep = getDoubleLineParameter(options) * getScaleFactor();
            newOb.setParameter(DOUBLE_LINE, true);
            newOb.setParameter(DL_SEP, dlsep);
        } else {
            newOb.setParameter(DOUBLE_LINE, false);
            newOb.setParameter(DL_SEP,
                JaxoPrefs.getFloatPref(JaxoPrefs.PREF_DLSEP));
        }

        return newOb;
    }

    private JaxoObject newA4JGlArc() {

        final String[] options = getOptions(string);
        final boolean isdoub = isDouble(options);
        final boolean clock = getClockwiseParameter(options);

        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) {
            //this is a loop

            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(AMP, Math.round(
                Float.parseFloat(ampwig[0]) * 2 * getScaleFactor()));

        } else {
            //this is a genuine arc

            newOb = JaxoObjectFactory.newObject(JaxoConstants.GLARC);
            setArcPoints(st, clock, newOb);

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

        //common to both arcs and loops

        newOb.setParameter(STROKE_WIDTH, getStroke());
        newOb.setParameter(COLOR, getColor());

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

        if (isdoub) {
            final float dlsep = getDoubleLineParameter(options) * getScaleFactor();
            newOb.setParameter(DOUBLE_LINE, true);
            newOb.setParameter(DL_SEP, dlsep);
        } else {
            newOb.setParameter(DOUBLE_LINE, false);
            newOb.setParameter(DL_SEP,
                JaxoPrefs.getFloatPref(JaxoPrefs.PREF_DLSEP));
        }

        return newOb;
    }

    private JaxoObject newVertexT4() { // same as in JaxoAxodraw
        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 float[] get4jArrowDefaults(final String[] options) {
        final float[] defaults = {0, 0, 0, 0, 1, 0};
        // position/length/width/inset/scale/flip
        float dlsep = 0;
        if (isDouble(options)) {
            dlsep = getDoubleLineParameter(options);
        }

        defaults[0] = 0.5f; // position
        defaults[2] = 1.2f * (2 + 0.7f * dlsep + getStroke()); // width
        defaults[1] = 2.5f * defaults[2]; // length
        defaults[3] = 0.2f; // inset
        defaults[4] = 1; // scale
        defaults[5] = 0; // flip

        return defaults;
    }

    private void setArcPoints(final String[] st, final boolean clock, final JaxoObject newOb) {
        final Point2D[] pts = getArcPoints(st, clock);
        newOb.setParameter("x", (int) Math.round(pts[0].getX()));
        newOb.setParameter("y", (int) Math.round(pts[0].getY()));
        newOb.setParameter("x2", (int) Math.round(pts[1].getX()));
        newOb.setParameter("y2", (int) Math.round(pts[1].getY()));
        newOb.setParameter("x3", (int) Math.round(pts[2].getX()));
        newOb.setParameter("y3", (int) Math.round(pts[2].getY()));
    }

    private void setArrow(final String[] options, final JaxoObject newOb) {
        final float[] arrowParameters = getArrowParameters(options);
        final JaxoDefaultArrow arrow = new JaxoDefaultArrow();
        arrow.setArrowLength(arrowParameters[1]);
        arrow.setArrowWidth(arrowParameters[2]);
        arrow.setArrowInset(arrowParameters[3]);
        newOb.setParameter("arrow", JaxoArrow.class, arrow);
        newOb.setParameter(PAINT_ARROW, true);
        newOb.setParameter("arrowPosition", arrowParameters[0]);
        if (arrowParameters[5] == 1) {
            newOb.setParameter("flip", true);
        }
    }

    private void setBezierPoints(final JaxoObject newOb, final int[] pars) {
        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("x4", pars[6]);
        newOb.setParameter("y4", pars[7]);
    }
}
