import '../../../assert/js/assert.js';
import '../../../globals.js';
// Copyright 2019-2024, University of Colorado Boulder
/**
 * Represents an image with a specific center "offset". Considered immutable (with an immutable image, the Canvas if
 * provided should not change).
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */
import { isTReadOnlyProperty } from '../../../axon/js/TReadOnlyProperty.js';
import Matrix3 from '../../../dot/js/Matrix3.js';
import Vector2 from '../../../dot/js/Vector2.js';
import { Shape } from '../../../kite/js/imports.js';
import mutate from '../../../phet-core/js/mutate.js';
import optionize from '../../../phet-core/js/optionize.js';
import { Imageable, scenery } from '../imports.js';
let globalIdCounter = 1;
const scratchVector = new Vector2(0, 0);
export default class SpriteImage extends Imageable(Object) {
    /**
     * @param image
     * @param offset - A 2d offset from the upper-left of the image which is considered the "center".
     * @param [providedOptions]
     */
    constructor(image, offset, providedOptions) {
        assert && assert(image instanceof HTMLImageElement || image instanceof HTMLCanvasElement);
        const initImageableOptions = {
            hitTestPixels: false,
            pickable: true
        };
        if (isTReadOnlyProperty(image)) {
            initImageableOptions.imageProperty = image;
        }
        else {
            initImageableOptions.image = image;
        }
        const options = optionize()(initImageableOptions, providedOptions);
        super();
        this.id = globalIdCounter++;
        this.offset = offset;
        this.pickable = options.pickable;
        this.shape = null;
        this.imageData = null;
        // Initialize Imageable items (including the image itself)
        if (isTReadOnlyProperty(image)) {
            this.imageProperty = image;
        }
        else {
            this.image = image;
        }
        mutate(this, Object.keys(Imageable.DEFAULT_OPTIONS), options);
    }
    get width() {
        return this.imageWidth;
    }
    get height() {
        return this.imageHeight;
    }
    /**
     * Returns a Shape that represents the hit-testable area of this SpriteImage.
     */
    getShape() {
        if (!this.pickable) {
            return new Shape();
        }
        if (!this.shape) {
            if (this.hitTestPixels) {
                this.ensureImageData();
                if (this.imageData) {
                    this.shape = Imageable.hitTestDataToShape(this.imageData, this.width, this.height);
                }
                else {
                    // Empty, if we haven't been able to load image data (even if we have a width/height)
                    return new Shape();
                }
            }
            else if (this.width && this.height) {
                this.shape = Shape.rect(0, 0, this.width, this.height);
            }
            else {
                // If we have no width/height
                return new Shape();
            }
            // Apply our offset
            this.shape = this.shape.transformed(Matrix3.translation(-this.offset.x, -this.offset.y));
        }
        return this.shape;
    }
    /**
     * Ensures we have a computed imageData (computes it lazily if necessary).
     */
    ensureImageData() {
        if (!this.imageData && this.width && this.height) {
            this.imageData = Imageable.getHitTestData(this.image, this.width, this.height);
        }
    }
    /**
     * Returns whether a given point is considered "inside" the SpriteImage.
     */
    containsPoint(point) {
        if (!this.pickable) {
            return false;
        }
        const width = this.width;
        const height = this.height;
        // If our image isn't really loaded yet, bail out
        if (!width && !height) {
            return false;
        }
        const position = scratchVector.set(point).add(this.offset);
        // Initial position check (are we within the rectangle)
        if (position.x < 0 || position.y < 0 || position.x > width || position.y > height) {
            return false;
        }
        if (!this.hitTestPixels) {
            return true;
        }
        else {
            // Lazy-load image data
            this.ensureImageData();
            // And test if it's available
            if (this.imageData) {
                return Imageable.testHitTestData(this.imageData, width, height, position);
            }
            else {
                return false;
            }
        }
    }
}
scenery.register('SpriteImage', SpriteImage);
//# sourceMappingURL=SpriteImage.js.map