/*
 * Created on Apr 16, 2003
 */

package de.renew.fa.figures;

import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.TextAttribute;
import java.awt.geom.Rectangle2D;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;

import CH.ifa.draw.framework.ParentFigure;
import de.renew.fa.FAPlugin;
import de.renew.gui.CPNTextFigure;


/**
 * A FATextFigure is a TextFigure that can be used to inscribe FAStateFigures.
 *
 * @author Lawrence Cabac
 */
public class FATextFigure extends CPNTextFigure {
    static final long serialVersionUID = -7270464173137023567L;
    private static final org.apache.log4j.Logger LOGGER =
        org.apache.log4j.Logger.getLogger(FATextFigure.class);

    /**
     * A FATextFigure of thy NAME.
     * Used for type comparisons.
     */
    public static final FATextFigure NAME = new FATextFigure(CPNTextFigure.NAME);

    /**
     * A FATextFigure of type INSCRIPTION.
     * Used for type comparisons.
     */
    public static final FATextFigure INSCRIPTION = new FATextFigure(CPNTextFigure.INSCRIPTION);

    /**
     * Constructs a new FATextFigure with default values.
     */
    public FATextFigure() {
        this(CPNTextFigure.INSCRIPTION, true);
    }

    /**
     * Constructs a new FATextFigure of a specific type.
     *
     * @param type Takes an enum from CPNTextFigure for its type.
     * @see CPNTextFigure
     */
    public FATextFigure(int type) {
        this(type, true);
        LOGGER.debug("FATextFigure of type " + this.fType + " created");
    }

    /**
     * Constructs a new FATextFigure of a specific type.
     * Additionally, it can be set to not be able to connect.
     *
     * @param type Takes an enum from CPNTextFigure for its type.
     * @param canBeConnected If true, this figure can be connected with other figures. False otherwise.
     * @see CPNTextFigure
     */
    public FATextFigure(int type, boolean canBeConnected) {
        super(type, canBeConnected);
    }

    /**
     * Constructs a new FATextFigure of a specific type.
     * Additionally, its text content can be set directly in the constructor.
     *
     * @param type Takes an enum from CPNTextFigure for its type.
     * @param text The text which should be contained in the figure.
     * @see CPNTextFigure
     */
    public FATextFigure(int type, String text) {
        this(type, true);
        setText(text);
    }

    @Override
    protected void drawLine(Graphics g, int i) {
        Font font = getLineFont(i); //NOTICEsignature
        g.setFont(font);

        boolean useIndices = FAPlugin.getCurrent().getUseIndices();
        int x = getLineBox(g, i).x;
        int y = getLineBox(g, i).y;
        String text = getLine(i);
        if (!useIndices || text == null || text.equals("")) {
            g.drawString(text, x, y + getMetrics(font, g).getAscent());
        } else {
            AttributedString aStr = getFAText(text);
            Graphics2D g2d = (Graphics2D) g;
            g2d.drawString(aStr.getIterator(), x, y + (getMetrics(font, g).getAscent()));
        }
    }

    private AttributedString getFAText(String text) {
        // Create an AttributedString of the text that has superscripted index, if any
        String strippedtext = text.replaceAll("_\\{(.*?)\\}", "$1");
        strippedtext = strippedtext.replaceFirst("_", "");
        AttributedString aStr = new AttributedString(strippedtext);

        // If there is any text in the stripped string, set the font size attribute for aStr.
        // Additionally, if the figure is of type NAME, set the WEIGHT attribute.
        if (!"".equals(text)) {
            aStr.addAttribute(
                TextAttribute.SIZE, ((Integer) getAttribute("FontSize")).intValue() + 2);
            if (getType() == CPNTextFigure.NAME) {
                aStr.addAttribute(
                    TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, 0, strippedtext.length());
            }
        }

        if (!text.contains("_")) {
            return aStr;
        }

        // If there is no "{" left, set the SUPERSCRIPT attribute, then return.
        if (!text.contains("{")) {
            int index = text.indexOf('_');
            aStr.addAttribute(
                TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUB, index,
                strippedtext.length());

            return aStr;
        }

        // Only enters if the text does still have both an "_" and a "{" left.

        // Determine the position of the part to be superscripted
        boolean indexswitch = false;
        boolean bracketswitch = false;

        int pos = 0;
        for (int i = 0; i < text.length(); i++) {
            char c = text.charAt(i);

            //                System.out.println("c "+c+" i "+ i +" pos "+pos);
            if (c == '_') {
                indexswitch = true;
                continue;
            }
            if (indexswitch) {
                if (c == '}') {
                    bracketswitch = false;
                    indexswitch = false;
                    continue;
                } else if (c == '{') {
                    bracketswitch = true;
                    continue;
                }
            }
            if (indexswitch && bracketswitch) {
                aStr.addAttribute(
                    TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUB, pos + 0, pos + 1);
            }
            pos++;
        }

        //        AttributedString aStr = new AttributedString(text);
        //        AttributedCharacterIterator it = aStr.getIterator();
        //
        //        //        System.out.println("Iterator "+it.getBeginIndex() +" "+ it.getEndIndex());
        //        for (int j = it.getBeginIndex(); j < it.getEndIndex(); j++) {
        //            char c = it.next();
        //            if(c == '_'){
        //                aStr.addAttribute(TextAttribute., value);
        //            }
        //            
        //            //            System.out.println("char "+c);
        //            if (c == '0' || c == '1' || c == '2' || c == '3' || c == '4'
        //                        || c == '5' || c == '6' || c == '7' || c == '8'
        //                        || c == '9') {
        //                aStr.addAttribute(TextAttribute.SUPERSCRIPT,
        //                                  TextAttribute.SUPERSCRIPT_SUB, j + 1, j + 2);
        //                //                System.out.println("char " + c + " index "+ (j+1));
        //            }
        //            
        //        }
        //
        //        System.out.println(aStr+ " "+ aStr.getIterator());
        return aStr;
    }

    /**
    * Calculates the Dimension of the given line, considering occuring indices
    *
    * @param i
    *  The index of the current line.
    * @param g
    *  Could be null.
    * @return Dimension
    */
    @Override
    public Dimension getLineDimension(int i, Graphics g) {
        FAPlugin plugin = FAPlugin.getCurrent();
        boolean useIndices = false;
        if (plugin != null) {
            useIndices = plugin.getUseIndices();
        }
        if (!useIndices) {
            return super.getLineDimension(i, g);
        }
        FontMetrics metrics = getMetrics(getLineFont(i), g);
        AttributedString faText = getFAText(getLine(i));
        AttributedCharacterIterator it = faText.getIterator();

        //LineMetrics lmetrics = getMetrics(getLineFont(0), g).getLineMetrics(it, it.getBeginIndex(), it.getEndIndex(), g);
        //FontMetrics metrics2 = getMetrics(getLineFont(0), g);
        Rectangle2D stringBounds =
            metrics.getStringBounds(it, it.getBeginIndex(), it.getEndIndex(), g);
        double width = 0;
        double heightaddition = 0;
        it.first();
        for (int idx = 0; idx < it.getEndIndex(); idx++) {
            char c = it.current();
            if (c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6'
                || c == '7' || c == '8' || c == '9') {
                width += metrics.charWidth(c) / 1.5;
                heightaddition = metrics.getHeight() / 3;
            } else {
                width += metrics.charWidth(c);
            }
            //           System.out.println("Character "+c +" "+width);
            it.next();
        }

        return new Dimension(
            (int) width, (int) stringBounds.getBounds().getHeight() + (int) heightaddition);
    }

    @Override
    protected boolean canBeParent(int type, ParentFigure parent) {
        switch (type) {
            case LABEL:
                return true;
            case CPNTextFigure.INSCRIPTION:
                return parent instanceof FAArcConnection;
            case AUX:
            case CPNTextFigure.NAME:
                return parent instanceof FAArcConnection || parent instanceof FAStateFigure;
        }
        return false;
    }

    /**
     * Returns the name of the figure as a string in the format:
     * [className]([text])
     *
     * Example:
     * If the class of this figure is "de.renew.fa.figures"
     * and its text is "Hello World",
     * the following string will be returned:
     *
     * figures(HelloWorld)
     *
     *
     * @return The name of the figure at runtime
     */
    public String getName() {
        String cln = getClass().getName();
        int ind = cln.lastIndexOf('.') + 1;
        if (ind > 0) {
            cln = cln.substring(ind);
        }

        return cln + "(" + this.getText() + ")";
    }

    @Override
    public String toString() {
        return this.getText();
    }
}