import '../../chipper/js/initialize-globals.js';
import '../../assert/js/assert.js';
import '../../globals.js';
import { Shape } from '../../kite/js/imports.js';
import InstanceRegistry from '../../phet-core/js/documentation/InstanceRegistry.js';
import optionize from '../../phet-core/js/optionize.js';
import { Path } from '../../scenery/js/imports.js';
import ArrowShape from './ArrowShape.js';
import sceneryPhet from './sceneryPhet.js';
export default class ArrowNode extends Path {
    // Get these fields using ES5 getters.
    constructor(tailX, tailY, tipX, tipY, providedOptions) {
        // default options
        const options = optionize()({
            headHeight: 10,
            headWidth: 10,
            tailWidth: 5,
            isHeadDynamic: false,
            scaleTailToo: false,
            fractionalHeadHeight: 0.5, // head will be scaled when headHeight is greater than fractionalHeadHeight * arrow length
            doubleHead: false, // true puts heads on both ends of the arrow, false puts a head at the tip
            // Path options
            fill: 'black',
            stroke: 'black',
            lineWidth: 1
        }, providedOptions);
        // things you're likely to mess up, add more as needed
        assert && assert(options.headWidth > options.tailWidth);
        super(null);
        this.options = options;
        this.shapePoints = [];
        this._tailX = tailX;
        this._tailY = tailY;
        this._tipX = tipX;
        this._tipY = tipY;
        this.setTailAndTip(tailX, tailY, tipX, tipY);
        this.mutate(options);
        // support for binder documentation, stripped out in builds and only runs when ?binder is specified
        assert && phet?.chipper?.queryParameters?.binder && InstanceRegistry.registerDataURL('scenery-phet', 'ArrowNode', this);
    }
    get tailX() { return this._tailX; }
    get tailY() { return this._tailY; }
    get tipX() { return this._tipX; }
    get tipY() { return this._tipY; }
    /**
     * Sets the tail and tip positions to update the arrow shape.
     * If the tail and tip are at the same point, the arrow is not shown.
     */
    setTailAndTip(tailX, tailY, tipX, tipY) {
        this._tailX = tailX;
        this._tailY = tailY;
        this._tipX = tipX;
        this._tipY = tipY;
        const numberOfPointsChanged = this.updateShapePoints();
        // This bit of logic is to improve performance for the case where the Shape instance can be reused
        // (if the number of points in the array is the same).
        if (!this.shape || numberOfPointsChanged) {
            this.updateShape();
        }
        else {
            // This is the higher-performance case where the Shape instance can be reused
            this.shape.invalidatePoints();
        }
    }
    /**
     * Initialize or update the shape. Only called if the number of points in the shape changes.
     */
    updateShape() {
        const shape = new Shape();
        if (this.shapePoints.length > 1) {
            shape.moveToPoint(this.shapePoints[0]);
            for (let i = 1; i < this.shapePoints.length; i++) {
                shape.lineToPoint(this.shapePoints[i]);
            }
            shape.close();
        }
        this.shape = shape;
    }
    /**
     * Sets the tail position.
     */
    setTail(tailX, tailY) {
        this.setTailAndTip(tailX, tailY, this._tipX, this._tipY);
    }
    /**
     * Sets the tip position.
     */
    setTip(tipX, tipY) {
        this.setTailAndTip(this._tailX, this._tailY, tipX, tipY);
    }
    /**
     * Update the internal shapePoints array which is used to populate the points in the Shape instance.
     * Returns true if the number of points in the array has changed, which would require building a new shape instance.
     */
    updateShapePoints() {
        const numberOfPoints = this.shapePoints.length;
        this.shapePoints = ArrowShape.getArrowShapePoints(this._tailX, this._tailY, this._tipX, this._tipY, this.shapePoints, this.options);
        return (this.shapePoints.length !== numberOfPoints);
    }
    /**
     * Sets the tail width.
     */
    setTailWidth(tailWidth) {
        this.options.tailWidth = tailWidth;
        this.updateShapePoints();
        this.updateShape();
    }
    /**
     * Sets whether the arrow has one or two heads.
     */
    setDoubleHead(doubleHead) {
        this.options.doubleHead = doubleHead;
        this.updateShapePoints();
        this.updateShape();
    }
}
sceneryPhet.register('ArrowNode', ArrowNode);
//# sourceMappingURL=ArrowNode.js.map