package de.renew.tablet.tools;

import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;

import CH.ifa.draw.figures.PolyLineFigure;
import CH.ifa.draw.standard.UndoableTool;
import de.renew.draw.ui.ontology.DrawingEditor;


/**
 * Tool to scribble a PolyLineFigure
 * {@link PolyLineFigure}
 *
 * @author Lawrence Cabac
 */
public class ScribbleTool extends UndoableTool {
    private PolyLineFigure _fScribble;
    private int _fLastX;
    private int _fLastY;

    /**
     * Constructs a tool for the given view.
     *
     * @param editor the given view.
     */
    public ScribbleTool(DrawingEditor editor) {
        super(editor);
    }

    /**
     * Activates the tool.
     * This method is called whenever the user switches to this tool.
     */
    @Override
    public void activate() {
        super.activate();
        _fScribble = null;
    }

    /**
     * Deactivates the tool. This method is called whenever the user
     * switches to another tool.
     * If the user is still drawing the last drawn line is getting removed
     * when the width or height are below 4.
     */
    @Override
    public void deactivate() {
        if (_fScribble != null) {
            if (_fScribble.size().width < 4 || _fScribble.size().height < 4) {
                drawing().remove(_fScribble);
                noChangesMade();
            }
        }
        _fScribble = null;
        super.deactivate();
    }

    /**
     * Creates a new PolyLineFigure if the current figure is null.
     * Adds a new point with the given coordinates to the line.
     *
     * @param x x-coordinate
     * @param y y-coordinate
     */
    private void point(int x, int y) {
        // If the drawing is zoomed, the point has to be scaled
        AffineTransform at = view().getAffineTransform();
        if (at != null) {
            try {
                Point p = new Point(x, y);
                at.inverseTransform(p, p);
                x = p.x;
                y = p.y;

            } catch (NoninvertibleTransformException e) {
                System.err.println(
                    "DrawingView for drawing " + view().drawing().getName()
                        + " had an irreversible affine transformation.");
                System.err.println("The polyline was not correctly scaled.");
                e.printStackTrace();
            }
        }
        if (_fScribble == null) {
            _fScribble = new PolyLineFigure(x, y);
            view().add(_fScribble);
            changesMade();
        } else if (_fLastX != x || _fLastY != y) {
            _fScribble.addPoint(x, y);
        }

        _fLastX = x;
        _fLastY = y;
    }

    /**
     * Adds a new point with the given coordinates to a PolyLineFigure.
     * When double clicked switches to the default tool.
     *
     * @param e the mouse event
     * @param x x-coordinate
     * @param y y-coordinate
     */
    @Override
    public void mouseDown(MouseEvent e, int x, int y) {
        if (e.getClickCount() >= 2) {
            editor().toolDone();
        } else {
            // use original event coordinates to avoid
            // supress that the scribble is constrained to
            // the grid
            point(e.getX(), e.getY());
        }
    }

    /**
     * Adds a new point with the given coordinates to the current PolyLineFigure.
     *
     * @param e the mouse event
     * @param x x-coordinate
     * @param y y-coordinate
     */
    @Override
    public void mouseDrag(MouseEvent e, int x, int y) {
        if (_fScribble != null) {
            point(e.getX(), e.getY());
        }
    }

    /**
     * Sets the current PolyLineFigure to null.
     *
     * @param e the mouse event
     * @param x x-coordinate
     * @param y y-coordinate
     */
    @Override
    public void mouseUp(MouseEvent e, int x, int y) {
        //smoothPoints(fScribble); does not work
        _fScribble = null;
    }

    //    /**
    //     * Remove points that are nearly colinear with others
    //     **/
    //    public void smoothPoints(PolyLineFigure polyline) {
    //        polyline.willChange();
    //        boolean removed = false;
    //        Enumeration<Point> points = polyline.points();
    //        int j = 0;
    //        Point[] pointL = new Point[2000];
    //        int[] xpoints = new int[2000];
    //        int[] ypoints = new int[2000];
    //        while (points.hasMoreElements()) {
    //            Point point = (Point) points.nextElement();
    //            pointL[j] = point;
    //            xpoints[j] = point.x;
    //            ypoints[j] = point.y;
    //            j++;
    //        }
    //        int npoints = j;
    //        int n = npoints;
    //        do {
    //            removed = false;
    //            int i = 0;
    //            while (i < n && n >= 3) {
    //                int nxt = (i + 1) % n;
    //                int prv = (i - 1 + n) % n;
    //                String strategy = DrawPlugin.getCurrent().getProperties()
    //                                            .getProperty(PolygonFigure.SMOOTHINGSTRATEGY);
    //                boolean doremove = false;
    //                if (strategy == null || strategy.equals("")
    //                            || PolygonFigure.SMOOTHING_INLINE.equals(strategy)) {
    //                    if ((PolygonFigure.distanceFromLine(xpoints[prv],
    //                                                                ypoints[prv],
    //                                                                xpoints[nxt],
    //                                                                ypoints[nxt],
    //                                                                xpoints[i],
    //                                                                ypoints[i]) < PolygonFigure.TOO_CLOSE)) {
    //                        doremove = true;
    //                    }
    //                } else if (PolygonFigure.SMOOTHING_DISTANCES.equals(strategy)) {
    //                    if (Math.abs(xpoints[prv] - xpoints[i]) < 5
    //                                && Math.abs(ypoints[prv] - ypoints[i]) < 5) {
    //                        doremove = true;
    //                    }
    //                }
    //                if (doremove) {
    //                    removed = true;
    //                    --n;
    //                    polyline.removePointAt(i);
    //                } else {
    //                    ++i;
    //                }
    //            }
    //        } while (removed);
    ////        if (n != npoints) {
    ////            polyline = new Polygon(polyline.xpoints, polyline.ypoints, n);
    ////        }
    //        polyline.changed();
    //    }
}