/**
 *  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.object.text;

import java.awt.Dimension;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;

import net.sf.jaxodraw.object.JaxoObject;
import net.sf.jaxodraw.object.JaxoObjectEditPanel;
import net.sf.jaxodraw.util.JaxoPrefs;
import net.sf.jaxodraw.util.JaxoColor;
import net.sf.jaxodraw.util.graphics.JaxoGraphics2D;


/** Defines a JaxoObject which is just a string.
 * @since 2.0
 */
public class JaxoLatexText extends JaxoTextObject {
    private static final long serialVersionUID = 314159L;

    /**
     * Align left-top with respect to text coordinates.
     */
    public static final int ALIGN_LT = 0;

    /**
     * Align left-center with respect to text coordinates.
     */
    public static final int ALIGN_LC = 1;

    /**
     * Align left-bottom with respect to text coordinates.
     */
    public static final int ALIGN_LB = 2;

    /**
     * Align center-top with respect to text coordinates.
     */
    public static final int ALIGN_CT = 3;

    /**
     * Align center-center with respect to text coordinates.
     */
    public static final int ALIGN_CC = 4;

    /**
     * Align center-bottom with respect to text coordinates.
     */
    public static final int ALIGN_CB = 5;

    /**
     * Align right-top with respect to text coordinates.
     */
    public static final int ALIGN_RT = 6;

    /**
     * Align right-center with respect to text coordinates.
     */
    public static final int ALIGN_RC = 7;

    /**
     * Align right-bottom with respect to text coordinates.
     */
    public static final int ALIGN_RB = 8;


    /**
     * Latex text size tiny.
     */
    public static final int TINY = 0;

    /**
     * Latex text size scriptsize.
     */
    public static final int SCRIPTSIZE = 1;

    /**
     * Latex text size footnotesize.
     */
    public static final int FOOTNOTESIZE = 2;

    /**
     * Latex text size small.
     */
    public static final int SMALL = 3;

    /**
     * Latex text size normalsize.
     */
    public static final int NORMALSIZE = 4;

    /**
     * Latex text size large.
     */
    public static final int LARGE = 5;

    /**
     * Latex text size Large.
     */
    public static final int XLARGE = 6;

    /**
     * Latex text size LARGE.
     */
    public static final int XXLARGE = 7;

    /**
     * Latex text size huge.
     */
    public static final int HUGE = 8;

    /**
     * Latex text size Huge.
     */
    public static final int XHUGE = 9;

      //
     // private
    //

    private static final String[] ALIGNS =
        {"[lt]", "[l]", "[lb]", "[t]", "[]", "[b]", "[rt]", "[r]", "[rb]"};

    private static final String[] SIZES =
        {
            "{\\tiny{", "{\\scriptsize{", "{\\footnotesize{", "{\\small{",
            "{\\normalsize{", "{\\large{", "{\\Large{", "{\\LARGE{", "{\\huge{",
            "{\\Huge{"
        };

    /** An integer specifying how the text is alligned with respect to the
     *  current position.
     */
    private int allign;

    /** An integer specifying the LaTeX font size. */
    private int latexTextSize;

    // Bean getter and setter methods

    /** Returns the allign property of this text object.
     * @return The allign property of this text object.
     */
    public final int getAllign() {
        return allign;
    }

    /** Sets the allign property of this text object.
     * @param newAllign The allign property of this text object.
     */
    public final void setAllign(final int newAllign) {
        try {
            getLaTexAllign(newAllign);
        } catch (ArrayIndexOutOfBoundsException e) {
            throw new IllegalArgumentException("Invalid Latex text align!", e);
        }

        final Integer old = Integer.valueOf(allign);
        this.allign = newAllign;
        firePropertyChange("allign", old, Integer.valueOf(allign));
    }

    /** Returns the latex font size of this text object.
     * @return The latex font size of this text object.
     */
    public final int getLatexTextSize() {
        return latexTextSize;
    }

    /** Sets the latex font size of this text object.
     * @param newLatexfs The latex font size of this text object.
     */
    public final void setLatexTextSize(final int newLatexfs) {
        try {
            getLatexTextSize();
        } catch (ArrayIndexOutOfBoundsException e) {
            throw new IllegalArgumentException("Invalid Latex text size!", e);
        }

        final Integer old = Integer.valueOf(latexTextSize);
        this.latexTextSize = newLatexfs;
        firePropertyChange("latexTextSize", old, Integer.valueOf(latexTextSize));
    }

    /** {@inheritDoc} */
    @Override
    public boolean isCopy(final JaxoObject comp) {
        boolean isCopy = false;

        if (comp instanceof JaxoLatexText) {
            final JaxoLatexText tmp = (JaxoLatexText) comp;
            if ((tmp.getAllign() == getAllign())
                    && (tmp.getLatexTextSize() == getLatexTextSize()) && super.isCopy(tmp)) {
                isCopy = true;
            }
        }

        return isCopy;
    }

    /** Sets all parameters from the given object to the current one.
     * @param temp The object to copy from.
     */
    public void copyFrom(final JaxoLatexText temp) {
        super.copyFrom(temp);
        setAllign(temp.getAllign());
        setLatexTextSize(temp.getLatexTextSize());
    }

    /** {@inheritDoc} */
    @Override
    public void setState(final JaxoObject o) {
        if (o instanceof JaxoLatexText) {
            copyFrom((JaxoLatexText) o);
        } else {
            throw new UnsupportedOperationException("Cannot copy from super type!");
        }
    }

    /** {@inheritDoc} */
    public final void paint(final JaxoGraphics2D g2) {
        if (!g2.isPrinting()) {
            paintTexVisualAid(g2);
        }
    }

    /** Paints a visual aid for a tex label:
     *  a blue TeX icon.
     * @param g2 The graphics context to paint to
     */
    private void paintTexVisualAid(final JaxoGraphics2D g2) {
        final int x = getX();
        final int y = getY();
        final double theta = Math.toRadians(getRotationAngle());

        //AffineTransform at = new AffineTransform();
        //at.rotate(theta, x, y);
        final char[] ltT = {'T'};
        final char[] ltE = {'E'};
        final char[] ltX = {'X'};

        final Font ltTFont = new Font("Utopia", Font.PLAIN, 18);
        final Font ltEFont = new Font("Utopia", Font.PLAIN, 14);
        final Font ltXFont = ltTFont;

        g2.rotate(theta, x, y);

        int xOff = 5;
        int yOff = 16;

        if ((allign == ALIGN_CT) || (allign == ALIGN_CC) || (allign == ALIGN_CB)) {
            xOff = -13;
        } else if ((allign == ALIGN_RT) || (allign == ALIGN_RC) || (allign == ALIGN_RB)) {
            xOff = -31;
        }

        if ((allign == ALIGN_LC) || (allign == ALIGN_CC) || (allign == ALIGN_RC)) {
            yOff = 5;
        } else if ((allign == ALIGN_LB) || (allign == ALIGN_CB) || (allign == ALIGN_RB)) {
            yOff = -6;
        }

        g2.setColor(JaxoColor.GRAYSCALE180);
        g2.setFont(ltTFont);
        g2.drawChars(ltT, 0, ltT.length, x + xOff, y + yOff);
        g2.setFont(ltEFont);
        g2.drawChars(ltE, 0, ltE.length, x + xOff + 9, y + yOff + 2);
        g2.setFont(ltXFont);
        g2.drawChars(ltX, 0, ltX.length, x + xOff + 17, y + yOff);
        g2.setColor(JaxoColor.CADET_BLUE);
        g2.setFont(ltTFont);
        g2.drawChars(ltT, 0, ltT.length, (x + xOff) - 1, (y + yOff) - 1);
        g2.setFont(ltEFont);
        g2.drawChars(ltE, 0, ltE.length, x + xOff + 8, y + yOff + 1);
        g2.setFont(ltXFont);
        g2.drawChars(ltX, 0, ltX.length, x + xOff + 18, (y + yOff) - 1);

        g2.rotate(-theta, x, y);
    }

    /** Determines whether the cursor is currently above the
     * visual aid icon of this LatexText.
     * @param mouseX The current x - coordinate of the cursor
     * @param mouseY The current y - coordinate of the cursor
     * @return A boolean variable
     */
    public final boolean isRolledOver(final int mouseX, final int mouseY) {
        return getBounds().contains(mouseX, mouseY);
    }

    /**
     * Returns the bounding box of this object.
     *
     * @return the bounding box of this object.
     */
    public Rectangle getBounds() {
        final Rectangle bBox = new Rectangle();
        final GeneralPath gp = getGeneralPath();
        gp.reset();
        final int x = getX();
        final int y = getY();

        int xOff = 3;
        int yOff = 1;

        if ((allign == ALIGN_CT) || (allign == ALIGN_CC) || (allign == ALIGN_CB)) {
            xOff = -15;
        } else if ((allign == ALIGN_RT) || (allign == ALIGN_RC) || (allign == ALIGN_RB)) {
            xOff = -33;
        }

        if ((allign == ALIGN_LC) || (allign == ALIGN_CC) || (allign == ALIGN_RC)) {
            yOff = -10;
        } else if ((allign == ALIGN_LB) || (allign == ALIGN_CB) || (allign == ALIGN_RB)) {
            yOff = -21;
        }

        bBox.setLocation(x + xOff, y + yOff);
        bBox.setSize(32, 16);
        gp.append(bBox, false);

        if (getRotationAngle() != 0) {
            final AffineTransform at = new AffineTransform();
            at.rotate(Math.toRadians(getRotationAngle()), x, y);
            gp.transform(at);
        }

        return gp.getBounds();
    }

    /** {@inheritDoc} */
    public final String latexCommand(final float scale, final Dimension canvasDim) {
        // Text(x,y)[mode]{text}
        // r2Text(#1,#2)[#3](#4,#5)#6

        final Point2D position = getLaTexPosition(scale, canvasDim.height);
        final String allignCode = getLaTexAllign(allign);
        String rputAllign = allignCode;
        if ("[]".equals(rputAllign)) {
            rputAllign = "";
        }
        final String fontSize = getLaTexFontSize(latexTextSize);

        String color;
        if (JaxoColor.isGrayScale(getColor())) {
            color = "\\Gray";
        } else {
            color = "\\" + JaxoColor.getColorName(getColor());
        }

        if (getRotationAngle() == 0) {
            return "\\Text" + "(" + D_FORMAT.format(position.getX()) + ","
                + D_FORMAT.format(position.getY()) + ")" + allignCode
                + fontSize + color + "{$" + getTextString() + "$}}}";
        } else {
            final int ang = -getRotationAngle(); // pstricks counts angles counter-clockwise

            return "\\Text" + "(" + D_FORMAT.format(position.getX()) + ","
                + D_FORMAT.format(position.getY()) + ")" + allignCode
                + fontSize + color + "{$" + "\\rput" + rputAllign + "{" + ang
                + "}" + "{" + getTextString() + "}" + "$}}}";
        }
    }

    /** {@inheritDoc} */
    @Override
    public void setPreferences() {
        super.setPreferences();
        setRotationAngle(JaxoPrefs.getIntPref(JaxoPrefs.PREF_TEXROTANGLE));
        setColor(JaxoColor.getColor(JaxoPrefs.getStringPref(
                    JaxoPrefs.PREF_TEXTCOLOR),
                JaxoColor.JAXO_COLORS_MODE));
        setTextString("");
        setAllign(JaxoPrefs.getIntPref(JaxoPrefs.PREF_TEXALIGN));
        setLatexTextSize(JaxoPrefs.getIntPref(JaxoPrefs.PREF_TEXSIZE));
    }

    /** {@inheritDoc} */
    public void prepareEditPanel(final JaxoObjectEditPanel editPanel) {
        editPanel.addPositionPanel(getX(), getY(), 0, 0);
        editPanel.addRotationPanel(getRotationAngle(), 1, 0);
        editPanel.addColorPanel(getColor(), JaxoObjectEditPanel.TYPE_LINE_COLOR, 2, 0);
        editPanel.addTextPanel(getTextString(), 0, 1);
        editPanel.addLatexFontSizePanel(getLatexTextSize(), 1, 1);
        editPanel.addLatexAlignPanel(getAllign(), 2, 1);

        editPanel.setTitleAndIcon("LaTeX_text_parameters", "latex.png");
    }

      //
     // private methods
    //

    private Point2D getLaTexPosition(final float scaleFactor, final int canvasHeight) {
        return new Point2D.Float(getX() / scaleFactor,
            (canvasHeight - getY()) / scaleFactor);
    }

    private String getLaTexAllign(final int all) {
        return ALIGNS[all];
    }

    private String getLaTexFontSize(final int fs) {
        return SIZES[fs];
    }
}
