import { assertExists, noop } from '@blockeditor/global/utils';
import { hasClassNameInList } from '../../../../_common/utils/index.js';
import { Bound, CanvasElementType, StrokeStyle, } from '../../../../surface-block/index.js';
import { EXCLUDING_MOUSE_OUT_CLASS_LIST, SHAPE_OVERLAY_HEIGHT, SHAPE_OVERLAY_OPTIONS, SHAPE_OVERLAY_WIDTH, } from '../../utils/consts.js';
import { ShapeOverlay } from '../../utils/tool-overlay.js';
import { EdgelessToolController } from './index.js';
export class ShapeToolController extends EdgelessToolController {
    constructor() {
        super(...arguments);
        this.tool = {
            type: 'shape',
            shapeType: 'rect',
        };
        this._draggingElement = null;
        this._draggingElementId = null;
        // shape overlay
        this._shapeOverlay = null;
        this._draggingArea = null;
    }
    _addNewShape(e, width, height) {
        const { viewport } = this._edgeless.surface;
        const attributes = this._edgeless.surface.service.editSession.getLastProps('shape');
        const { shapeType } = this.tool;
        if (shapeType === 'rect' && attributes.radius > 0) {
            width += 40;
        }
        // create a shape block when drag start
        const [modelX, modelY] = viewport.toModelCoord(e.point.x, e.point.y);
        const bound = new Bound(modelX, modelY, width, height);
        const id = this._surface.addElement(CanvasElementType.SHAPE, {
            shapeType: shapeType,
            xywh: bound.serialize(),
            radius: attributes.radius,
        });
        return id;
    }
    onContainerClick(e) {
        this.clearOverlay();
        this._page.captureSync();
        const id = this._addNewShape(e, SHAPE_OVERLAY_WIDTH, SHAPE_OVERLAY_HEIGHT);
        const element = this._surface.pickById(id);
        assertExists(element);
        this._edgeless.tools.switchToDefaultMode({
            elements: [element.id],
            editing: false,
        });
    }
    onContainerContextMenu() {
        noop();
    }
    onContainerPointerDown() {
        noop();
    }
    onContainerDblClick() {
        noop();
    }
    onContainerTripleClick() {
        noop();
    }
    onContainerDragStart(e) {
        this.clearOverlay();
        this._page.captureSync();
        const id = this._addNewShape(e, 0, 0);
        this._draggingElementId = id;
        this._draggingElement = this._surface.pickById(id);
        this._draggingElement.stash('xywh');
        this._draggingArea = {
            start: new DOMPoint(e.x, e.y),
            end: new DOMPoint(e.x, e.y),
        };
    }
    onContainerDragMove(e) {
        assertExists(this._draggingElementId);
        assertExists(this._draggingArea);
        this._draggingArea.end = new DOMPoint(e.x, e.y);
        this._resize(e.keys.shift || this._edgeless.tools.shiftKey);
    }
    onContainerDragEnd() {
        if (this._draggingElement) {
            const draggingElement = this._draggingElement;
            this._page.transact(() => {
                draggingElement.pop('xywh');
            });
        }
        const id = this._draggingElementId;
        assertExists(id);
        if (this._draggingArea) {
            const width = Math.abs(this._draggingArea?.end.x - this._draggingArea?.start.x);
            const height = Math.abs(this._draggingArea?.end.y - this._draggingArea?.start.y);
            if (width < 20 && height < 20) {
                this._surface.removeElement(id);
                return;
            }
        }
        this._draggingElement = null;
        this._draggingElementId = null;
        this._draggingArea = null;
        this._page.captureSync();
        const element = this._surface.pickById(id);
        assertExists(element);
        this._edgeless.tools.switchToDefaultMode({
            elements: [element.id],
            editing: false,
        });
    }
    onPressShiftKey(pressed) {
        const id = this._draggingElementId;
        if (!id)
            return;
        this._resize(pressed);
    }
    _resize(shift = false) {
        const { _draggingElementId: id, _draggingArea, _edgeless } = this;
        assertExists(id);
        assertExists(_draggingArea);
        const { surface } = _edgeless;
        const { viewport } = surface;
        const { zoom } = viewport;
        const { start: { x: startX, y: startY }, end, } = _draggingArea;
        let { x: endX, y: endY } = end;
        if (shift) {
            const w = Math.abs(endX - startX);
            const h = Math.abs(endY - startY);
            const m = Math.max(w, h);
            endX = startX + (endX > startX ? m : -m);
            endY = startY + (endY > startY ? m : -m);
        }
        const [x, y] = viewport.toModelCoord(Math.min(startX, endX), Math.min(startY, endY));
        const w = Math.abs(startX - endX) / zoom;
        const h = Math.abs(startY - endY) / zoom;
        const bound = new Bound(x, y, w, h);
        this._surface.updateElement(id, {
            xywh: bound.serialize(),
        });
    }
    _updateOverlayPosition(x, y) {
        if (!this._shapeOverlay)
            return;
        this._shapeOverlay.x = x;
        this._shapeOverlay.y = y;
        this._edgeless.surface.refresh();
    }
    clearOverlay() {
        if (!this._shapeOverlay)
            return;
        this._shapeOverlay.dispose();
        this._edgeless.surface.viewport.removeOverlay(this._shapeOverlay);
        this._shapeOverlay = null;
        this._edgeless.surface.refresh();
    }
    _hideOverlay() {
        if (!this._shapeOverlay)
            return;
        this._shapeOverlay.globalAlpha = 0;
        this._edgeless.surface.refresh();
    }
    onContainerMouseMove(e) {
        if (!this._shapeOverlay)
            return;
        // shpae options, like stroke color, fill color, etc.
        if (this._shapeOverlay.globalAlpha === 0)
            this._shapeOverlay.globalAlpha = 1;
        const [x, y] = this._surface.viewport.toModelCoord(e.x, e.y);
        this._updateOverlayPosition(x, y);
    }
    onContainerMouseOut(e) {
        if (e.raw.relatedTarget &&
            hasClassNameInList(e.raw.relatedTarget, EXCLUDING_MOUSE_OUT_CLASS_LIST))
            return;
        this._hideOverlay();
    }
    beforeModeSwitch() {
        this.clearOverlay();
    }
    afterModeSwitch(newTool) {
        if (newTool.type !== 'shape')
            return;
        this.createOverlay();
    }
    createOverlay() {
        this.clearOverlay();
        const options = SHAPE_OVERLAY_OPTIONS;
        const attributes = this._edgeless.surface.service.editSession.getLastProps('shape');
        options.stroke = attributes.strokeColor;
        options.fill = attributes.fillColor;
        switch (attributes.strokeStyle) {
            case StrokeStyle.Dashed:
                options.strokeLineDash = [12, 12];
                break;
            case StrokeStyle.None:
                options.strokeLineDash = [];
                options.stroke = 'transparent';
                break;
            default:
                options.strokeLineDash = [];
        }
        let shapeType = attributes.shapeType;
        if (attributes.radius > 0 && shapeType === 'rect') {
            shapeType = 'roundedRect';
        }
        this._shapeOverlay = new ShapeOverlay(this._edgeless, shapeType, options, {
            shapeStyle: attributes.shapeStyle,
            fillColor: options.fill,
            strokeColor: options.stroke,
        });
        this._edgeless.surface.viewport.addOverlay(this._shapeOverlay);
    }
}
//# sourceMappingURL=shape-tool.js.map