/*
 * @(#)TextTool.java 5.1
 *
 */
package CH.ifa.draw.figures;

import java.awt.Container;
import java.awt.Font;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;

import CH.ifa.draw.standard.CreationTool;
import CH.ifa.draw.standard.TextHolder;
import CH.ifa.draw.util.FloatingTextField;
import de.renew.draw.storables.ontology.Figure;
import de.renew.draw.ui.ontology.DrawingEditor;

/**
 * Tool to create new or edit existing text figures.
 * The editing behavior is implemented by overlaying the
 * Figure providing the text with a FloatingTextField.<p>
 * A tool interaction is done once a Figure that is not
 * a TextHolder is clicked.
 * <p>
 * {@link TextHolder}
 * {@link FloatingTextField}
 */
public class TextTool extends CreationTool {

    /**
     * FloatingTextField which holds the text.
     */
    protected FloatingTextField _textField;

    private TextHolder _typingTarget;

    /**
     * Constructor of the class TextTool.
     *
     * @param editor given view
     * @param prototype prototypical TextFigure used to create new TextFigures
     */
    public TextTool(DrawingEditor editor, TextFigure prototype) {
        super(editor, prototype);
    }

    /**
     * If the pressed figure is a TextHolder it can be edited otherwise
     * a new text figure is created.
     */
    @Override
    public void mouseDown(MouseEvent e, int x, int y) {
        Figure pressedFigure;
        TextHolder textHolder = null;

        pressedFigure = drawing().findFigureInside(x, y);
        if (pressedFigure instanceof TextHolder) {
            textHolder = (TextHolder) pressedFigure;
            if (!textHolder.acceptsTyping()) {
                textHolder = null;
            }
        }
        if (textHolder != null) {
            beginEdit(textHolder);
            return;
        }
        if (_typingTarget != null) {
            endEdit();
            editor().toolDone();
        } else {
            super.mouseDown(e, x, y);
            textHolder = (TextHolder) createdFigure();
            beginEdit(textHolder);
        }
    }

    @Override
    public void mouseDrag(MouseEvent e, int x, int y) {}

    @Override
    public void mouseUp(MouseEvent e, int x, int y) {}

    /**
     * Terminates the editing of a text figure.
     */
    @Override
    public void deactivate() {
        super.deactivate();
        endEdit();
    }

    /**
     * Sets the text cursor.
     */
    @Override
    public void activate() {
        super.activate();

        // JDK1.1 TEXT_CURSOR has an incorrect hot spot
        //view.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
    }

    /**
     * Checks whether a text editing session is currently active and returns a boolean accordingly.
     *
     * @return {@code true} if a text figure is currently being edited, otherwise return {@code false}
     */
    protected boolean isTypingActive() {
        return _typingTarget != null;
    }

    /**
     * Creates a <code>FloatingTextField</code> in order to enter a text for a text figure.
     *
     * @param figure - the figure, which holds the text.
     */
    public void beginEdit(TextHolder figure) {
        if (_textField == null) {
            _textField = new FloatingTextField();
            // listen for a text editing finish event (Ctrl-ENTER).
            _textField.addKeyListener(new KeyAdapter() {
                @Override
                public void keyPressed(KeyEvent keyEvent) {
                    if (keyEvent.isControlDown() && keyEvent.getKeyCode() == KeyEvent.VK_ENTER) {
                        deactivate();
                        editor().toolDone();
                    }
                }
            });
        }
        if (figure != _typingTarget && _typingTarget != null) {
            endEdit();
        }
        _textField.setText(figure.getText());
        figure.setText("");
        Rectangle bounds = fieldBounds(figure);
        Font font = figure.getFont();

        AffineTransform affineTransform = view().getAffineTransform();
        if (affineTransform != null) {
            Point p = new Point(bounds.x, bounds.y);
            affineTransform.transform(p, p);
            // We still don't need width and height, as it is overwritten anyway
            bounds = new Rectangle(p.x, p.y, 0, 0);

            font = font.deriveFont(affineTransform);
        }

        _textField.createOverlay((Container) view(), bounds, font);
        _typingTarget = figure;
        view().checkDamage();
    }

    /**
     * Sets the caret position to the given line and column.
     *
     * @param line line index
     * @param col column index
     */
    public void setCaretPosition(int line, int col) {
        _textField.setCaretPosition(line, col);
    }

    /**
     * Selects a range of text in the active {@link FloatingTextField}.
     *
     * @param startLine the starting line index of the selection
     * @param startColumn the starting column index of the selection
     * @param endLine the ending line index of the selection
     * @param endColumn the ending column index of the selection
     */
    public void select(int startLine, int startColumn, int endLine, int endColumn) {
        _textField.select(startLine, startColumn, endLine, endColumn);
    }

    /**
     * Ends the current text editing session.
     * <p>
     * If a text figure was being edited, updates its text content from the floating text field.
     * If the new text is empty or consists only of whitespace, the figure is removed from the drawing.
     * Also notifies the view of the change and creates an undo snapshot.
     */
    public void endEdit() {
        if (_typingTarget != null) {
            String newText = _textField.getText();
            String oldText = _typingTarget.getText();
            _typingTarget.setText(newText);
            if (newText.trim().isEmpty()) {
                drawing().remove((Figure) _typingTarget);
            }
            _typingTarget = null;
            _textField.endOverlay();
            view().checkDamage();
            if (!oldText.equals(newText)) {
                changesMade();
                intermediateUndoSnapshot();
            } else {
                noChangesMade();
            }
        }
    }

    private Rectangle fieldBounds(TextHolder figure) {
        /*
         * width and height are actually overridden by FloatingTExtField.
         * So only x,y coordinates are needed.
         */
        return figure.textDisplayBox();
    }
}