"use strict";
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebGLImageLoader = void 0;
var imageHelper_1 = require("./helpers/imageHelper");
/*
 * ImageLoader is a part of sigma/rendering/webgl/programs/node.image
 * It loads images in one texture, which used for all nodes.
 */
var MAX_TEXTURE_SIZE = 128;
var WebGLImageLoader = /** @class */ (function () {
    function WebGLImageLoader() {
        var _this = this;
        this.rebindTextureFns = [];
        this.images = {};
        this.hasReceivedImages = false;
        this.pendingImagesFrameID = undefined;
        /**
         * Helper to load an image:
         */
        this.loadImage = function (id, imageSource) {
            if (_this.images[id])
                return;
            var image = new Image();
            image.addEventListener('load', function () {
                _this.images[id] = {
                    status: 'pending',
                    image: image
                };
                if (typeof _this.pendingImagesFrameID !== 'number') {
                    _this.pendingImagesFrameID = requestAnimationFrame(function () { return _this.finalizePendingImages(); });
                }
            });
            image.addEventListener('error', function () {
                _this.images[id] = { status: 'error' };
            });
            _this.images[id] = { status: 'loading' };
            // Load image:
            (0, imageHelper_1.clearCrossOriginForCORSIfNotSameOrigin)(image, imageSource);
            // add ?not-from-cache parameter for loading image not from cache
            // because cached image does not contain cors headers
            // https://www.hacksoft.io/blog/handle-images-cors-error-in-chrome
            image.src = imageSource.startsWith('data:image') ? imageSource : imageSource + '?not-from-cache';
        };
        /**
         * Helper that takes all pending images and adds them into the texture:
         */
        this.finalizePendingImages = function () {
            _this.pendingImagesFrameID = undefined;
            var pendingImages = [];
            // List all pending images:
            for (var id in _this.images) {
                var state = _this.images[id];
                if (state.status === 'pending') {
                    pendingImages.push({
                        id: id,
                        image: state.image,
                        size: Math.min(state.image.width, state.image.height) || 1
                    });
                }
            }
            // Add images to texture:
            var canvas = document.createElement('canvas');
            var ctx = canvas.getContext('2d');
            canvas.width = pendingImages.reduce(function (iter, _a) {
                var size = _a.size;
                return iter + size;
            }, _this.hasReceivedImages ? _this.textureImage.width : 0);
            canvas.height = Math.max.apply(Math, __spreadArray([_this.hasReceivedImages ? _this.textureImage.height : 0], pendingImages.map(function (_a) {
                var size = _a.size;
                return size;
            }), false));
            var xOffset = 0;
            if (_this.hasReceivedImages) {
                ctx.putImageData(_this.textureImage, 0, 0);
                xOffset = _this.textureImage.width;
            }
            pendingImages.forEach(function (_a) {
                var id = _a.id, image = _a.image, size = _a.size;
                var imageSizeInTexture = Math.min(MAX_TEXTURE_SIZE, size);
                // Crop image, to only keep the biggest square, centered:
                var dx = 0, dy = 0;
                if ((image.width || 0) > (image.height || 0)) {
                    dx = (image.width - image.height) / 2;
                }
                else {
                    dy = (image.height - image.width) / 2;
                }
                ctx.drawImage(image, dx, dy, size, size, xOffset, 0, imageSizeInTexture, imageSizeInTexture);
                // Update image state:
                _this.images[id] = {
                    status: 'ready',
                    x: xOffset,
                    y: 0,
                    width: imageSizeInTexture,
                    height: imageSizeInTexture
                };
                xOffset += imageSizeInTexture;
            });
            _this.textureImage = ctx.getImageData(0, 0, canvas.width, canvas.height);
            _this.hasReceivedImages = true;
            _this.rebindTextureFns.forEach(function (fn) { return fn(); });
        };
    }
    return WebGLImageLoader;
}());
exports.WebGLImageLoader = WebGLImageLoader;
