/**  
 * @since Last modified: 2024-09-10 11:20:41
 * @class Masonry
 * @description Folding too long text and omittind.
 * @param {*} elem - target element
 * @param {Object} [options] - Parameters 
 * @see {@link https://codepen.io/axui/pen/ZEwvpNL|demo @ codepen}
 * @example
 * ax.Masonry('#id');
 */
import getEl from '../utils/getEl';
import isEmpty from '../utils/isEmpty';
import instance from '../utils/instance';
import breakpoints from '../utils/breakpoints';
import createEl from '../utils/createEl';
import deepClone from '../utils/deepClone';
import purifyHtml from '../utils/purifyHtml';
import PubBase from './PubBase';
import PubListen from './PubListen';
import PubUpdate from './PubUpdate';
import PubCommon from './PubCommon';
import pipe from '../utils/pipe';
import ax from '../ax';
import { T_masonry } from '../../../types/masonry';
import { T_el, T_fn, T_obj } from '../../../types/ax';
import optMasonry from '../options/optMasonry';
import elProps from '../utils/elProps';
import prefix from '../global/prefix';
import alias from '../global/alias';
import classes from '../utils/classes';
import toPixel from '../utils/toPixel';
import Observe from './Observe';
import getDataType from '../utils/getDataType';
class Masonry extends pipe(PubListen, PubUpdate, PubCommon)(PubBase) {
    targetEl: any;
    options: T_masonry = {};
    destroyed: any;
    plans: any;
    storKeys: any;
    storObs: any;
    storTmp: any;
    rawOpts: any;
    static hostType = 'node';
    constructor(elem: any, options?: T_masonry, initial: boolean = true) {
        super();
        this.ready({
            options,
            maps: optMasonry,
            host: elem,
            component: false,
        });
        this.itemsTmp = [];
        this.itemsObs = new Observe(this.itemsTmp, {
            onSet: (data) => {
                if (getDataType(data.value).includes('HTML')) {
                    this.targetEl.appendChild(data.value);
                    this.itemSizeObs.observe(data.value);
                }
            },
            onDelete: (data) => { },
            onComplete: () => {
            }
        });
        this.items = this.itemsObs.proxy;
        this.itemSizeObs = new ResizeObserver((data: T_obj[]) => {
            for (let k of data) {
                this.updateItemStyle(k.target);
            }
        });
        super.listen({ name: 'ready' });
        initial && this.init() ;
    }
    async init(cb?: T_fn): Promise<any> {
        super.listen({ name: 'launch' });
        this.options.b4Init && await this.options.b4Init.call(this);
        this.gap = Math.ceil(toPixel(this.options.gap as string | number));
        this.setAttrs();
        if (Array.isArray(this.options.content) && this.options.content.length > 0) {
            this.items.push(...this.options.content)
        } else if (this.targetEl.innerHTML.trim()) {
            this.items.push(...this.targetEl.children);
        } else {
            return this;
        }
        super.listen({ name: 'init', cb });
        return this;
    }
    setAttrs() {
        this.targetEl.classList.add(`${prefix}masonry`);
        classes.add(this.targetEl, this.options.classes);
        this.targetEl.style.columnGap = `${this.gap}px`;
        this.options.cols && (this.targetEl.style.gridTemplateColumns = `repeat(${this.options.cols}, 1fr)`);
    }
    updateItemStyle(el: T_el) {
        let height = el.offsetHeight;
        el.style.gridRow = `span ${Math.ceil(height + this.gap)}`;
    }
    setItem(el: T_el) {
        this.itemSizeObs.observe(el);
    }
    async add(data: T_el[], cb?: T_fn) {
        if (this.destroyed) return this;
        let tmp = Array.isArray(data) ? data : [data];
        this.options.b4Add && await this.options.b4Add.call(this, tmp);
        this.items.push(...tmp);
        super.listen({ name: 'add', cb, params: [tmp] });
        return this;
    }
    async remove(data: T_el | T_el[], cb?: T_fn) {
        if (this.destroyed) return this;
        let tmp = Array.isArray(data) ? data : [data];
        this.options.b4Remove && await this.options.b4Remove.call(this, tmp);
        for (let k = 0; k < tmp.length; k++) {
            let item = tmp[k],
                idx = this.items.findIndex((k: any) => k === item);
            if (idx > -1) {
                this.items.splice(idx, 1);
                this.items[idx].remove();
            }
        }
        super.listen({ name: 'remove', cb, params: [tmp] });
        return this;
    }
    async clear(cb?: T_fn) {
        if (this.destroyed) return this;
        this.options.b4Clear && await this.options.b4Clear.call(this);
        this.items.splice(0);
        this.targetEl.innerHTML = '';
        super.listen({ name: 'clear', cb });
        return this;
    }
    /**
     * @description Destroy instance.Prohibit use.
     * @param {fn_cb_destroy} cb - Call back after destroy.
     * @returns {*} Return the instance itself
     */
    destroy(cb?: any): any {
        if (this.destroyed) return this;
        this.button.onclick = null;
        super.clearCache();
        this.destroyed = true;
        super.listen({ name: 'destroy', cb });
        return this;
    }
}
export default Masonry;
