import { KeyValuePair } from "../../../core/collection/KeyValuePair.js";
import { noop } from "../../../core/function/noop.js";
import { ImmutableObjectPool } from "../../../core/model/object/ImmutableObjectPool.js";
import { ObjectPoolFactory } from "../../../core/model/object/ObjectPoolFactory.js";
import { HTMLElementCacheKey } from "../../common/HTMLElementCacheKey.js";
import View from "../../View.js";

/**
 *
 * @type {ObjectPoolFactory<HTMLElementCacheKey>}
 */
const pool = new ObjectPoolFactory(
    () => new HTMLElementCacheKey(),
    noop,
    key => {
        key.reset();
    }
);

/**
 *
 * @type {ImmutableObjectPool<HTMLElementCacheKey, HTMLImageElement>}
 */
const view_pool = new ImmutableObjectPool({
    capacity: 500,
    perKeyCapacity: 100
});


/**
 *
 * @param {HTMLElementCacheKey} key
 * @return {HTMLImageElement}
 */
function obtainImageElement(key) {
    let element = view_pool.get(key);

    if (element === undefined) {
        element = key.createElement();
    }

    return element;
}

class ImageView extends View {
    /**
     *
     * @param {String|ObservedString} url
     * @param {String[]} classList
     * @param {*} [attributes]
     */
    constructor(url, { classList = [], attributes = {} } = {}) {
        super();


        /**
         * @type {string}
         */
        let src;

        if (url === null || url === undefined) {
            src = '';
        } else if (typeof url === "string") {
            src = url;
        } else if (typeof url === "object" && typeof url.getValue === "function") {
            src = url.getValue();

            if (url.onChanged !== undefined) {
                this.bindSignal(url.onChanged, this.__setSource, this);
            }
        }

        const cacheKey = pool.create();
        cacheKey.tag = 'img';

        cacheKey.attributes = [
            new KeyValuePair('src', src),
            new KeyValuePair('class', classList.join(' '))
        ];

        for (const attributesKey in attributes) {
            const attributeValue = String(attributes[attributesKey]);

            const attribute = new KeyValuePair(attributesKey, attributeValue);

            cacheKey.attributes.push(attribute);
        }

        cacheKey.update();


        this.el = obtainImageElement(cacheKey);

        pool.release(cacheKey);

        const classListSize = classList.length;

        for (let i = 0; i < classListSize; i++) {
            const c = classList[i];

            this.addClass(c);
        }

        this.size.onChanged.add(this.__setSize, this);

    }

    destroy() {
        super.destroy();

        const key = pool.create();
        key.initializeFromElement(this.el);

        const added = view_pool.add(key, this.el);

        if (!added) {
            pool.release(key);
        }

    }

    /**
     *
     * @param {number} x
     * @param {number} y
     * @private
     */
    __setSize(x, y) {
        this.el.setAttribute('width', x);
        this.el.setAttribute('height', y);
    }

    /**
     *
     * @param {string} url
     * @private
     */
    __setSource(url) {
        this.el.setAttribute('src', url);
    }
}

export default ImageView;
