import { closest } from "../utils/util.js";

/**
 * Manages focus when a presentation is embedded. This
 * helps us only capture keyboard from the presentation
 * a user is currently interacting with in a page where
 * multiple presentations are embedded.
 */

const STATE_FOCUS = "focus";
const STATE_BLUR = "blur";

export default class Focus {
    constructor(Reveal) {
        this.Reveal = Reveal;

        this.onRevealPointerDown = this.onRevealPointerDown.bind(this);
        this.onDocumentPointerDown = this.onDocumentPointerDown.bind(this);
    }

    /**
     * Called when the reveal.js config is updated.
     */
    configure(config, oldConfig) {
        if (config.embedded) {
            this.blur();
        } else {
            this.focus();
            this.unbind();
        }
    }

    bind() {
        if (this.Reveal.getConfig().embedded) {
            this.Reveal.getRevealElement().addEventListener(
                "pointerdown",
                this.onRevealPointerDown,
                false,
            );
        }
    }

    unbind() {
        this.Reveal.getRevealElement().removeEventListener(
            "pointerdown",
            this.onRevealPointerDown,
            false,
        );
        document.removeEventListener(
            "pointerdown",
            this.onDocumentPointerDown,
            false,
        );
    }

    focus() {
        if (this.state !== STATE_FOCUS) {
            this.Reveal.getRevealElement().classList.add("focused");
            document.addEventListener(
                "pointerdown",
                this.onDocumentPointerDown,
                false,
            );
        }

        this.state = STATE_FOCUS;
    }

    blur() {
        if (this.state !== STATE_BLUR) {
            this.Reveal.getRevealElement().classList.remove("focused");
            document.removeEventListener(
                "pointerdown",
                this.onDocumentPointerDown,
                false,
            );
        }

        this.state = STATE_BLUR;
    }

    isFocused() {
        return this.state === STATE_FOCUS;
    }

    destroy() {
        this.Reveal.getRevealElement().classList.remove("focused");
    }

    onRevealPointerDown(event) {
        this.focus();
    }

    onDocumentPointerDown(event) {
        let revealElement = closest(event.target, ".reveal");
        if (
            !revealElement ||
            revealElement !== this.Reveal.getRevealElement()
        ) {
            this.blur();
        }
    }
}
