import React = require("react");
import { observable, action } from "mobx";
import { observer } from "mobx-react";
import { InkStrokeProperties } from "./InkStrokeProperties";
import { setupMoveUpEvents, emptyFunction } from "../../Utils";
import { UndoManager } from "../util/UndoManager";
import { ControlPoint, InkData, PointData } from "../../fields/InkField";
import { Transform } from "../util/Transform";

export interface InkControlProps {
    data: InkData;
    addedPoints: PointData[];
    format: number[];
    ScreenToLocalTransform: () => Transform;
}

@observer
export class InkControls extends React.Component<InkControlProps> {
    // @observable private _controlPoints: ControlPoint[] = [];
    @observable private _overControl = -1;
    @observable private _overAddPoint = -1;

    /**
     * Handles the movement of a selected control point when the user clicks and drags.
     * @param controlNum The index of the currently selected control point.
     */
    @action
    onControlDown = (e: React.PointerEvent, controlNum: number): void => {
        if (InkStrokeProperties.Instance) {
            InkStrokeProperties.Instance.moveControl(0, 0, 1);
            const controlUndo = UndoManager.StartBatch("DocDecs set radius");
            const screenScale = this.props.ScreenToLocalTransform().Scale;
            setupMoveUpEvents(this, e,
                (e: PointerEvent, down: number[], delta: number[]) => {
                    InkStrokeProperties.Instance?.moveControl(-delta[0] * screenScale, -delta[1] * screenScale, controlNum);
                    return false;
                },
                () => controlUndo?.end(), emptyFunction);
        }
    }

    /**
     * Deletes the currently selected point.
     */
    @action
    onDelete = (e: KeyboardEvent) => {
        if (["-", "Backspace", "Delete"].includes(e.key)) {
            if (InkStrokeProperties.Instance?.deletePoints()) e.stopPropagation();
        }
    }

    /**
     * Changes the current selected control point.
     */
    @action
    changeCurrPoint = (i: number) => {
        if (InkStrokeProperties.Instance) {
            InkStrokeProperties.Instance._currentPoint = i;
            document.addEventListener("keydown", this.onDelete, true);
        }
    }

    @action onEnterControl = (i: number) => { this._overControl = i; };
    @action onLeaveControl = () => { this._overControl = -1; };
    @action onEnterAddPoint = (i: number) => { this._overAddPoint = i; };
    @action onLeaveAddPoint = () => { this._overAddPoint = -1; };
 
    render() {
        const data = this.props.data;
        const controlPoints: ControlPoint[] = [];
        if (data.length >= 4) {
            for (let i = 0; i <= data.length - 4; i += 4) {
                controlPoints.push({ X: data[i].X, Y: data[i].Y, I: i });
                controlPoints.push({ X: data[i + 3].X, Y: data[i + 3].Y, I: i + 3 });
            }
        }
        const addedPoints = this.props.addedPoints;
        const [left, top, scaleX, scaleY, strokeWidth, dotsize] = this.props.format;

        return (
            <>
                {addedPoints.map((pts, i) =>
                    <svg height="10" width="10" key={`add${i}`}>
                        <circle 
                            cx={(pts.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2} 
                            cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2} 
                            r={strokeWidth / 2} 
                            stroke={this._overAddPoint === i ? "#1F85DE" : "transparent"} 
                            strokeWidth={dotsize / 4} fill={this._overAddPoint === i ? "#1F85DE" : "transparent"}
                            onPointerDown={() => { InkStrokeProperties.Instance?.addPoints(pts.X, pts.Y, addedPoints, i, controlPoints); }} 
                            onMouseEnter={() => this.onEnterAddPoint(i)} 
                            onMouseLeave={this.onLeaveAddPoint} 
                            pointerEvents="all" 
                            cursor="all-scroll"
                        />
                    </svg>
                )}
                {controlPoints.map((control, i) =>
                    <svg height="10" width="10" key={`ctrl${i}`}>
                        <rect 
                            x={(control.X - left - strokeWidth / 2) * scaleX} 
                            y={(control.Y - top - strokeWidth / 2) * scaleY} 
                            height={this._overControl === i ? strokeWidth * 1.5 : strokeWidth} 
                            width={this._overControl === i ? strokeWidth * 1.5 : strokeWidth} 
                            strokeWidth={strokeWidth / 6} stroke="#1F85DE" 
                            fill={InkStrokeProperties.Instance?._currentPoint === control.I ? "#1F85DE" : "white"}
                            onPointerDown={(e) => { this.changeCurrPoint(control.I); this.onControlDown(e, control.I); }} 
                            onMouseEnter={() => this.onEnterControl(i)} 
                            onMouseLeave={this.onLeaveControl} 
                            pointerEvents="all" 
                            cursor="default"
                        />
                    </svg>
                )}
            </>
        );
    }
}