'use strict';

const listener = require('./listener-154f256a.js');
const browser = require('./browser-9ac97263.js');
const helpers = require('./helpers-46584747.js');

class BalElementStateListener extends listener.ListenerAbstract {
    constructor() {
        super(...arguments);
        this.state = BalElementStateListener.DefaultState;
        this.onMouseEnter = () => {
            this.updateState({ hovered: true });
        };
        this.onMouseLeave = () => {
            this.updateState({ hovered: false });
        };
        this.onPointerDown = () => {
            this.updateState({ pressed: true });
        };
        this.onPointerUp = () => {
            this.updateState({ pressed: false });
        };
    }
    connect(el) {
        super.connect(el);
        helpers.addEventListener(this.el, 'mouseenter', this.onMouseEnter, BalElementStateListener.EventListenerOptions);
        helpers.addEventListener(this.el, 'mouseleave', this.onMouseLeave, BalElementStateListener.EventListenerOptions);
        helpers.addEventListener(this.el, 'pointerdown', this.onPointerDown, BalElementStateListener.EventListenerOptions);
        if (browser.balBrowser.hasDocument) {
            helpers.addEventListener(document, 'pointerup', this.onPointerUp, BalElementStateListener.EventListenerOptions);
        }
    }
    disconnect() {
        super.disconnect();
        if (this.el) {
            helpers.removeEventListener(this.el, 'mouseenter', this.onMouseEnter);
            helpers.removeEventListener(this.el, 'mouseleave', this.onMouseLeave);
            helpers.removeEventListener(this.el, 'pointerdown', this.onPointerDown);
            if (browser.balBrowser.hasDocument) {
                helpers.removeEventListener(document, 'pointerup', this.onPointerUp);
            }
        }
    }
    updateState(newState) {
        this.state = Object.assign(Object.assign({}, this.state), newState);
        this.notify(this.state);
    }
}
BalElementStateListener.EventListenerOptions = {
    passive: true,
};
BalElementStateListener.DefaultState = {
    hovered: false,
    pressed: false,
};

class BalElementStateSubject extends listener.SingleSubject {
    constructor() {
        super((observer, data) => {
            if (data) {
                observer.elementStateListener(data);
            }
        });
        this.listener = new BalElementStateListener();
    }
    attach(observer) {
        super.attach(observer);
        this.listener.connect(observer.el);
        this.listener.add(info => super.notify(info));
    }
    detach() {
        super.detach();
        this.listener.disconnect();
    }
}

function ListenToElementStates() {
    return function (target, _propertyKey, _descriptor) {
        const { connectedCallback, disconnectedCallback } = target;
        target.connectedCallback = function () {
            if (!this._balElementStateSubject) {
                this._balElementStateSubject = new BalElementStateSubject();
                this._balElementStateSubject.attach(this);
            }
            return connectedCallback && connectedCallback.call(this);
        };
        target.disconnectedCallback = function () {
            if (this._balElementStateSubject) {
                this._balElementStateSubject.detach();
                this._balElementStateSubject = undefined;
            }
            return disconnectedCallback && disconnectedCallback.call(this);
        };
    };
}

exports.BalElementStateListener = BalElementStateListener;
exports.ListenToElementStates = ListenToElementStates;
