package de.renew.windowmanagement;

import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;

/**
 * responsible class for the dragging action to be displayed on the cursor.
 */
public class DraggableComponentAdapter extends MouseAdapter {

    /**
     * The parent container in which this component can be dragged via a mouse drag event.
     */
    private final DragCanvas _canvas;

    /**
     * The component to be dragged.
     */
    private final Component _dragTarget;

    /**
     * Default mouse cursor for dragging action
     */
    protected Cursor _draggingCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);

    /**
     * This is the constructor for DraggableComponentAdapter.
     *
     * @param canvas is the drawable where we display our components
     * @param target is the object that can be moved around
     */
    public DraggableComponentAdapter(DragCanvas canvas, Component target) {
        this._dragTarget = target;
        this._canvas = canvas;
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        if (_dragTarget.isShowing()) {
            Point absolute = e.getLocationOnScreen();
            _dragTarget.setCursor(_draggingCursor);

            BufferedImage image = new BufferedImage(
                _dragTarget.getWidth(), _dragTarget.getHeight(), BufferedImage.TYPE_INT_RGB);
            Graphics g = image.getGraphics();
            _dragTarget.printAll(g);
            g.setColor(new Color(0.6f, 0.6f, 0.6f, 0.6f));
            g.fillRect(0, 0, _dragTarget.getWidth(), _dragTarget.getHeight());
            _canvas.requestOverlayingShadow(absolute, image);
            Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1);
            ((JComponent) e.getSource()).scrollRectToVisible(r);

            _canvas.repaint();
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        Point absolute = e.getLocationOnScreen();

        if (wasDragged(absolute)) {
            Point canvasAbsolute = _canvas.getLocationOnScreen();
            Point adjustedLocation =
                new Point(absolute.x - canvasAbsolute.x, absolute.y - canvasAbsolute.y);
            if (_canvas.contains(adjustedLocation)) {
                _canvas.dropComponent(_dragTarget, absolute);
            }
        }

        _canvas.requestOverlayingShadow(null, null);
        _canvas.repaint();
        _dragTarget.setCursor(Cursor.getDefaultCursor());
        _canvas.validate();
    }

    /**
     * Helper method to determine if the component has actually changed positions after being dragged.
     *
     * @param newPosition is the updated position
     * @return true, if the position was changed, false it wasn't
     */
    private boolean wasDragged(Point newPosition) {
        Point oldPosition = _dragTarget.getLocationOnScreen();
        if (oldPosition.x + _dragTarget.getWidth() < newPosition.x || oldPosition.x > newPosition.x
            || oldPosition.y + _dragTarget.getHeight() < newPosition.y
            || oldPosition.y > newPosition.y) {
            return true;
        } else {
            return false;
        }
    }
}