import { getImageSrc } from './utils';
import imageLayout from './imageLayout';
const TIMEOUT = 250;
const imageEffectMap = {
    parallax: 'ImageParallax',
    fixed: 'ImageReveal',
};
function wowImageFactory(services, environmentConsts, contextWindow) {
    return class WowImage extends contextWindow.HTMLElement {
        constructor() {
            // eslint-disable-line no-useless-constructor
            super();
            this.childListObserver = null;
            this.timeoutId = null;
        }
        attributeChangedCallback(_, oldValue) {
            if (oldValue) {
                this.reLayout();
            }
        }
        connectedCallback() {
            if (environmentConsts.disableImagesLazyLoading) {
                this.reLayout();
            }
            else {
                this.observeIntersect();
            }
        }
        disconnectedCallback() {
            this.unobserveResize();
            this.unobserveIntersect();
            this.unobserveChildren();
        }
        static get observedAttributes() {
            return ['data-image-info'];
        }
        reLayout() {
            const domNodes = {};
            const measures = {};
            const imageId = this.getAttribute('id');
            const imageInfo = JSON.parse(this.dataset.imageInfo || '');
            const isResponsive = this.dataset.isResponsive === 'true';
            const { bgEffectName } = this.dataset;
            const { scrollEffect } = imageInfo.imageData;
            const { sourceSets } = imageInfo;
            const bgEffect = bgEffectName || (scrollEffect && imageEffectMap[scrollEffect]);
            if (sourceSets && sourceSets.length) {
                sourceSets.forEach((sourceSet) => {
                    if (sourceSet.scrollEffect) {
                        sourceSet.scrollEffect =
                            imageEffectMap[sourceSet.scrollEffect];
                    }
                });
            }
            domNodes[imageId] = this;
            if (imageInfo.containerId) {
                domNodes[imageInfo.containerId] = contextWindow.document.getElementById(`${imageInfo.containerId}`);
            }
            const containerElm = imageInfo.containerId
                ? domNodes[imageInfo.containerId]
                : undefined;
            domNodes.image = this.querySelector('img');
            domNodes.picture = this.querySelector('picture');
            if (!domNodes.image) {
                // missing children, can't layout, wait for children to be created first
                const target = this;
                this.observeChildren(target);
                return;
            }
            // clean up
            this.unobserveChildren();
            // from now on just observe changes to children of top level
            this.observeChildren(this);
            services.mutationService.measure(() => {
                imageLayout.measure(imageId, measures, domNodes, {
                    containerElm,
                    bgEffect,
                    sourceSets,
                }, services);
            });
            const patchImage = (shouldLoadImage, loadImageImmediately) => {
                services.mutationService.mutate(() => {
                    imageLayout.patch(imageId, measures, domNodes, imageInfo, services, environmentConsts, shouldLoadImage, isResponsive, bgEffect, loadImageImmediately);
                });
            };
            const imageElement = domNodes.image;
            const ssrSrcNeedProcessing = this.dataset.hasSsrSrc && !imageElement.dataset.ssrSrcDone;
            // if image has no src or current src if from ssr render stage  -
            // load the image immediately, otherwise - debounce the reload
            const loadImageImmediately = !getImageSrc(imageElement) || ssrSrcNeedProcessing;
            if (loadImageImmediately) {
                patchImage(true, true);
            }
            else {
                this.debounceImageLoad(patchImage);
            }
        }
        /**
         * Debounce consecutive image loads
         *
         * @param {function} patchImage closure for patching the image
         */
        debounceImageLoad(patchImage) {
            clearTimeout(this.timeoutId);
            this.timeoutId = contextWindow.setTimeout(() => {
                patchImage(true);
            }, TIMEOUT);
            patchImage(false);
        }
        observeResize() {
            services.resizeService?.observe(this);
        }
        unobserveResize() {
            services.resizeService?.unobserve(this);
        }
        observeIntersect() {
            services.intersectionService?.observe(this);
        }
        unobserveIntersect() {
            services.intersectionService?.unobserve(this);
        }
        /**
         * Observe DOM mutations to wait for addition of missing children
         *
         * @param {HTMLElement} parent
         */
        observeChildren(parent) {
            if (!this.childListObserver) {
                this.childListObserver = new contextWindow.MutationObserver(() => {
                    this.reLayout();
                });
            }
            this.childListObserver.observe(parent, { childList: true });
        }
        /**
         * Remove DOM MutationObserver if one was created
         */
        unobserveChildren() {
            if (this.childListObserver) {
                this.childListObserver.disconnect();
                this.childListObserver = null;
            }
        }
    };
}
export default wowImageFactory;
//# sourceMappingURL=WowImage.js.map