import { Bound } from '../utils/bound.js';
import { getBoundsWithRotation, isPointIn } from '../utils/math-utils.js';
import {} from '../utils/point-location.js';
import { deserializeXYWH, } from '../utils/xywh.js';
export class SurfaceElement {
    containedByBounds(_) {
        throw new Error('Method not implemented.');
    }
    getNearestPoint(_) {
        throw new Error('Method not implemented.');
    }
    intersectWithLine(_, _1) {
        throw new Error('Method not implemented.');
    }
    getRelativePointLocation(_) {
        throw new Error('Method not implemented.');
    }
    boxSelect(bound) {
        return (this.containedByBounds(bound) ||
            bound.points.some((point, i, points) => this.intersectWithLine(point, points[(i + 1) % points.length])));
    }
    constructor(yMap, options, data = {}) {
        this.renderer = null;
        this._connectable = true;
        this._stashedValues = new Map();
        this._localProps = ['display', 'opacity'];
        this.computedValue = v => v;
        this._onMap = (events) => {
            this.renderer?.removeElement(this);
            this.renderer?.addElement(this);
            const e = events[0];
            const props = {};
            e.changes.keys.forEach((_, key) => {
                props[key] = this.yMap.get(key);
            });
            this.options.onElementUpdated({
                id: this.id,
                props: props,
            });
        };
        if (!yMap.doc) {
            throw new Error('yMap must be bound to a Y.Doc');
        }
        this.yMap = yMap;
        for (const key in data) {
            this.yMap.set(key, data[key]);
        }
        this.options = options;
    }
    init() { }
    get display() {
        return this._stashedValues.get('display') ?? true;
    }
    set display(val) {
        this._stashedValues.set('display', val);
    }
    get opacity() {
        return this._stashedValues.get('opacity') ?? 1;
    }
    set opacity(val) {
        this._stashedValues.set('opacity', val);
    }
    get id() {
        const id = this.yMap.get('id');
        return id;
    }
    get index() {
        const index = this.yMap.get('index');
        return index;
    }
    get type() {
        const type = this.yMap.get('type');
        return type;
    }
    get xywh() {
        return (this._stashedValues.get('xywh') ??
            this.yMap.get('xywh'));
    }
    get seed() {
        const seed = this.yMap.get('seed');
        return seed;
    }
    get rotate() {
        return (this._stashedValues.get('rotate') ??
            this.yMap.get('rotate') ??
            0);
    }
    get batch() {
        return this.yMap.get('batch') ?? null;
    }
    get elementBound() {
        if (this.rotate) {
            return Bound.from(getBoundsWithRotation(this));
        }
        return Bound.deserialize(this.xywh);
    }
    get x() {
        const [x] = this.deserializeXYWH();
        return x;
    }
    get y() {
        const [, y] = this.deserializeXYWH();
        return y;
    }
    get w() {
        const [, , w] = this.deserializeXYWH();
        return w;
    }
    get h() {
        const [, , , h] = this.deserializeXYWH();
        return h;
    }
    get connectable() {
        return this._connectable;
    }
    applyUpdate(updates) {
        for (const key in updates) {
            if (this._stashedValues.has(key)) {
                this._stashedValues.set(key, updates[key]);
                this.options.onElementUpdated({
                    id: this.id,
                    props: { [key]: updates[key] },
                });
            }
            else {
                this.yMap.set(key, updates[key]);
            }
        }
        this.renderer?.refresh();
    }
    deserializeXYWH() {
        return deserializeXYWH(this.xywh);
    }
    serialize() {
        return this.yMap.toJSON();
    }
    hitTest(x, y, _options) {
        return isPointIn(this, x, y);
    }
    mount(renderer) {
        this.renderer = renderer;
        this.renderer.addElement(this);
        this.yMap.observeDeep(this._onMap);
    }
    unmount() {
        this.yMap.unobserveDeep(this._onMap);
        this.renderer?.removeElement(this);
        this.renderer = null;
    }
    render(_ctx, _matrix, _rc) {
        return;
    }
    stash(key) {
        if (this._stashedValues.has(key))
            return;
        this._stashedValues.set(key, this.yMap.get(key));
    }
    pop(key) {
        if (this._localProps.includes(key))
            return;
        if (this._stashedValues.has(key)) {
            const value = this._stashedValues.get(key);
            this._stashedValues.delete(key);
            this.yMap.set(key, value);
        }
    }
}
//# sourceMappingURL=surface-element.js.map